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