blob: c8ffb9327d023fe3d6cf3ce16bff4fd1f09dd1a5 [file] [log] [blame]
Greg Clayton061b79d2011-05-09 20:18:18 +00001//===-- ARMUtils.h ----------------------------------------------*- C++ -*-===//
Johnny Chen4baf2e32011-01-24 18:24:53 +00002//
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
Johnny Chen41a0a152011-02-16 01:27:54 +000013#include "ARMDefines.h"
Johnny Chen108d5aa2011-01-26 01:00:55 +000014#include "InstructionUtils.h"
Johnny Chen0d771a22011-02-15 17:52:22 +000015#include "llvm/Support/MathExtras.h" // for SignExtend64 template function
Johnny Chen108d5aa2011-01-26 01:00:55 +000016
Johnny Chenc3b5bc32011-01-24 19:50:30 +000017// Common utilities for the ARM/Thumb Instruction Set Architecture.
Johnny Chen4baf2e32011-01-24 18:24:53 +000018
19namespace lldb_private {
20
Johnny Chen7c677ac2011-02-17 17:31:08 +000021static inline uint32_t Align(uint32_t val, uint32_t alignment)
22{
23 return alignment * (val / alignment);
24}
25
Johnny Chen0d771a22011-02-15 17:52:22 +000026static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
27{
28 switch (type) {
29 default:
Greg Claytone1f47bb2011-06-02 22:23:35 +000030 //assert(0 && "Invalid shift type");
31 return UINT32_MAX;
Johnny Chen0d771a22011-02-15 17:52:22 +000032 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
Johnny Chen3dd06052011-02-22 21:17:52 +000055// A8.6.35 CMP (register) -- Encoding T3
56// Convenience function.
57static 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.
64static 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
Johnny Chen82f16aa2011-02-15 20:10:55 +000069static 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
Johnny Chen0d771a22011-02-15 17:52:22 +000075static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
76{
77 switch (type) {
78 default:
Greg Claytone1f47bb2011-06-02 22:23:35 +000079 //assert(0 && "Invalid shift type");
80 return SRType_Invalid;
Johnny Chen0d771a22011-02-15 17:52:22 +000081 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
92static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
93{
Greg Claytone1f47bb2011-06-02 22:23:35 +000094 //assert(amount > 0);
Johnny Chen0fa98ca2011-02-15 22:21:33 +000095 carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
Johnny Chen0d771a22011-02-15 17:52:22 +000096 return value << amount;
97}
98
99static inline uint32_t LSL(const uint32_t value, const uint32_t amount)
100{
Greg Claytone1f47bb2011-06-02 22:23:35 +0000101 //assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000102 if (amount == 0)
103 return value;
104 uint32_t dont_care;
105 return LSL_C(value, amount, dont_care);
106}
107
108static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
109{
Greg Claytone1f47bb2011-06-02 22:23:35 +0000110 //assert(amount > 0);
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000111 carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
Johnny Chen0d771a22011-02-15 17:52:22 +0000112 return value >> amount;
113}
114
115static inline uint32_t LSR(const uint32_t value, const uint32_t amount)
116{
Greg Claytone1f47bb2011-06-02 22:23:35 +0000117 //assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000118 if (amount == 0)
119 return value;
120 uint32_t dont_care;
121 return LSR_C(value, amount, dont_care);
122}
123
124static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
125{
Greg Claytone1f47bb2011-06-02 22:23:35 +0000126 //assert(amount > 0 && amount <= 32);
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000127 bool negative = BitIsSet(value, 31);
128 if (amount <= 32)
129 {
130 carry_out = Bit32(value, amount - 1);
131 int64_t extended = llvm::SignExtend64<32>(value);
132 return UnsignedBits(extended, amount + 31, amount);
133 }
134 else
135 {
136 carry_out = (negative ? 1 : 0);
137 return (negative ? 0xffffffff : 0);
138 }
Johnny Chen0d771a22011-02-15 17:52:22 +0000139}
140
141static inline uint32_t ASR(const uint32_t value, const uint32_t amount)
142{
Greg Claytone1f47bb2011-06-02 22:23:35 +0000143 //assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000144 if (amount == 0)
145 return value;
146 uint32_t dont_care;
147 return ASR_C(value, amount, dont_care);
148}
149
150static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out)
151{
Greg Claytone1f47bb2011-06-02 22:23:35 +0000152 //assert(amount > 0);
Johnny Chen0fa98ca2011-02-15 22:21:33 +0000153 uint32_t amt = amount % 32;
154 uint32_t result = Rotr32(value, amt);
Johnny Chen0d771a22011-02-15 17:52:22 +0000155 carry_out = Bit32(value, 31);
156 return result;
157}
158
159static inline uint32_t ROR(const uint32_t value, const uint32_t amount)
160{
Greg Claytone1f47bb2011-06-02 22:23:35 +0000161 //assert(amount >= 0);
Johnny Chen0d771a22011-02-15 17:52:22 +0000162 if (amount == 0)
163 return value;
164 uint32_t dont_care;
165 return ROR_C(value, amount, dont_care);
166}
167
168static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out)
169{
170 carry_out = Bit32(value, 0);
171 return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
172}
173
174static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in)
175{
176 uint32_t dont_care;
177 return RRX_C(value, carry_in, dont_care);
178}
179
180static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
181 const uint32_t carry_in, uint32_t &carry_out)
182{
Greg Claytone1f47bb2011-06-02 22:23:35 +0000183 //assert(type != SRType_RRX || amount == 1);
Johnny Chen0d771a22011-02-15 17:52:22 +0000184 if (amount == 0)
185 {
186 carry_out = carry_in;
187 return value;
188 }
189 uint32_t result;
190 switch (type) {
191 case SRType_LSL:
192 result = LSL_C(value, amount, carry_out);
193 break;
194 case SRType_LSR:
195 result = LSR_C(value, amount, carry_out);
196 break;
197 case SRType_ASR:
198 result = ASR_C(value, amount, carry_out);
199 break;
200 case SRType_ROR:
201 result = ROR_C(value, amount, carry_out);
202 break;
203 case SRType_RRX:
Johnny Cheneeab4852011-02-16 22:14:44 +0000204 result = RRX_C(value, carry_in, carry_out);
Johnny Chen0d771a22011-02-15 17:52:22 +0000205 break;
206 }
207 return result;
208}
209
210static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
211 const uint32_t carry_in)
212{
213 // Don't care about carry out in this case.
214 uint32_t dont_care;
215 return Shift_C(value, type, amount, carry_in, dont_care);
216}
217
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000218static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
219{
Johnny Chen108d5aa2011-01-26 01:00:55 +0000220 return Bits32(val, msbit, lsbit);
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000221}
222
223static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
224{
225 return bits(val, msbit, msbit);
226}
227
Johnny Chen60c0d622011-01-25 23:49:39 +0000228static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000229{
Johnny Chen60c0d622011-01-25 23:49:39 +0000230 uint32_t m = shift % N;
231 return (val >> m) | (val << (N - m));
232}
233
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000234// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
Johnny Chen3dd06052011-02-22 21:17:52 +0000235static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000236{
Johnny Chen3dd06052011-02-22 21:17:52 +0000237 uint32_t imm32; // the expanded result
238 uint32_t imm = bits(opcode, 7, 0); // immediate value
239 uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000240 if (amt == 0)
241 {
242 imm32 = imm;
243 carry_out = carry_in;
244 }
245 else
246 {
247 imm32 = ror(imm, 32, amt);
248 carry_out = Bit32(imm32, 31);
249 }
250 return imm32;
251}
252
Johnny Chen3dd06052011-02-22 21:17:52 +0000253static inline uint32_t ARMExpandImm(uint32_t opcode)
Johnny Chen60c0d622011-01-25 23:49:39 +0000254{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000255 // 'carry_in' argument to following function call does not affect the imm32 result.
256 uint32_t carry_in = 0;
257 uint32_t carry_out;
Johnny Chen3dd06052011-02-22 21:17:52 +0000258 return ARMExpandImm_C(opcode, carry_in, carry_out);
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000259}
260
261// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
Johnny Chen3dd06052011-02-22 21:17:52 +0000262static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000263{
Johnny Chen3e9a41c2011-02-14 19:09:36 +0000264 uint32_t imm32; // the expaned result
Johnny Chen3dd06052011-02-22 21:17:52 +0000265 const uint32_t i = bit(opcode, 26);
266 const uint32_t imm3 = bits(opcode, 14, 12);
267 const uint32_t abcdefgh = bits(opcode, 7, 0);
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000268 const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
269
270 if (bits(imm12, 11, 10) == 0)
271 {
Caroline Tice3d79d342011-03-24 21:11:26 +0000272 switch (bits(imm12, 9, 8)) {
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000273 case 0:
274 imm32 = abcdefgh;
275 break;
276
277 case 1:
278 imm32 = abcdefgh << 16 | abcdefgh;
279 break;
280
281 case 2:
282 imm32 = abcdefgh << 24 | abcdefgh << 8;
283 break;
284
285 case 3:
286 imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
287 break;
288 }
289 carry_out = carry_in;
290 }
291 else
292 {
293 const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
294 imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
295 carry_out = Bit32(imm32, 31);
296 }
297 return imm32;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000298}
299
Johnny Chen3dd06052011-02-22 21:17:52 +0000300static inline uint32_t ThumbExpandImm(uint32_t opcode)
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000301{
Johnny Chen07f2f5a2011-02-14 19:08:41 +0000302 // 'carry_in' argument to following function call does not affect the imm32 result.
303 uint32_t carry_in = 0;
304 uint32_t carry_out;
Johnny Chen3dd06052011-02-22 21:17:52 +0000305 return ThumbExpandImm_C(opcode, carry_in, carry_out);
Johnny Chen60c0d622011-01-25 23:49:39 +0000306}
307
308// imm32 = ZeroExtend(i:imm3:imm8, 32)
Johnny Chen3dd06052011-02-22 21:17:52 +0000309static inline uint32_t ThumbImm12(uint32_t opcode)
Johnny Chen60c0d622011-01-25 23:49:39 +0000310{
Johnny Chen3dd06052011-02-22 21:17:52 +0000311 const uint32_t i = bit(opcode, 26);
312 const uint32_t imm3 = bits(opcode, 14, 12);
313 const uint32_t imm8 = bits(opcode, 7, 0);
Johnny Chen60c0d622011-01-25 23:49:39 +0000314 const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
315 return imm12;
Johnny Chen4c0e0bc2011-01-25 22:45:28 +0000316}
317
Johnny Chene4455022011-01-26 00:08:59 +0000318// imm32 = ZeroExtend(imm7:'00', 32)
Johnny Chena695f952011-02-23 21:24:25 +0000319static inline uint32_t ThumbImm7Scaled(uint32_t opcode)
Johnny Chene4455022011-01-26 00:08:59 +0000320{
Johnny Chen3dd06052011-02-22 21:17:52 +0000321 const uint32_t imm7 = bits(opcode, 6, 0);
Johnny Chene4455022011-01-26 00:08:59 +0000322 return imm7 * 4;
323}
324
Johnny Chena695f952011-02-23 21:24:25 +0000325// imm32 = ZeroExtend(imm8:'00', 32)
326static inline uint32_t ThumbImm8Scaled(uint32_t opcode)
327{
328 const uint32_t imm8 = bits(opcode, 7, 0);
329 return imm8 * 4;
330}
331
Johnny Chen4baf2e32011-01-24 18:24:53 +0000332// This function performs the check for the register numbers 13 and 15 that are
333// not permitted for many Thumb register specifiers.
334static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
335
Johnny Chen4baf2e32011-01-24 18:24:53 +0000336} // namespace lldb_private
337
338#endif // lldb_ARMUtils_h_