1 //===-- ARMUtils.h ----------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H
10 #define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H
12 #include "ARMDefines.h"
13 #include "InstructionUtils.h"
14 #include "llvm/ADT/bit.h"
15 #include "llvm/Support/MathExtras.h"
17 // Common utilities for the ARM/Thumb Instruction Set Architecture.
19 namespace lldb_private
{
21 static inline uint32_t Align(uint32_t val
, uint32_t alignment
) {
22 return alignment
* (val
/ alignment
);
25 static inline uint32_t DecodeImmShift(const uint32_t type
, const uint32_t imm5
,
26 ARM_ShifterType
&shift_t
) {
29 assert(0 && "Invalid shift type");
36 return (imm5
== 0 ? 32 : imm5
);
39 return (imm5
== 0 ? 32 : imm5
);
49 shift_t
= SRType_Invalid
;
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(Bits32(opcode
, 5, 4),
58 Bits32(opcode
, 14, 12) << 2 | Bits32(opcode
, 7, 6),
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(Bits32(opcode
, 6, 5), Bits32(opcode
, 11, 7), shift_t
);
69 static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t
,
70 const uint32_t imm5
) {
71 ARM_ShifterType dont_care
;
72 return DecodeImmShift(shift_t
, imm5
, dont_care
);
75 static inline ARM_ShifterType
DecodeRegShift(const uint32_t type
) {
78 // assert(0 && "Invalid shift type");
79 return SRType_Invalid
;
91 static inline uint32_t LSL_C(const uint32_t value
, const uint32_t amount
,
92 uint32_t &carry_out
, bool *success
) {
98 carry_out
= amount
<= 32 ? Bit32(value
, 32 - amount
) : 0;
99 return value
<< amount
;
102 static inline uint32_t LSL(const uint32_t value
, const uint32_t amount
,
108 uint32_t result
= LSL_C(value
, amount
, dont_care
, success
);
115 static inline uint32_t LSR_C(const uint32_t value
, const uint32_t amount
,
116 uint32_t &carry_out
, bool *success
) {
122 carry_out
= amount
<= 32 ? Bit32(value
, amount
- 1) : 0;
123 return value
>> amount
;
126 static inline uint32_t LSR(const uint32_t value
, const uint32_t amount
,
132 uint32_t result
= LSR_C(value
, amount
, dont_care
, success
);
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) {
146 bool negative
= BitIsSet(value
, 31);
148 carry_out
= Bit32(value
, amount
- 1);
149 int64_t extended
= llvm::SignExtend64
<32>(value
);
150 return UnsignedBits(extended
, amount
+ 31, amount
);
152 carry_out
= (negative
? 1 : 0);
153 return (negative
? 0xffffffff : 0);
157 static inline uint32_t ASR(const uint32_t value
, const uint32_t amount
,
163 uint32_t result
= ASR_C(value
, amount
, dont_care
, success
);
170 static inline uint32_t ROR_C(const uint32_t value
, const uint32_t amount
,
171 uint32_t &carry_out
, bool *success
) {
177 uint32_t result
= llvm::rotr
<uint32_t>(value
, amount
);
178 carry_out
= Bit32(value
, 31);
182 static inline uint32_t ROR(const uint32_t value
, const uint32_t amount
,
188 uint32_t result
= ROR_C(value
, amount
, dont_care
, success
);
195 static inline uint32_t RRX_C(const uint32_t value
, const uint32_t carry_in
,
196 uint32_t &carry_out
, bool *success
) {
198 carry_out
= Bit32(value
, 0);
199 return Bit32(carry_in
, 0) << 31 | Bits32(value
, 31, 1);
202 static inline uint32_t RRX(const uint32_t value
, const uint32_t carry_in
,
206 uint32_t result
= RRX_C(value
, carry_in
, dont_care
, success
);
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) {
223 carry_out
= carry_in
;
229 result
= LSL_C(value
, amount
, carry_out
, success
);
232 result
= LSR_C(value
, amount
, carry_out
, success
);
235 result
= ASR_C(value
, amount
, carry_out
, success
);
238 result
= ROR_C(value
, amount
, carry_out
, success
);
241 result
= RRX_C(value
, carry_in
, carry_out
, success
);
253 static inline uint32_t Shift(const uint32_t value
, ARM_ShifterType type
,
254 const uint32_t amount
, const uint32_t carry_in
,
256 // Don't care about carry out in this case.
258 uint32_t result
= Shift_C(value
, type
, amount
, carry_in
, dont_care
, success
);
265 static inline uint32_t bits(const uint32_t val
, const uint32_t msbit
,
266 const uint32_t lsbit
) {
267 return Bits32(val
, msbit
, lsbit
);
270 static inline uint32_t bit(const uint32_t val
, const uint32_t msbit
) {
271 return bits(val
, msbit
, msbit
);
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
));
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(opcode
, 7, 0); // immediate value
284 uint32_t amt
= 2 * bits(opcode
, 11, 8); // rotate amount
287 carry_out
= carry_in
;
289 imm32
= ror(imm
, 32, amt
);
290 carry_out
= Bit32(imm32
, 31);
295 static inline uint32_t ARMExpandImm(uint32_t opcode
) {
296 // 'carry_in' argument to following function call does not affect the imm32
298 uint32_t carry_in
= 0;
300 return ARMExpandImm_C(opcode
, carry_in
, carry_out
);
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(opcode
, 26);
308 const uint32_t imm3
= bits(opcode
, 14, 12);
309 const uint32_t abcdefgh
= bits(opcode
, 7, 0);
310 const uint32_t imm12
= i
<< 11 | imm3
<< 8 | abcdefgh
;
312 if (bits(imm12
, 11, 10) == 0) {
313 switch (bits(imm12
, 9, 8)) {
314 default: // Keep static analyzer happy with a default case
322 imm32
= abcdefgh
<< 16 | abcdefgh
;
326 imm32
= abcdefgh
<< 24 | abcdefgh
<< 8;
330 imm32
= abcdefgh
<< 24 | abcdefgh
<< 16 | abcdefgh
<< 8 | abcdefgh
;
333 carry_out
= carry_in
;
335 const uint32_t unrotated_value
= 0x80 | bits(imm12
, 6, 0);
336 imm32
= ror(unrotated_value
, 32, bits(imm12
, 11, 7));
337 carry_out
= Bit32(imm32
, 31);
342 static inline uint32_t ThumbExpandImm(uint32_t opcode
) {
343 // 'carry_in' argument to following function call does not affect the imm32
345 uint32_t carry_in
= 0;
347 return ThumbExpandImm_C(opcode
, carry_in
, carry_out
);
350 // imm32 = ZeroExtend(i:imm3:imm8, 32)
351 static inline uint32_t ThumbImm12(uint32_t opcode
) {
352 const uint32_t i
= bit(opcode
, 26);
353 const uint32_t imm3
= bits(opcode
, 14, 12);
354 const uint32_t imm8
= bits(opcode
, 7, 0);
355 const uint32_t imm12
= i
<< 11 | imm3
<< 8 | imm8
;
359 // imm32 = ZeroExtend(imm7:'00', 32)
360 static inline uint32_t ThumbImm7Scaled(uint32_t opcode
) {
361 const uint32_t imm7
= bits(opcode
, 6, 0);
365 // imm32 = ZeroExtend(imm8:'00', 32)
366 static inline uint32_t ThumbImm8Scaled(uint32_t opcode
) {
367 const uint32_t imm8
= bits(opcode
, 7, 0);
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; }
375 } // namespace lldb_private
377 #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_ARMUTILS_H