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(Bits32(opcode, 5, 4), 58 Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 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(Bits32(opcode, 6, 5), Bits32(opcode, 11, 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(shift_t, imm5, 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(value, 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, 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(value, 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, 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, 31); 147 if (amount <= 32) { 148 carry_out = Bit32(value, amount - 1); 149 int64_t extended = llvm::SignExtend64<32>(value); 150 return UnsignedBits(extended, amount + 31, 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, 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>(value, amount); 178 carry_out = Bit32(value, 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, 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(value, 0); 199 return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 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, 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, 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(val, msbit, lsbit); 268 } 269 270 static inline uint32_t bit(const uint32_t val, const uint32_t msbit) { 271 return bits(val, msbit, 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(opcode, 7, 0); // immediate value 284 uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount 285 if (amt == 0) { 286 imm32 = imm; 287 carry_out = carry_in; 288 } else { 289 imm32 = ror(imm, 32, amt); 290 carry_out = Bit32(imm32, 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(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; 311 312 if (bits(imm12, 11, 10) == 0) { 313 switch (bits(imm12, 9, 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(imm12, 6, 0); 336 imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7)); 337 carry_out = Bit32(imm32, 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(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; 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(opcode, 6, 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(opcode, 7, 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