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