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
19namespace lldb_private {
20
21static inline uint32_t Align(uint32_t val, uint32_t alignment)
22{
23    return alignment * (val / alignment);
24}
25
26static 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.
60static 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.
67static 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
72static 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
78static 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
95static 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
106static 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
119static 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
130static 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
143static 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
164static 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
177static 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
190static 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
203static 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
210static 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
221static 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
261static 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
273static 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
278static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
279{
280    return bits(val, msbit, msbit);
281}
282
283static 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)
290static 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
308static 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)
317static 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
356static 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)
365static 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)
375static 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)
382static 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.
390static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
391
392}   // namespace lldb_private
393
394#endif  // lldb_ARMUtils_h_
395