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