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