1 //===-- ARMUtils.h ----------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef lldb_ARMUtils_h_
11 #define lldb_ARMUtils_h_
12 
13 #include "ARMDefines.h"
14 #include "InstructionUtils.h"
15 #include "llvm/Support/MathExtras.h" // for SignExtend64 template function
16 
17 // Common utilities for the ARM/Thumb Instruction Set Architecture.
18 
19 namespace lldb_private {
20 
21 static inline uint32_t Align(uint32_t val, uint32_t alignment)
22 {
23     return alignment * (val / alignment);
24 }
25 
26 static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
27 {
28     switch (type) {
29     default:
30         //assert(0 && "Invalid shift type");
31         return UINT32_MAX;
32     case 0:
33         shift_t = SRType_LSL;
34         return imm5;
35     case 1:
36         shift_t = SRType_LSR;
37         return (imm5 == 0 ? 32 : imm5);
38     case 2:
39         shift_t = SRType_ASR;
40         return (imm5 == 0 ? 32 : imm5);
41     case 3:
42         if (imm5 == 0)
43         {
44             shift_t = SRType_RRX;
45             return 1;
46         }
47         else
48         {
49             shift_t = SRType_ROR;
50             return imm5;
51         }
52     }
53 }
54 
55 // A8.6.35 CMP (register) -- Encoding T3
56 // Convenience function.
57 static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode, ARM_ShifterType &shift_t)
58 {
59     return DecodeImmShift(Bits32(opcode, 5, 4), Bits32(opcode, 14, 12)<<2 | Bits32(opcode, 7, 6), shift_t);
60 }
61 
62 // A8.6.35 CMP (register) -- Encoding A1
63 // Convenience function.
64 static inline uint32_t DecodeImmShiftARM(const uint32_t opcode, ARM_ShifterType &shift_t)
65 {
66     return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);
67 }
68 
69 static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t, const uint32_t imm5)
70 {
71     ARM_ShifterType dont_care;
72     return DecodeImmShift(shift_t, imm5, dont_care);
73 }
74 
75 static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
76 {
77     switch (type) {
78     default:
79         //assert(0 && "Invalid shift type");
80         return SRType_Invalid;
81     case 0:
82         return SRType_LSL;
83     case 1:
84         return SRType_LSR;
85     case 2:
86         return SRType_ASR;
87     case 3:
88         return SRType_ROR;
89     }
90 }
91 
92 static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
93 {
94     if (amount == 0) {
95         *success = false;
96         return 0;
97     }
98     *success = true;
99     carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
100     return value << amount;
101 }
102 
103 static inline uint32_t LSL(const uint32_t value, const uint32_t amount, bool *success)
104 {
105     *success = true;
106     if (amount == 0)
107         return value;
108     uint32_t dont_care;
109     uint32_t result = LSL_C(value, amount, dont_care, success);
110     if (*success)
111         return result;
112     else
113         return 0;
114 }
115 
116 static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
117 {
118     if (amount == 0) {
119         *success = false;
120         return 0;
121     }
122     *success = true;
123     carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
124     return value >> amount;
125 }
126 
127 static inline uint32_t LSR(const uint32_t value, const uint32_t amount, bool *success)
128 {
129     *success = true;
130     if (amount == 0)
131         return value;
132     uint32_t dont_care;
133     uint32_t result = LSR_C(value, amount, dont_care, success);
134     if (*success)
135         return result;
136     else
137         return 0;
138 }
139 
140 static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
141 {
142     if (amount == 0 || amount > 32) {
143         *success = false;
144         return 0;
145     }
146     *success = true;
147     bool negative = BitIsSet(value, 31);
148     if (amount <= 32)
149     {
150         carry_out = Bit32(value, amount - 1);
151         int64_t extended = llvm::SignExtend64<32>(value);
152         return UnsignedBits(extended, amount + 31, amount);
153     }
154     else
155     {
156         carry_out = (negative ? 1 : 0);
157         return (negative ? 0xffffffff : 0);
158     }
159 }
160 
161 static inline uint32_t ASR(const uint32_t value, const uint32_t amount, bool *success)
162 {
163     *success = true;
164     if (amount == 0)
165         return value;
166     uint32_t dont_care;
167     uint32_t result = ASR_C(value, amount, dont_care, success);
168     if (*success)
169         return result;
170     else
171         return 0;
172 }
173 
174 static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
175 {
176     if (amount == 0) {
177         *success = false;
178         return 0;
179     }
180     *success = true;
181     uint32_t amt = amount % 32;
182     uint32_t result = Rotr32(value, amt);
183     carry_out = Bit32(value, 31);
184     return result;
185 }
186 
187 static inline uint32_t ROR(const uint32_t value, const uint32_t amount, bool *success)
188 {
189     *success = true;
190     if (amount == 0)
191         return value;
192     uint32_t dont_care;
193     uint32_t result = ROR_C(value, amount, dont_care, success);
194     if (*success)
195         return result;
196     else
197         return 0;
198 }
199 
200 static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out, bool *success)
201 {
202     *success = true;
203     carry_out = Bit32(value, 0);
204     return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
205 }
206 
207 static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in, bool *success)
208 {
209     *success = true;
210     uint32_t dont_care;
211     uint32_t result = RRX_C(value, carry_in, dont_care, success);
212     if (*success)
213         return result;
214     else
215         return 0;
216 }
217 
218 static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
219                                const uint32_t carry_in, uint32_t &carry_out, bool *success)
220 {
221     if (type == SRType_RRX && amount != 1) {
222         *success = false;
223         return 0;
224     }
225     *success = true;
226 
227     if (amount == 0) {
228         carry_out = carry_in;
229         return value;
230     }
231     uint32_t result;
232     switch (type) {
233     case SRType_LSL:
234         result = LSL_C(value, amount, carry_out, success);
235         break;
236     case SRType_LSR:
237         result = LSR_C(value, amount, carry_out, success);
238         break;
239     case SRType_ASR:
240         result = ASR_C(value, amount, carry_out, success);
241         break;
242     case SRType_ROR:
243         result = ROR_C(value, amount, carry_out, success);
244         break;
245     case SRType_RRX:
246         result = RRX_C(value, carry_in, carry_out, success);
247         break;
248     default:
249         *success = false;
250         break;
251     }
252     if (*success)
253         return result;
254     else
255         return 0;
256 }
257 
258 static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
259                              const uint32_t carry_in, bool *success)
260 {
261     // Don't care about carry out in this case.
262     uint32_t dont_care;
263     uint32_t result = Shift_C(value, type, amount, carry_in, dont_care, success);
264     if (*success)
265         return result;
266     else
267         return 0;
268 }
269 
270 static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
271 {
272     return Bits32(val, msbit, lsbit);
273 }
274 
275 static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
276 {
277     return bits(val, msbit, msbit);
278 }
279 
280 static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
281 {
282     uint32_t m = shift % N;
283     return (val >> m) | (val << (N - m));
284 }
285 
286 // (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
287 static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
288 {
289     uint32_t imm32;                         // the expanded result
290     uint32_t imm = bits(opcode, 7, 0);      // immediate value
291     uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount
292     if (amt == 0)
293     {
294         imm32 = imm;
295         carry_out = carry_in;
296     }
297     else
298     {
299         imm32 = ror(imm, 32, amt);
300         carry_out = Bit32(imm32, 31);
301     }
302     return imm32;
303 }
304 
305 static inline uint32_t ARMExpandImm(uint32_t opcode)
306 {
307     // 'carry_in' argument to following function call does not affect the imm32 result.
308     uint32_t carry_in = 0;
309     uint32_t carry_out;
310     return ARMExpandImm_C(opcode, carry_in, carry_out);
311 }
312 
313 // (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
314 static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
315 {
316     uint32_t imm32; // the expaned result
317     const uint32_t i = bit(opcode, 26);
318     const uint32_t imm3 = bits(opcode, 14, 12);
319     const uint32_t abcdefgh = bits(opcode, 7, 0);
320     const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
321 
322     if (bits(imm12, 11, 10) == 0)
323     {
324         switch (bits(imm12, 9, 8)) {
325         case 0:
326             imm32 = abcdefgh;
327             break;
328 
329         case 1:
330             imm32 = abcdefgh << 16 | abcdefgh;
331             break;
332 
333         case 2:
334             imm32 = abcdefgh << 24 | abcdefgh << 8;
335             break;
336 
337         case 3:
338             imm32 = abcdefgh  << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
339             break;
340         }
341         carry_out = carry_in;
342     }
343     else
344     {
345         const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
346         imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
347         carry_out = Bit32(imm32, 31);
348     }
349     return imm32;
350 }
351 
352 static inline uint32_t ThumbExpandImm(uint32_t opcode)
353 {
354     // 'carry_in' argument to following function call does not affect the imm32 result.
355     uint32_t carry_in = 0;
356     uint32_t carry_out;
357     return ThumbExpandImm_C(opcode, carry_in, carry_out);
358 }
359 
360 // imm32 = ZeroExtend(i:imm3:imm8, 32)
361 static inline uint32_t ThumbImm12(uint32_t opcode)
362 {
363   const uint32_t i = bit(opcode, 26);
364   const uint32_t imm3 = bits(opcode, 14, 12);
365   const uint32_t imm8 = bits(opcode, 7, 0);
366   const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
367   return imm12;
368 }
369 
370 // imm32 = ZeroExtend(imm7:'00', 32)
371 static inline uint32_t ThumbImm7Scaled(uint32_t opcode)
372 {
373   const uint32_t imm7 = bits(opcode, 6, 0);
374   return imm7 * 4;
375 }
376 
377 // imm32 = ZeroExtend(imm8:'00', 32)
378 static inline uint32_t ThumbImm8Scaled(uint32_t opcode)
379 {
380   const uint32_t imm8 = bits(opcode, 7, 0);
381   return imm8 * 4;
382 }
383 
384 // This function performs the check for the register numbers 13 and 15 that are
385 // not permitted for many Thumb register specifiers.
386 static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
387 
388 }   // namespace lldb_private
389 
390 #endif  // lldb_ARMUtils_h_
391