xref: /aosp_15_r20/external/vixl/src/aarch32/instructions-aarch32.h (revision f5c631da2f1efdd72b5fd1e20510e4042af13d77)
1*f5c631daSSadaf Ebrahimi // Copyright 2017, VIXL authors
2*f5c631daSSadaf Ebrahimi // All rights reserved.
3*f5c631daSSadaf Ebrahimi //
4*f5c631daSSadaf Ebrahimi // Redistribution and use in source and binary forms, with or without
5*f5c631daSSadaf Ebrahimi // modification, are permitted provided that the following conditions are met:
6*f5c631daSSadaf Ebrahimi //
7*f5c631daSSadaf Ebrahimi //   * Redistributions of source code must retain the above copyright notice,
8*f5c631daSSadaf Ebrahimi //     this list of conditions and the following disclaimer.
9*f5c631daSSadaf Ebrahimi //   * Redistributions in binary form must reproduce the above copyright notice,
10*f5c631daSSadaf Ebrahimi //     this list of conditions and the following disclaimer in the documentation
11*f5c631daSSadaf Ebrahimi //     and/or other materials provided with the distribution.
12*f5c631daSSadaf Ebrahimi //   * Neither the name of ARM Limited nor the names of its contributors may be
13*f5c631daSSadaf Ebrahimi //     used to endorse or promote products derived from this software without
14*f5c631daSSadaf Ebrahimi //     specific prior written permission.
15*f5c631daSSadaf Ebrahimi //
16*f5c631daSSadaf Ebrahimi // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17*f5c631daSSadaf Ebrahimi // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*f5c631daSSadaf Ebrahimi // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*f5c631daSSadaf Ebrahimi // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20*f5c631daSSadaf Ebrahimi // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*f5c631daSSadaf Ebrahimi // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22*f5c631daSSadaf Ebrahimi // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23*f5c631daSSadaf Ebrahimi // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*f5c631daSSadaf Ebrahimi // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25*f5c631daSSadaf Ebrahimi // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*f5c631daSSadaf Ebrahimi 
27*f5c631daSSadaf Ebrahimi #ifndef VIXL_AARCH32_INSTRUCTIONS_AARCH32_H_
28*f5c631daSSadaf Ebrahimi #define VIXL_AARCH32_INSTRUCTIONS_AARCH32_H_
29*f5c631daSSadaf Ebrahimi 
30*f5c631daSSadaf Ebrahimi extern "C" {
31*f5c631daSSadaf Ebrahimi #include <stdint.h>
32*f5c631daSSadaf Ebrahimi }
33*f5c631daSSadaf Ebrahimi 
34*f5c631daSSadaf Ebrahimi #include <algorithm>
35*f5c631daSSadaf Ebrahimi #include <ostream>
36*f5c631daSSadaf Ebrahimi 
37*f5c631daSSadaf Ebrahimi #include "code-buffer-vixl.h"
38*f5c631daSSadaf Ebrahimi #include "utils-vixl.h"
39*f5c631daSSadaf Ebrahimi #include "aarch32/constants-aarch32.h"
40*f5c631daSSadaf Ebrahimi 
41*f5c631daSSadaf Ebrahimi #if defined(__arm__) && !defined(__SOFTFP__)
42*f5c631daSSadaf Ebrahimi #define HARDFLOAT __attribute__((noinline, pcs("aapcs-vfp")))
43*f5c631daSSadaf Ebrahimi #else
44*f5c631daSSadaf Ebrahimi #define HARDFLOAT __attribute__((noinline))
45*f5c631daSSadaf Ebrahimi #endif
46*f5c631daSSadaf Ebrahimi 
47*f5c631daSSadaf Ebrahimi namespace vixl {
48*f5c631daSSadaf Ebrahimi namespace aarch32 {
49*f5c631daSSadaf Ebrahimi 
50*f5c631daSSadaf Ebrahimi class Operand;
51*f5c631daSSadaf Ebrahimi class SOperand;
52*f5c631daSSadaf Ebrahimi class DOperand;
53*f5c631daSSadaf Ebrahimi class QOperand;
54*f5c631daSSadaf Ebrahimi class MemOperand;
55*f5c631daSSadaf Ebrahimi class AlignedMemOperand;
56*f5c631daSSadaf Ebrahimi 
57*f5c631daSSadaf Ebrahimi enum AddrMode { Offset = 0, PreIndex = 1, PostIndex = 2 };
58*f5c631daSSadaf Ebrahimi 
59*f5c631daSSadaf Ebrahimi class CPURegister {
60*f5c631daSSadaf Ebrahimi  public:
61*f5c631daSSadaf Ebrahimi   enum RegisterType {
62*f5c631daSSadaf Ebrahimi     kNoRegister = 0,
63*f5c631daSSadaf Ebrahimi     kRRegister = 1,
64*f5c631daSSadaf Ebrahimi     kSRegister = 2,
65*f5c631daSSadaf Ebrahimi     kDRegister = 3,
66*f5c631daSSadaf Ebrahimi     kQRegister = 4
67*f5c631daSSadaf Ebrahimi   };
68*f5c631daSSadaf Ebrahimi 
69*f5c631daSSadaf Ebrahimi  private:
70*f5c631daSSadaf Ebrahimi   static const int kCodeBits = 5;
71*f5c631daSSadaf Ebrahimi   static const int kTypeBits = 4;
72*f5c631daSSadaf Ebrahimi   static const int kSizeBits = 8;
73*f5c631daSSadaf Ebrahimi   static const int kCodeShift = 0;
74*f5c631daSSadaf Ebrahimi   static const int kTypeShift = kCodeShift + kCodeBits;
75*f5c631daSSadaf Ebrahimi   static const int kSizeShift = kTypeShift + kTypeBits;
76*f5c631daSSadaf Ebrahimi   static const uint32_t kCodeMask = ((1 << kCodeBits) - 1) << kCodeShift;
77*f5c631daSSadaf Ebrahimi   static const uint32_t kTypeMask = ((1 << kTypeBits) - 1) << kTypeShift;
78*f5c631daSSadaf Ebrahimi   static const uint32_t kSizeMask = ((1 << kSizeBits) - 1) << kSizeShift;
79*f5c631daSSadaf Ebrahimi   uint32_t value_;
80*f5c631daSSadaf Ebrahimi 
81*f5c631daSSadaf Ebrahimi  public:
CPURegister(RegisterType type,uint32_t code,int size)82*f5c631daSSadaf Ebrahimi   CPURegister(RegisterType type, uint32_t code, int size)
83*f5c631daSSadaf Ebrahimi       : value_((type << kTypeShift) | (code << kCodeShift) |
84*f5c631daSSadaf Ebrahimi                (size << kSizeShift)) {
85*f5c631daSSadaf Ebrahimi #ifdef VIXL_DEBUG
86*f5c631daSSadaf Ebrahimi     switch (type) {
87*f5c631daSSadaf Ebrahimi       case kNoRegister:
88*f5c631daSSadaf Ebrahimi         break;
89*f5c631daSSadaf Ebrahimi       case kRRegister:
90*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(code < kNumberOfRegisters);
91*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(size == kRegSizeInBits);
92*f5c631daSSadaf Ebrahimi         break;
93*f5c631daSSadaf Ebrahimi       case kSRegister:
94*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(code < kNumberOfSRegisters);
95*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(size == kSRegSizeInBits);
96*f5c631daSSadaf Ebrahimi         break;
97*f5c631daSSadaf Ebrahimi       case kDRegister:
98*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(code < kMaxNumberOfDRegisters);
99*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(size == kDRegSizeInBits);
100*f5c631daSSadaf Ebrahimi         break;
101*f5c631daSSadaf Ebrahimi       case kQRegister:
102*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(code < kNumberOfQRegisters);
103*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(size == kQRegSizeInBits);
104*f5c631daSSadaf Ebrahimi         break;
105*f5c631daSSadaf Ebrahimi       default:
106*f5c631daSSadaf Ebrahimi         VIXL_UNREACHABLE();
107*f5c631daSSadaf Ebrahimi         break;
108*f5c631daSSadaf Ebrahimi     }
109*f5c631daSSadaf Ebrahimi #endif
110*f5c631daSSadaf Ebrahimi   }
GetType()111*f5c631daSSadaf Ebrahimi   RegisterType GetType() const {
112*f5c631daSSadaf Ebrahimi     return static_cast<RegisterType>((value_ & kTypeMask) >> kTypeShift);
113*f5c631daSSadaf Ebrahimi   }
IsRegister()114*f5c631daSSadaf Ebrahimi   bool IsRegister() const { return GetType() == kRRegister; }
IsS()115*f5c631daSSadaf Ebrahimi   bool IsS() const { return GetType() == kSRegister; }
IsD()116*f5c631daSSadaf Ebrahimi   bool IsD() const { return GetType() == kDRegister; }
IsQ()117*f5c631daSSadaf Ebrahimi   bool IsQ() const { return GetType() == kQRegister; }
IsVRegister()118*f5c631daSSadaf Ebrahimi   bool IsVRegister() const { return IsS() || IsD() || IsQ(); }
IsFPRegister()119*f5c631daSSadaf Ebrahimi   bool IsFPRegister() const { return IsS() || IsD(); }
GetCode()120*f5c631daSSadaf Ebrahimi   uint32_t GetCode() const { return (value_ & kCodeMask) >> kCodeShift; }
GetReg()121*f5c631daSSadaf Ebrahimi   uint32_t GetReg() const { return value_; }
GetSizeInBits()122*f5c631daSSadaf Ebrahimi   int GetSizeInBits() const { return (value_ & kSizeMask) >> kSizeShift; }
GetRegSizeInBytes()123*f5c631daSSadaf Ebrahimi   int GetRegSizeInBytes() const {
124*f5c631daSSadaf Ebrahimi     return (GetType() == kNoRegister) ? 0 : (GetSizeInBits() / 8);
125*f5c631daSSadaf Ebrahimi   }
Is64Bits()126*f5c631daSSadaf Ebrahimi   bool Is64Bits() const { return GetSizeInBits() == 64; }
Is128Bits()127*f5c631daSSadaf Ebrahimi   bool Is128Bits() const { return GetSizeInBits() == 128; }
IsSameFormat(CPURegister reg)128*f5c631daSSadaf Ebrahimi   bool IsSameFormat(CPURegister reg) {
129*f5c631daSSadaf Ebrahimi     return (value_ & ~kCodeMask) == (reg.value_ & ~kCodeMask);
130*f5c631daSSadaf Ebrahimi   }
Is(CPURegister ref)131*f5c631daSSadaf Ebrahimi   bool Is(CPURegister ref) const { return GetReg() == ref.GetReg(); }
IsValid()132*f5c631daSSadaf Ebrahimi   bool IsValid() const { return GetType() != kNoRegister; }
133*f5c631daSSadaf Ebrahimi };
134*f5c631daSSadaf Ebrahimi 
135*f5c631daSSadaf Ebrahimi class Register : public CPURegister {
136*f5c631daSSadaf Ebrahimi  public:
Register()137*f5c631daSSadaf Ebrahimi   Register() : CPURegister(kNoRegister, 0, kRegSizeInBits) {}
Register(uint32_t code)138*f5c631daSSadaf Ebrahimi   explicit Register(uint32_t code)
139*f5c631daSSadaf Ebrahimi       : CPURegister(kRRegister, code % kNumberOfRegisters, kRegSizeInBits) {
140*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(GetCode() < kNumberOfRegisters);
141*f5c631daSSadaf Ebrahimi   }
Is(Register ref)142*f5c631daSSadaf Ebrahimi   bool Is(Register ref) const { return GetCode() == ref.GetCode(); }
IsLow()143*f5c631daSSadaf Ebrahimi   bool IsLow() const { return GetCode() < kNumberOfT32LowRegisters; }
IsLR()144*f5c631daSSadaf Ebrahimi   bool IsLR() const { return GetCode() == kLrCode; }
IsPC()145*f5c631daSSadaf Ebrahimi   bool IsPC() const { return GetCode() == kPcCode; }
IsSP()146*f5c631daSSadaf Ebrahimi   bool IsSP() const { return GetCode() == kSpCode; }
147*f5c631daSSadaf Ebrahimi };
148*f5c631daSSadaf Ebrahimi 
149*f5c631daSSadaf Ebrahimi std::ostream& operator<<(std::ostream& os, const Register reg);
150*f5c631daSSadaf Ebrahimi 
151*f5c631daSSadaf Ebrahimi class RegisterOrAPSR_nzcv {
152*f5c631daSSadaf Ebrahimi   uint32_t code_;
153*f5c631daSSadaf Ebrahimi 
154*f5c631daSSadaf Ebrahimi  public:
RegisterOrAPSR_nzcv(uint32_t code)155*f5c631daSSadaf Ebrahimi   explicit RegisterOrAPSR_nzcv(uint32_t code) : code_(code) {
156*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(code_ < kNumberOfRegisters);
157*f5c631daSSadaf Ebrahimi   }
IsAPSR_nzcv()158*f5c631daSSadaf Ebrahimi   bool IsAPSR_nzcv() const { return code_ == kPcCode; }
GetCode()159*f5c631daSSadaf Ebrahimi   uint32_t GetCode() const { return code_; }
AsRegister()160*f5c631daSSadaf Ebrahimi   Register AsRegister() const {
161*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(!IsAPSR_nzcv());
162*f5c631daSSadaf Ebrahimi     return Register(code_);
163*f5c631daSSadaf Ebrahimi   }
164*f5c631daSSadaf Ebrahimi };
165*f5c631daSSadaf Ebrahimi 
166*f5c631daSSadaf Ebrahimi const RegisterOrAPSR_nzcv APSR_nzcv(kPcCode);
167*f5c631daSSadaf Ebrahimi 
168*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os,
169*f5c631daSSadaf Ebrahimi                                 const RegisterOrAPSR_nzcv reg) {
170*f5c631daSSadaf Ebrahimi   if (reg.IsAPSR_nzcv()) return os << "APSR_nzcv";
171*f5c631daSSadaf Ebrahimi   return os << reg.AsRegister();
172*f5c631daSSadaf Ebrahimi }
173*f5c631daSSadaf Ebrahimi 
174*f5c631daSSadaf Ebrahimi class SRegister;
175*f5c631daSSadaf Ebrahimi class DRegister;
176*f5c631daSSadaf Ebrahimi class QRegister;
177*f5c631daSSadaf Ebrahimi 
178*f5c631daSSadaf Ebrahimi class VRegister : public CPURegister {
179*f5c631daSSadaf Ebrahimi  public:
VRegister()180*f5c631daSSadaf Ebrahimi   VRegister() : CPURegister(kNoRegister, 0, 0) {}
VRegister(RegisterType type,uint32_t code,int size)181*f5c631daSSadaf Ebrahimi   VRegister(RegisterType type, uint32_t code, int size)
182*f5c631daSSadaf Ebrahimi       : CPURegister(type, code, size) {}
183*f5c631daSSadaf Ebrahimi 
184*f5c631daSSadaf Ebrahimi   SRegister S() const;
185*f5c631daSSadaf Ebrahimi   DRegister D() const;
186*f5c631daSSadaf Ebrahimi   QRegister Q() const;
187*f5c631daSSadaf Ebrahimi };
188*f5c631daSSadaf Ebrahimi 
189*f5c631daSSadaf Ebrahimi class SRegister : public VRegister {
190*f5c631daSSadaf Ebrahimi  public:
SRegister()191*f5c631daSSadaf Ebrahimi   SRegister() : VRegister(kNoRegister, 0, kSRegSizeInBits) {}
SRegister(uint32_t code)192*f5c631daSSadaf Ebrahimi   explicit SRegister(uint32_t code)
193*f5c631daSSadaf Ebrahimi       : VRegister(kSRegister, code, kSRegSizeInBits) {}
Encode(int single_bit_field,int four_bit_field_lowest_bit)194*f5c631daSSadaf Ebrahimi   uint32_t Encode(int single_bit_field, int four_bit_field_lowest_bit) const {
195*f5c631daSSadaf Ebrahimi     if (four_bit_field_lowest_bit == 0) {
196*f5c631daSSadaf Ebrahimi       return ((GetCode() & 0x1) << single_bit_field) |
197*f5c631daSSadaf Ebrahimi              ((GetCode() & 0x1e) >> 1);
198*f5c631daSSadaf Ebrahimi     }
199*f5c631daSSadaf Ebrahimi     return ((GetCode() & 0x1) << single_bit_field) |
200*f5c631daSSadaf Ebrahimi            ((GetCode() & 0x1e) << (four_bit_field_lowest_bit - 1));
201*f5c631daSSadaf Ebrahimi   }
202*f5c631daSSadaf Ebrahimi };
203*f5c631daSSadaf Ebrahimi 
ExtractSRegister(uint32_t instr,int single_bit_field,int four_bit_field_lowest_bit)204*f5c631daSSadaf Ebrahimi inline unsigned ExtractSRegister(uint32_t instr,
205*f5c631daSSadaf Ebrahimi                                  int single_bit_field,
206*f5c631daSSadaf Ebrahimi                                  int four_bit_field_lowest_bit) {
207*f5c631daSSadaf Ebrahimi   VIXL_ASSERT(single_bit_field > 0);
208*f5c631daSSadaf Ebrahimi   if (four_bit_field_lowest_bit == 0) {
209*f5c631daSSadaf Ebrahimi     return ((instr << 1) & 0x1e) | ((instr >> single_bit_field) & 0x1);
210*f5c631daSSadaf Ebrahimi   }
211*f5c631daSSadaf Ebrahimi   return ((instr >> (four_bit_field_lowest_bit - 1)) & 0x1e) |
212*f5c631daSSadaf Ebrahimi          ((instr >> single_bit_field) & 0x1);
213*f5c631daSSadaf Ebrahimi }
214*f5c631daSSadaf Ebrahimi 
215*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, const SRegister reg) {
216*f5c631daSSadaf Ebrahimi   return os << "s" << reg.GetCode();
217*f5c631daSSadaf Ebrahimi }
218*f5c631daSSadaf Ebrahimi 
219*f5c631daSSadaf Ebrahimi class DRegister : public VRegister {
220*f5c631daSSadaf Ebrahimi  public:
DRegister()221*f5c631daSSadaf Ebrahimi   DRegister() : VRegister(kNoRegister, 0, kDRegSizeInBits) {}
DRegister(uint32_t code)222*f5c631daSSadaf Ebrahimi   explicit DRegister(uint32_t code)
223*f5c631daSSadaf Ebrahimi       : VRegister(kDRegister, code, kDRegSizeInBits) {}
GetLane(uint32_t lane)224*f5c631daSSadaf Ebrahimi   SRegister GetLane(uint32_t lane) const {
225*f5c631daSSadaf Ebrahimi     uint32_t lane_count = kDRegSizeInBits / kSRegSizeInBits;
226*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(lane < lane_count);
227*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(GetCode() * lane_count < kNumberOfSRegisters);
228*f5c631daSSadaf Ebrahimi     return SRegister(GetCode() * lane_count + lane);
229*f5c631daSSadaf Ebrahimi   }
Encode(int single_bit_field,int four_bit_field_lowest_bit)230*f5c631daSSadaf Ebrahimi   uint32_t Encode(int single_bit_field, int four_bit_field_lowest_bit) const {
231*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(single_bit_field >= 4);
232*f5c631daSSadaf Ebrahimi     return ((GetCode() & 0x10) << (single_bit_field - 4)) |
233*f5c631daSSadaf Ebrahimi            ((GetCode() & 0xf) << four_bit_field_lowest_bit);
234*f5c631daSSadaf Ebrahimi   }
235*f5c631daSSadaf Ebrahimi };
236*f5c631daSSadaf Ebrahimi 
ExtractDRegister(uint32_t instr,int single_bit_field,int four_bit_field_lowest_bit)237*f5c631daSSadaf Ebrahimi inline unsigned ExtractDRegister(uint32_t instr,
238*f5c631daSSadaf Ebrahimi                                  int single_bit_field,
239*f5c631daSSadaf Ebrahimi                                  int four_bit_field_lowest_bit) {
240*f5c631daSSadaf Ebrahimi   VIXL_ASSERT(single_bit_field >= 4);
241*f5c631daSSadaf Ebrahimi   return ((instr >> (single_bit_field - 4)) & 0x10) |
242*f5c631daSSadaf Ebrahimi          ((instr >> four_bit_field_lowest_bit) & 0xf);
243*f5c631daSSadaf Ebrahimi }
244*f5c631daSSadaf Ebrahimi 
245*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, const DRegister reg) {
246*f5c631daSSadaf Ebrahimi   return os << "d" << reg.GetCode();
247*f5c631daSSadaf Ebrahimi }
248*f5c631daSSadaf Ebrahimi 
249*f5c631daSSadaf Ebrahimi enum DataTypeType {
250*f5c631daSSadaf Ebrahimi   kDataTypeS = 0x100,
251*f5c631daSSadaf Ebrahimi   kDataTypeU = 0x200,
252*f5c631daSSadaf Ebrahimi   kDataTypeF = 0x300,
253*f5c631daSSadaf Ebrahimi   kDataTypeI = 0x400,
254*f5c631daSSadaf Ebrahimi   kDataTypeP = 0x500,
255*f5c631daSSadaf Ebrahimi   kDataTypeUntyped = 0x600
256*f5c631daSSadaf Ebrahimi };
257*f5c631daSSadaf Ebrahimi const int kDataTypeSizeMask = 0x0ff;
258*f5c631daSSadaf Ebrahimi const int kDataTypeTypeMask = 0x100;
259*f5c631daSSadaf Ebrahimi enum DataTypeValue {
260*f5c631daSSadaf Ebrahimi   kDataTypeValueInvalid = 0x000,
261*f5c631daSSadaf Ebrahimi   kDataTypeValueNone = 0x001,  // value used when dt is ignored.
262*f5c631daSSadaf Ebrahimi   S8 = kDataTypeS | 8,
263*f5c631daSSadaf Ebrahimi   S16 = kDataTypeS | 16,
264*f5c631daSSadaf Ebrahimi   S32 = kDataTypeS | 32,
265*f5c631daSSadaf Ebrahimi   S64 = kDataTypeS | 64,
266*f5c631daSSadaf Ebrahimi   U8 = kDataTypeU | 8,
267*f5c631daSSadaf Ebrahimi   U16 = kDataTypeU | 16,
268*f5c631daSSadaf Ebrahimi   U32 = kDataTypeU | 32,
269*f5c631daSSadaf Ebrahimi   U64 = kDataTypeU | 64,
270*f5c631daSSadaf Ebrahimi   F16 = kDataTypeF | 16,
271*f5c631daSSadaf Ebrahimi   F32 = kDataTypeF | 32,
272*f5c631daSSadaf Ebrahimi   F64 = kDataTypeF | 64,
273*f5c631daSSadaf Ebrahimi   I8 = kDataTypeI | 8,
274*f5c631daSSadaf Ebrahimi   I16 = kDataTypeI | 16,
275*f5c631daSSadaf Ebrahimi   I32 = kDataTypeI | 32,
276*f5c631daSSadaf Ebrahimi   I64 = kDataTypeI | 64,
277*f5c631daSSadaf Ebrahimi   P8 = kDataTypeP | 8,
278*f5c631daSSadaf Ebrahimi   P64 = kDataTypeP | 64,
279*f5c631daSSadaf Ebrahimi   Untyped8 = kDataTypeUntyped | 8,
280*f5c631daSSadaf Ebrahimi   Untyped16 = kDataTypeUntyped | 16,
281*f5c631daSSadaf Ebrahimi   Untyped32 = kDataTypeUntyped | 32,
282*f5c631daSSadaf Ebrahimi   Untyped64 = kDataTypeUntyped | 64
283*f5c631daSSadaf Ebrahimi };
284*f5c631daSSadaf Ebrahimi 
285*f5c631daSSadaf Ebrahimi class DataType {
286*f5c631daSSadaf Ebrahimi   DataTypeValue value_;
287*f5c631daSSadaf Ebrahimi 
288*f5c631daSSadaf Ebrahimi  public:
DataType(uint32_t size)289*f5c631daSSadaf Ebrahimi   explicit DataType(uint32_t size)
290*f5c631daSSadaf Ebrahimi       : value_(static_cast<DataTypeValue>(kDataTypeUntyped | size)) {
291*f5c631daSSadaf Ebrahimi     VIXL_ASSERT((size == 8) || (size == 16) || (size == 32) || (size == 64));
292*f5c631daSSadaf Ebrahimi   }
293*f5c631daSSadaf Ebrahimi   // Users should be able to use "S8", "S6" and so forth to instantiate this
294*f5c631daSSadaf Ebrahimi   // class.
DataType(DataTypeValue value)295*f5c631daSSadaf Ebrahimi   DataType(DataTypeValue value) : value_(value) {}  // NOLINT(runtime/explicit)
GetValue()296*f5c631daSSadaf Ebrahimi   DataTypeValue GetValue() const { return value_; }
GetType()297*f5c631daSSadaf Ebrahimi   DataTypeType GetType() const {
298*f5c631daSSadaf Ebrahimi     return static_cast<DataTypeType>(value_ & kDataTypeTypeMask);
299*f5c631daSSadaf Ebrahimi   }
GetSize()300*f5c631daSSadaf Ebrahimi   uint32_t GetSize() const { return value_ & kDataTypeSizeMask; }
IsSize(uint32_t size)301*f5c631daSSadaf Ebrahimi   bool IsSize(uint32_t size) const {
302*f5c631daSSadaf Ebrahimi     return (value_ & kDataTypeSizeMask) == size;
303*f5c631daSSadaf Ebrahimi   }
304*f5c631daSSadaf Ebrahimi   const char* GetName() const;
Is(DataType type)305*f5c631daSSadaf Ebrahimi   bool Is(DataType type) const { return value_ == type.value_; }
Is(DataTypeValue value)306*f5c631daSSadaf Ebrahimi   bool Is(DataTypeValue value) const { return value_ == value; }
Is(DataTypeType type)307*f5c631daSSadaf Ebrahimi   bool Is(DataTypeType type) const { return GetType() == type; }
IsNoneOr(DataTypeValue value)308*f5c631daSSadaf Ebrahimi   bool IsNoneOr(DataTypeValue value) const {
309*f5c631daSSadaf Ebrahimi     return (value_ == value) || (value_ == kDataTypeValueNone);
310*f5c631daSSadaf Ebrahimi   }
Is(DataTypeType type,uint32_t size)311*f5c631daSSadaf Ebrahimi   bool Is(DataTypeType type, uint32_t size) const {
312*f5c631daSSadaf Ebrahimi     return value_ == static_cast<DataTypeValue>(type | size);
313*f5c631daSSadaf Ebrahimi   }
IsNoneOr(DataTypeType type,uint32_t size)314*f5c631daSSadaf Ebrahimi   bool IsNoneOr(DataTypeType type, uint32_t size) const {
315*f5c631daSSadaf Ebrahimi     return Is(type, size) || Is(kDataTypeValueNone);
316*f5c631daSSadaf Ebrahimi   }
317*f5c631daSSadaf Ebrahimi };
318*f5c631daSSadaf Ebrahimi 
319*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, DataType dt) {
320*f5c631daSSadaf Ebrahimi   return os << dt.GetName();
321*f5c631daSSadaf Ebrahimi }
322*f5c631daSSadaf Ebrahimi 
323*f5c631daSSadaf Ebrahimi class DRegisterLane : public DRegister {
324*f5c631daSSadaf Ebrahimi   uint32_t lane_;
325*f5c631daSSadaf Ebrahimi 
326*f5c631daSSadaf Ebrahimi  public:
DRegisterLane(DRegister reg,uint32_t lane)327*f5c631daSSadaf Ebrahimi   DRegisterLane(DRegister reg, uint32_t lane)
328*f5c631daSSadaf Ebrahimi       : DRegister(reg.GetCode()), lane_(lane) {}
DRegisterLane(uint32_t code,uint32_t lane)329*f5c631daSSadaf Ebrahimi   DRegisterLane(uint32_t code, uint32_t lane) : DRegister(code), lane_(lane) {}
GetLane()330*f5c631daSSadaf Ebrahimi   uint32_t GetLane() const { return lane_; }
EncodeX(DataType dt,int single_bit_field,int four_bit_field_lowest_bit)331*f5c631daSSadaf Ebrahimi   uint32_t EncodeX(DataType dt,
332*f5c631daSSadaf Ebrahimi                    int single_bit_field,
333*f5c631daSSadaf Ebrahimi                    int four_bit_field_lowest_bit) const {
334*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(single_bit_field >= 4);
335*f5c631daSSadaf Ebrahimi     uint32_t value = lane_ << ((dt.GetSize() == 16) ? 3 : 4) | GetCode();
336*f5c631daSSadaf Ebrahimi     return ((value & 0x10) << (single_bit_field - 4)) |
337*f5c631daSSadaf Ebrahimi            ((value & 0xf) << four_bit_field_lowest_bit);
338*f5c631daSSadaf Ebrahimi   }
339*f5c631daSSadaf Ebrahimi };
340*f5c631daSSadaf Ebrahimi 
ExtractDRegisterAndLane(uint32_t instr,DataType dt,int single_bit_field,int four_bit_field_lowest_bit,int * lane)341*f5c631daSSadaf Ebrahimi inline unsigned ExtractDRegisterAndLane(uint32_t instr,
342*f5c631daSSadaf Ebrahimi                                         DataType dt,
343*f5c631daSSadaf Ebrahimi                                         int single_bit_field,
344*f5c631daSSadaf Ebrahimi                                         int four_bit_field_lowest_bit,
345*f5c631daSSadaf Ebrahimi                                         int* lane) {
346*f5c631daSSadaf Ebrahimi   VIXL_ASSERT(single_bit_field >= 4);
347*f5c631daSSadaf Ebrahimi   uint32_t value = ((instr >> (single_bit_field - 4)) & 0x10) |
348*f5c631daSSadaf Ebrahimi                    ((instr >> four_bit_field_lowest_bit) & 0xf);
349*f5c631daSSadaf Ebrahimi   if (dt.GetSize() == 16) {
350*f5c631daSSadaf Ebrahimi     *lane = value >> 3;
351*f5c631daSSadaf Ebrahimi     return value & 0x7;
352*f5c631daSSadaf Ebrahimi   }
353*f5c631daSSadaf Ebrahimi   *lane = value >> 4;
354*f5c631daSSadaf Ebrahimi   return value & 0xf;
355*f5c631daSSadaf Ebrahimi }
356*f5c631daSSadaf Ebrahimi 
357*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, const DRegisterLane lane) {
358*f5c631daSSadaf Ebrahimi   os << "d" << lane.GetCode() << "[";
359*f5c631daSSadaf Ebrahimi   if (lane.GetLane() == static_cast<uint32_t>(-1)) return os << "??]";
360*f5c631daSSadaf Ebrahimi   return os << lane.GetLane() << "]";
361*f5c631daSSadaf Ebrahimi }
362*f5c631daSSadaf Ebrahimi 
363*f5c631daSSadaf Ebrahimi class QRegister : public VRegister {
364*f5c631daSSadaf Ebrahimi  public:
QRegister()365*f5c631daSSadaf Ebrahimi   QRegister() : VRegister(kNoRegister, 0, kQRegSizeInBits) {}
QRegister(uint32_t code)366*f5c631daSSadaf Ebrahimi   explicit QRegister(uint32_t code)
367*f5c631daSSadaf Ebrahimi       : VRegister(kQRegister, code, kQRegSizeInBits) {}
Encode(int offset)368*f5c631daSSadaf Ebrahimi   uint32_t Encode(int offset) { return GetCode() << offset; }
GetDLane(uint32_t lane)369*f5c631daSSadaf Ebrahimi   DRegister GetDLane(uint32_t lane) const {
370*f5c631daSSadaf Ebrahimi     uint32_t lane_count = kQRegSizeInBits / kDRegSizeInBits;
371*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(lane < lane_count);
372*f5c631daSSadaf Ebrahimi     return DRegister(GetCode() * lane_count + lane);
373*f5c631daSSadaf Ebrahimi   }
GetLowDRegister()374*f5c631daSSadaf Ebrahimi   DRegister GetLowDRegister() const { return DRegister(GetCode() * 2); }
GetHighDRegister()375*f5c631daSSadaf Ebrahimi   DRegister GetHighDRegister() const { return DRegister(1 + GetCode() * 2); }
GetSLane(uint32_t lane)376*f5c631daSSadaf Ebrahimi   SRegister GetSLane(uint32_t lane) const {
377*f5c631daSSadaf Ebrahimi     uint32_t lane_count = kQRegSizeInBits / kSRegSizeInBits;
378*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(lane < lane_count);
379*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(GetCode() * lane_count < kNumberOfSRegisters);
380*f5c631daSSadaf Ebrahimi     return SRegister(GetCode() * lane_count + lane);
381*f5c631daSSadaf Ebrahimi   }
Encode(int single_bit_field,int four_bit_field_lowest_bit)382*f5c631daSSadaf Ebrahimi   uint32_t Encode(int single_bit_field, int four_bit_field_lowest_bit) {
383*f5c631daSSadaf Ebrahimi     // Encode "code * 2".
384*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(single_bit_field >= 3);
385*f5c631daSSadaf Ebrahimi     return ((GetCode() & 0x8) << (single_bit_field - 3)) |
386*f5c631daSSadaf Ebrahimi            ((GetCode() & 0x7) << (four_bit_field_lowest_bit + 1));
387*f5c631daSSadaf Ebrahimi   }
388*f5c631daSSadaf Ebrahimi };
389*f5c631daSSadaf Ebrahimi 
ExtractQRegister(uint32_t instr,int single_bit_field,int four_bit_field_lowest_bit)390*f5c631daSSadaf Ebrahimi inline unsigned ExtractQRegister(uint32_t instr,
391*f5c631daSSadaf Ebrahimi                                  int single_bit_field,
392*f5c631daSSadaf Ebrahimi                                  int four_bit_field_lowest_bit) {
393*f5c631daSSadaf Ebrahimi   VIXL_ASSERT(single_bit_field >= 3);
394*f5c631daSSadaf Ebrahimi   return ((instr >> (single_bit_field - 3)) & 0x8) |
395*f5c631daSSadaf Ebrahimi          ((instr >> (four_bit_field_lowest_bit + 1)) & 0x7);
396*f5c631daSSadaf Ebrahimi }
397*f5c631daSSadaf Ebrahimi 
398*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, const QRegister reg) {
399*f5c631daSSadaf Ebrahimi   return os << "q" << reg.GetCode();
400*f5c631daSSadaf Ebrahimi }
401*f5c631daSSadaf Ebrahimi 
402*f5c631daSSadaf Ebrahimi // clang-format off
403*f5c631daSSadaf Ebrahimi #define AARCH32_REGISTER_CODE_LIST(R)                                          \
404*f5c631daSSadaf Ebrahimi   R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)                               \
405*f5c631daSSadaf Ebrahimi   R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)
406*f5c631daSSadaf Ebrahimi // clang-format on
407*f5c631daSSadaf Ebrahimi #define DEFINE_REGISTER(N) const Register r##N(N);
408*f5c631daSSadaf Ebrahimi AARCH32_REGISTER_CODE_LIST(DEFINE_REGISTER)
409*f5c631daSSadaf Ebrahimi #undef DEFINE_REGISTER
410*f5c631daSSadaf Ebrahimi #undef AARCH32_REGISTER_CODE_LIST
411*f5c631daSSadaf Ebrahimi 
412*f5c631daSSadaf Ebrahimi enum RegNum { kIPRegNum = 12, kSPRegNum = 13, kLRRegNum = 14, kPCRegNum = 15 };
413*f5c631daSSadaf Ebrahimi 
414*f5c631daSSadaf Ebrahimi const Register ip(kIPRegNum);
415*f5c631daSSadaf Ebrahimi const Register sp(kSPRegNum);
416*f5c631daSSadaf Ebrahimi const Register pc(kPCRegNum);
417*f5c631daSSadaf Ebrahimi const Register lr(kLRRegNum);
418*f5c631daSSadaf Ebrahimi const Register NoReg;
419*f5c631daSSadaf Ebrahimi const VRegister NoVReg;
420*f5c631daSSadaf Ebrahimi 
421*f5c631daSSadaf Ebrahimi // clang-format off
422*f5c631daSSadaf Ebrahimi #define SREGISTER_CODE_LIST(R)                                                 \
423*f5c631daSSadaf Ebrahimi   R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)                               \
424*f5c631daSSadaf Ebrahimi   R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)                              \
425*f5c631daSSadaf Ebrahimi   R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23)                              \
426*f5c631daSSadaf Ebrahimi   R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
427*f5c631daSSadaf Ebrahimi // clang-format on
428*f5c631daSSadaf Ebrahimi #define DEFINE_REGISTER(N) const SRegister s##N(N);
429*f5c631daSSadaf Ebrahimi SREGISTER_CODE_LIST(DEFINE_REGISTER)
430*f5c631daSSadaf Ebrahimi #undef DEFINE_REGISTER
431*f5c631daSSadaf Ebrahimi #undef SREGISTER_CODE_LIST
432*f5c631daSSadaf Ebrahimi const SRegister NoSReg;
433*f5c631daSSadaf Ebrahimi 
434*f5c631daSSadaf Ebrahimi // clang-format off
435*f5c631daSSadaf Ebrahimi #define DREGISTER_CODE_LIST(R)                                                 \
436*f5c631daSSadaf Ebrahimi R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)                                 \
437*f5c631daSSadaf Ebrahimi R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)                                \
438*f5c631daSSadaf Ebrahimi R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23)                                \
439*f5c631daSSadaf Ebrahimi R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
440*f5c631daSSadaf Ebrahimi // clang-format on
441*f5c631daSSadaf Ebrahimi #define DEFINE_REGISTER(N) const DRegister d##N(N);
442*f5c631daSSadaf Ebrahimi DREGISTER_CODE_LIST(DEFINE_REGISTER)
443*f5c631daSSadaf Ebrahimi #undef DEFINE_REGISTER
444*f5c631daSSadaf Ebrahimi #undef DREGISTER_CODE_LIST
445*f5c631daSSadaf Ebrahimi const DRegister NoDReg;
446*f5c631daSSadaf Ebrahimi 
447*f5c631daSSadaf Ebrahimi // clang-format off
448*f5c631daSSadaf Ebrahimi #define QREGISTER_CODE_LIST(R)                                                 \
449*f5c631daSSadaf Ebrahimi   R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)                               \
450*f5c631daSSadaf Ebrahimi   R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)
451*f5c631daSSadaf Ebrahimi // clang-format on
452*f5c631daSSadaf Ebrahimi #define DEFINE_REGISTER(N) const QRegister q##N(N);
QREGISTER_CODE_LIST(DEFINE_REGISTER)453*f5c631daSSadaf Ebrahimi QREGISTER_CODE_LIST(DEFINE_REGISTER)
454*f5c631daSSadaf Ebrahimi #undef DEFINE_REGISTER
455*f5c631daSSadaf Ebrahimi #undef QREGISTER_CODE_LIST
456*f5c631daSSadaf Ebrahimi const QRegister NoQReg;
457*f5c631daSSadaf Ebrahimi 
458*f5c631daSSadaf Ebrahimi class RegisterList {
459*f5c631daSSadaf Ebrahimi  public:
460*f5c631daSSadaf Ebrahimi   RegisterList() : list_(0) {}
461*f5c631daSSadaf Ebrahimi   RegisterList(Register reg)  // NOLINT(runtime/explicit)
462*f5c631daSSadaf Ebrahimi       : list_(RegisterToList(reg)) {}
463*f5c631daSSadaf Ebrahimi   RegisterList(Register reg1, Register reg2)
464*f5c631daSSadaf Ebrahimi       : list_(RegisterToList(reg1) | RegisterToList(reg2)) {}
465*f5c631daSSadaf Ebrahimi   RegisterList(Register reg1, Register reg2, Register reg3)
466*f5c631daSSadaf Ebrahimi       : list_(RegisterToList(reg1) | RegisterToList(reg2) |
467*f5c631daSSadaf Ebrahimi               RegisterToList(reg3)) {}
468*f5c631daSSadaf Ebrahimi   RegisterList(Register reg1, Register reg2, Register reg3, Register reg4)
469*f5c631daSSadaf Ebrahimi       : list_(RegisterToList(reg1) | RegisterToList(reg2) |
470*f5c631daSSadaf Ebrahimi               RegisterToList(reg3) | RegisterToList(reg4)) {}
471*f5c631daSSadaf Ebrahimi   explicit RegisterList(uint32_t list) : list_(list) {}
472*f5c631daSSadaf Ebrahimi   uint32_t GetList() const { return list_; }
473*f5c631daSSadaf Ebrahimi   void SetList(uint32_t list) { list_ = list; }
474*f5c631daSSadaf Ebrahimi   bool Includes(const Register& reg) const {
475*f5c631daSSadaf Ebrahimi     return (list_ & RegisterToList(reg)) != 0;
476*f5c631daSSadaf Ebrahimi   }
477*f5c631daSSadaf Ebrahimi   void Combine(const RegisterList& other) { list_ |= other.GetList(); }
478*f5c631daSSadaf Ebrahimi   void Combine(const Register& reg) { list_ |= RegisterToList(reg); }
479*f5c631daSSadaf Ebrahimi   void Remove(const RegisterList& other) { list_ &= ~other.GetList(); }
480*f5c631daSSadaf Ebrahimi   void Remove(const Register& reg) { list_ &= ~RegisterToList(reg); }
481*f5c631daSSadaf Ebrahimi   bool Overlaps(const RegisterList& other) const {
482*f5c631daSSadaf Ebrahimi     return (list_ & other.list_) != 0;
483*f5c631daSSadaf Ebrahimi   }
484*f5c631daSSadaf Ebrahimi   bool IsR0toR7orPC() const {
485*f5c631daSSadaf Ebrahimi     // True if all the registers from the list are not from r8-r14.
486*f5c631daSSadaf Ebrahimi     return (list_ & 0x7f00) == 0;
487*f5c631daSSadaf Ebrahimi   }
488*f5c631daSSadaf Ebrahimi   bool IsR0toR7orLR() const {
489*f5c631daSSadaf Ebrahimi     // True if all the registers from the list are not from r8-r13 nor from r15.
490*f5c631daSSadaf Ebrahimi     return (list_ & 0xbf00) == 0;
491*f5c631daSSadaf Ebrahimi   }
492*f5c631daSSadaf Ebrahimi   Register GetFirstAvailableRegister() const;
493*f5c631daSSadaf Ebrahimi   bool IsEmpty() const { return list_ == 0; }
494*f5c631daSSadaf Ebrahimi   bool IsSingleRegister() const { return IsPowerOf2(list_); }
495*f5c631daSSadaf Ebrahimi   int GetCount() const { return CountSetBits(list_); }
496*f5c631daSSadaf Ebrahimi   static RegisterList Union(const RegisterList& list_1,
497*f5c631daSSadaf Ebrahimi                             const RegisterList& list_2) {
498*f5c631daSSadaf Ebrahimi     return RegisterList(list_1.list_ | list_2.list_);
499*f5c631daSSadaf Ebrahimi   }
500*f5c631daSSadaf Ebrahimi   static RegisterList Union(const RegisterList& list_1,
501*f5c631daSSadaf Ebrahimi                             const RegisterList& list_2,
502*f5c631daSSadaf Ebrahimi                             const RegisterList& list_3) {
503*f5c631daSSadaf Ebrahimi     return Union(list_1, Union(list_2, list_3));
504*f5c631daSSadaf Ebrahimi   }
505*f5c631daSSadaf Ebrahimi   static RegisterList Union(const RegisterList& list_1,
506*f5c631daSSadaf Ebrahimi                             const RegisterList& list_2,
507*f5c631daSSadaf Ebrahimi                             const RegisterList& list_3,
508*f5c631daSSadaf Ebrahimi                             const RegisterList& list_4) {
509*f5c631daSSadaf Ebrahimi     return Union(Union(list_1, list_2), Union(list_3, list_4));
510*f5c631daSSadaf Ebrahimi   }
511*f5c631daSSadaf Ebrahimi   static RegisterList Intersection(const RegisterList& list_1,
512*f5c631daSSadaf Ebrahimi                                    const RegisterList& list_2) {
513*f5c631daSSadaf Ebrahimi     return RegisterList(list_1.list_ & list_2.list_);
514*f5c631daSSadaf Ebrahimi   }
515*f5c631daSSadaf Ebrahimi   static RegisterList Intersection(const RegisterList& list_1,
516*f5c631daSSadaf Ebrahimi                                    const RegisterList& list_2,
517*f5c631daSSadaf Ebrahimi                                    const RegisterList& list_3) {
518*f5c631daSSadaf Ebrahimi     return Intersection(list_1, Intersection(list_2, list_3));
519*f5c631daSSadaf Ebrahimi   }
520*f5c631daSSadaf Ebrahimi   static RegisterList Intersection(const RegisterList& list_1,
521*f5c631daSSadaf Ebrahimi                                    const RegisterList& list_2,
522*f5c631daSSadaf Ebrahimi                                    const RegisterList& list_3,
523*f5c631daSSadaf Ebrahimi                                    const RegisterList& list_4) {
524*f5c631daSSadaf Ebrahimi     return Intersection(Intersection(list_1, list_2),
525*f5c631daSSadaf Ebrahimi                         Intersection(list_3, list_4));
526*f5c631daSSadaf Ebrahimi   }
527*f5c631daSSadaf Ebrahimi 
528*f5c631daSSadaf Ebrahimi  private:
529*f5c631daSSadaf Ebrahimi   static uint32_t RegisterToList(Register reg) {
530*f5c631daSSadaf Ebrahimi     if (reg.GetType() == CPURegister::kNoRegister) {
531*f5c631daSSadaf Ebrahimi       return 0;
532*f5c631daSSadaf Ebrahimi     } else {
533*f5c631daSSadaf Ebrahimi       return UINT32_C(1) << reg.GetCode();
534*f5c631daSSadaf Ebrahimi     }
535*f5c631daSSadaf Ebrahimi   }
536*f5c631daSSadaf Ebrahimi 
537*f5c631daSSadaf Ebrahimi   // Bitfield representation of all registers in the list
538*f5c631daSSadaf Ebrahimi   // (1 for r0, 2 for r1, 4 for r2, ...).
539*f5c631daSSadaf Ebrahimi   uint32_t list_;
540*f5c631daSSadaf Ebrahimi };
541*f5c631daSSadaf Ebrahimi 
GetRegisterListEncoding(const RegisterList & registers,int first,int count)542*f5c631daSSadaf Ebrahimi inline uint32_t GetRegisterListEncoding(const RegisterList& registers,
543*f5c631daSSadaf Ebrahimi                                         int first,
544*f5c631daSSadaf Ebrahimi                                         int count) {
545*f5c631daSSadaf Ebrahimi   return (registers.GetList() >> first) & ((1 << count) - 1);
546*f5c631daSSadaf Ebrahimi }
547*f5c631daSSadaf Ebrahimi 
548*f5c631daSSadaf Ebrahimi std::ostream& operator<<(std::ostream& os, RegisterList registers);
549*f5c631daSSadaf Ebrahimi 
550*f5c631daSSadaf Ebrahimi class VRegisterList {
551*f5c631daSSadaf Ebrahimi  public:
VRegisterList()552*f5c631daSSadaf Ebrahimi   VRegisterList() : list_(0) {}
VRegisterList(VRegister reg)553*f5c631daSSadaf Ebrahimi   explicit VRegisterList(VRegister reg) : list_(RegisterToList(reg)) {}
VRegisterList(VRegister reg1,VRegister reg2)554*f5c631daSSadaf Ebrahimi   VRegisterList(VRegister reg1, VRegister reg2)
555*f5c631daSSadaf Ebrahimi       : list_(RegisterToList(reg1) | RegisterToList(reg2)) {}
VRegisterList(VRegister reg1,VRegister reg2,VRegister reg3)556*f5c631daSSadaf Ebrahimi   VRegisterList(VRegister reg1, VRegister reg2, VRegister reg3)
557*f5c631daSSadaf Ebrahimi       : list_(RegisterToList(reg1) | RegisterToList(reg2) |
558*f5c631daSSadaf Ebrahimi               RegisterToList(reg3)) {}
VRegisterList(VRegister reg1,VRegister reg2,VRegister reg3,VRegister reg4)559*f5c631daSSadaf Ebrahimi   VRegisterList(VRegister reg1, VRegister reg2, VRegister reg3, VRegister reg4)
560*f5c631daSSadaf Ebrahimi       : list_(RegisterToList(reg1) | RegisterToList(reg2) |
561*f5c631daSSadaf Ebrahimi               RegisterToList(reg3) | RegisterToList(reg4)) {}
VRegisterList(uint64_t list)562*f5c631daSSadaf Ebrahimi   explicit VRegisterList(uint64_t list) : list_(list) {}
GetList()563*f5c631daSSadaf Ebrahimi   uint64_t GetList() const { return list_; }
SetList(uint64_t list)564*f5c631daSSadaf Ebrahimi   void SetList(uint64_t list) { list_ = list; }
565*f5c631daSSadaf Ebrahimi   // Because differently-sized V registers overlap with one another, there is no
566*f5c631daSSadaf Ebrahimi   // way to implement a single 'Includes' function in a way that is unsurprising
567*f5c631daSSadaf Ebrahimi   // for all existing uses.
IncludesAllOf(const VRegister & reg)568*f5c631daSSadaf Ebrahimi   bool IncludesAllOf(const VRegister& reg) const {
569*f5c631daSSadaf Ebrahimi     return (list_ & RegisterToList(reg)) == RegisterToList(reg);
570*f5c631daSSadaf Ebrahimi   }
IncludesAliasOf(const VRegister & reg)571*f5c631daSSadaf Ebrahimi   bool IncludesAliasOf(const VRegister& reg) const {
572*f5c631daSSadaf Ebrahimi     return (list_ & RegisterToList(reg)) != 0;
573*f5c631daSSadaf Ebrahimi   }
Combine(const VRegisterList & other)574*f5c631daSSadaf Ebrahimi   void Combine(const VRegisterList& other) { list_ |= other.GetList(); }
Combine(const VRegister & reg)575*f5c631daSSadaf Ebrahimi   void Combine(const VRegister& reg) { list_ |= RegisterToList(reg); }
Remove(const VRegisterList & other)576*f5c631daSSadaf Ebrahimi   void Remove(const VRegisterList& other) { list_ &= ~other.GetList(); }
Remove(const VRegister & reg)577*f5c631daSSadaf Ebrahimi   void Remove(const VRegister& reg) { list_ &= ~RegisterToList(reg); }
Overlaps(const VRegisterList & other)578*f5c631daSSadaf Ebrahimi   bool Overlaps(const VRegisterList& other) const {
579*f5c631daSSadaf Ebrahimi     return (list_ & other.list_) != 0;
580*f5c631daSSadaf Ebrahimi   }
581*f5c631daSSadaf Ebrahimi   QRegister GetFirstAvailableQRegister() const;
582*f5c631daSSadaf Ebrahimi   DRegister GetFirstAvailableDRegister() const;
583*f5c631daSSadaf Ebrahimi   SRegister GetFirstAvailableSRegister() const;
IsEmpty()584*f5c631daSSadaf Ebrahimi   bool IsEmpty() const { return list_ == 0; }
Union(const VRegisterList & list_1,const VRegisterList & list_2)585*f5c631daSSadaf Ebrahimi   static VRegisterList Union(const VRegisterList& list_1,
586*f5c631daSSadaf Ebrahimi                              const VRegisterList& list_2) {
587*f5c631daSSadaf Ebrahimi     return VRegisterList(list_1.list_ | list_2.list_);
588*f5c631daSSadaf Ebrahimi   }
Union(const VRegisterList & list_1,const VRegisterList & list_2,const VRegisterList & list_3)589*f5c631daSSadaf Ebrahimi   static VRegisterList Union(const VRegisterList& list_1,
590*f5c631daSSadaf Ebrahimi                              const VRegisterList& list_2,
591*f5c631daSSadaf Ebrahimi                              const VRegisterList& list_3) {
592*f5c631daSSadaf Ebrahimi     return Union(list_1, Union(list_2, list_3));
593*f5c631daSSadaf Ebrahimi   }
Union(const VRegisterList & list_1,const VRegisterList & list_2,const VRegisterList & list_3,const VRegisterList & list_4)594*f5c631daSSadaf Ebrahimi   static VRegisterList Union(const VRegisterList& list_1,
595*f5c631daSSadaf Ebrahimi                              const VRegisterList& list_2,
596*f5c631daSSadaf Ebrahimi                              const VRegisterList& list_3,
597*f5c631daSSadaf Ebrahimi                              const VRegisterList& list_4) {
598*f5c631daSSadaf Ebrahimi     return Union(Union(list_1, list_2), Union(list_3, list_4));
599*f5c631daSSadaf Ebrahimi   }
Intersection(const VRegisterList & list_1,const VRegisterList & list_2)600*f5c631daSSadaf Ebrahimi   static VRegisterList Intersection(const VRegisterList& list_1,
601*f5c631daSSadaf Ebrahimi                                     const VRegisterList& list_2) {
602*f5c631daSSadaf Ebrahimi     return VRegisterList(list_1.list_ & list_2.list_);
603*f5c631daSSadaf Ebrahimi   }
Intersection(const VRegisterList & list_1,const VRegisterList & list_2,const VRegisterList & list_3)604*f5c631daSSadaf Ebrahimi   static VRegisterList Intersection(const VRegisterList& list_1,
605*f5c631daSSadaf Ebrahimi                                     const VRegisterList& list_2,
606*f5c631daSSadaf Ebrahimi                                     const VRegisterList& list_3) {
607*f5c631daSSadaf Ebrahimi     return Intersection(list_1, Intersection(list_2, list_3));
608*f5c631daSSadaf Ebrahimi   }
Intersection(const VRegisterList & list_1,const VRegisterList & list_2,const VRegisterList & list_3,const VRegisterList & list_4)609*f5c631daSSadaf Ebrahimi   static VRegisterList Intersection(const VRegisterList& list_1,
610*f5c631daSSadaf Ebrahimi                                     const VRegisterList& list_2,
611*f5c631daSSadaf Ebrahimi                                     const VRegisterList& list_3,
612*f5c631daSSadaf Ebrahimi                                     const VRegisterList& list_4) {
613*f5c631daSSadaf Ebrahimi     return Intersection(Intersection(list_1, list_2),
614*f5c631daSSadaf Ebrahimi                         Intersection(list_3, list_4));
615*f5c631daSSadaf Ebrahimi   }
616*f5c631daSSadaf Ebrahimi 
617*f5c631daSSadaf Ebrahimi  private:
RegisterToList(VRegister reg)618*f5c631daSSadaf Ebrahimi   static uint64_t RegisterToList(VRegister reg) {
619*f5c631daSSadaf Ebrahimi     if (reg.GetType() == CPURegister::kNoRegister) {
620*f5c631daSSadaf Ebrahimi       return 0;
621*f5c631daSSadaf Ebrahimi     } else {
622*f5c631daSSadaf Ebrahimi       switch (reg.GetSizeInBits()) {
623*f5c631daSSadaf Ebrahimi         case kQRegSizeInBits:
624*f5c631daSSadaf Ebrahimi           return UINT64_C(0xf) << (reg.GetCode() * 4);
625*f5c631daSSadaf Ebrahimi         case kDRegSizeInBits:
626*f5c631daSSadaf Ebrahimi           return UINT64_C(0x3) << (reg.GetCode() * 2);
627*f5c631daSSadaf Ebrahimi         case kSRegSizeInBits:
628*f5c631daSSadaf Ebrahimi           return UINT64_C(0x1) << reg.GetCode();
629*f5c631daSSadaf Ebrahimi         default:
630*f5c631daSSadaf Ebrahimi           VIXL_UNREACHABLE();
631*f5c631daSSadaf Ebrahimi           return 0;
632*f5c631daSSadaf Ebrahimi       }
633*f5c631daSSadaf Ebrahimi     }
634*f5c631daSSadaf Ebrahimi   }
635*f5c631daSSadaf Ebrahimi 
636*f5c631daSSadaf Ebrahimi   // Bitfield representation of all registers in the list.
637*f5c631daSSadaf Ebrahimi   // (0x3 for d0, 0xc0 for d1, 0x30 for d2, ...). We have one, two or four bits
638*f5c631daSSadaf Ebrahimi   // per register according to their size. This way we can make sure that we
639*f5c631daSSadaf Ebrahimi   // account for overlapping registers.
640*f5c631daSSadaf Ebrahimi   // A register is wholly included in this list only if all of its bits are set.
641*f5c631daSSadaf Ebrahimi   // A register is aliased by the list if at least one of its bits are set.
642*f5c631daSSadaf Ebrahimi   // The IncludesAllOf and IncludesAliasOf helpers are provided to make this
643*f5c631daSSadaf Ebrahimi   // distinction clear.
644*f5c631daSSadaf Ebrahimi   uint64_t list_;
645*f5c631daSSadaf Ebrahimi };
646*f5c631daSSadaf Ebrahimi 
647*f5c631daSSadaf Ebrahimi class SRegisterList {
648*f5c631daSSadaf Ebrahimi   SRegister first_;
649*f5c631daSSadaf Ebrahimi   int length_;
650*f5c631daSSadaf Ebrahimi 
651*f5c631daSSadaf Ebrahimi  public:
SRegisterList(SRegister reg)652*f5c631daSSadaf Ebrahimi   explicit SRegisterList(SRegister reg) : first_(reg.GetCode()), length_(1) {}
SRegisterList(SRegister first,int length)653*f5c631daSSadaf Ebrahimi   SRegisterList(SRegister first, int length)
654*f5c631daSSadaf Ebrahimi       : first_(first.GetCode()), length_(length) {
655*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(length >= 0);
656*f5c631daSSadaf Ebrahimi   }
GetSRegister(int n)657*f5c631daSSadaf Ebrahimi   SRegister GetSRegister(int n) const {
658*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(n >= 0);
659*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(n < length_);
660*f5c631daSSadaf Ebrahimi     return SRegister((first_.GetCode() + n) % kNumberOfSRegisters);
661*f5c631daSSadaf Ebrahimi   }
GetFirstSRegister()662*f5c631daSSadaf Ebrahimi   const SRegister& GetFirstSRegister() const { return first_; }
GetLastSRegister()663*f5c631daSSadaf Ebrahimi   SRegister GetLastSRegister() const { return GetSRegister(length_ - 1); }
GetLength()664*f5c631daSSadaf Ebrahimi   int GetLength() const { return length_; }
665*f5c631daSSadaf Ebrahimi };
666*f5c631daSSadaf Ebrahimi 
667*f5c631daSSadaf Ebrahimi std::ostream& operator<<(std::ostream& os, SRegisterList registers);
668*f5c631daSSadaf Ebrahimi 
669*f5c631daSSadaf Ebrahimi class DRegisterList {
670*f5c631daSSadaf Ebrahimi   DRegister first_;
671*f5c631daSSadaf Ebrahimi   int length_;
672*f5c631daSSadaf Ebrahimi 
673*f5c631daSSadaf Ebrahimi  public:
DRegisterList(DRegister reg)674*f5c631daSSadaf Ebrahimi   explicit DRegisterList(DRegister reg) : first_(reg.GetCode()), length_(1) {}
DRegisterList(DRegister first,int length)675*f5c631daSSadaf Ebrahimi   DRegisterList(DRegister first, int length)
676*f5c631daSSadaf Ebrahimi       : first_(first.GetCode()), length_(length) {
677*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(length >= 0);
678*f5c631daSSadaf Ebrahimi   }
GetDRegister(int n)679*f5c631daSSadaf Ebrahimi   DRegister GetDRegister(int n) const {
680*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(n >= 0);
681*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(n < length_);
682*f5c631daSSadaf Ebrahimi     return DRegister((first_.GetCode() + n) % kMaxNumberOfDRegisters);
683*f5c631daSSadaf Ebrahimi   }
GetFirstDRegister()684*f5c631daSSadaf Ebrahimi   const DRegister& GetFirstDRegister() const { return first_; }
GetLastDRegister()685*f5c631daSSadaf Ebrahimi   DRegister GetLastDRegister() const { return GetDRegister(length_ - 1); }
GetLength()686*f5c631daSSadaf Ebrahimi   int GetLength() const { return length_; }
687*f5c631daSSadaf Ebrahimi };
688*f5c631daSSadaf Ebrahimi 
689*f5c631daSSadaf Ebrahimi std::ostream& operator<<(std::ostream& os, DRegisterList registers);
690*f5c631daSSadaf Ebrahimi 
691*f5c631daSSadaf Ebrahimi enum SpacingType { kSingle, kDouble };
692*f5c631daSSadaf Ebrahimi 
693*f5c631daSSadaf Ebrahimi enum TransferType { kMultipleLanes, kOneLane, kAllLanes };
694*f5c631daSSadaf Ebrahimi 
695*f5c631daSSadaf Ebrahimi class NeonRegisterList {
696*f5c631daSSadaf Ebrahimi   DRegister first_;
697*f5c631daSSadaf Ebrahimi   SpacingType spacing_;
698*f5c631daSSadaf Ebrahimi   TransferType type_;
699*f5c631daSSadaf Ebrahimi   int lane_;
700*f5c631daSSadaf Ebrahimi   int length_;
701*f5c631daSSadaf Ebrahimi 
702*f5c631daSSadaf Ebrahimi  public:
NeonRegisterList(DRegister reg,TransferType type)703*f5c631daSSadaf Ebrahimi   NeonRegisterList(DRegister reg, TransferType type)
704*f5c631daSSadaf Ebrahimi       : first_(reg.GetCode()),
705*f5c631daSSadaf Ebrahimi         spacing_(kSingle),
706*f5c631daSSadaf Ebrahimi         type_(type),
707*f5c631daSSadaf Ebrahimi         lane_(-1),
708*f5c631daSSadaf Ebrahimi         length_(1) {
709*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(type_ != kOneLane);
710*f5c631daSSadaf Ebrahimi   }
NeonRegisterList(DRegister reg,int lane)711*f5c631daSSadaf Ebrahimi   NeonRegisterList(DRegister reg, int lane)
712*f5c631daSSadaf Ebrahimi       : first_(reg.GetCode()),
713*f5c631daSSadaf Ebrahimi         spacing_(kSingle),
714*f5c631daSSadaf Ebrahimi         type_(kOneLane),
715*f5c631daSSadaf Ebrahimi         lane_(lane),
716*f5c631daSSadaf Ebrahimi         length_(1) {
717*f5c631daSSadaf Ebrahimi     VIXL_ASSERT((lane_ >= 0) && (lane_ < 8));
718*f5c631daSSadaf Ebrahimi   }
NeonRegisterList(DRegister first,DRegister last,SpacingType spacing,TransferType type)719*f5c631daSSadaf Ebrahimi   NeonRegisterList(DRegister first,
720*f5c631daSSadaf Ebrahimi                    DRegister last,
721*f5c631daSSadaf Ebrahimi                    SpacingType spacing,
722*f5c631daSSadaf Ebrahimi                    TransferType type)
723*f5c631daSSadaf Ebrahimi       : first_(first.GetCode()), spacing_(spacing), type_(type), lane_(-1) {
724*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(type != kOneLane);
725*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(first.GetCode() <= last.GetCode());
726*f5c631daSSadaf Ebrahimi 
727*f5c631daSSadaf Ebrahimi     int range = last.GetCode() - first.GetCode();
728*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(IsSingleSpaced() || IsMultiple(range, 2));
729*f5c631daSSadaf Ebrahimi     length_ = (IsDoubleSpaced() ? (range / 2) : range) + 1;
730*f5c631daSSadaf Ebrahimi 
731*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(length_ <= 4);
732*f5c631daSSadaf Ebrahimi   }
NeonRegisterList(DRegister first,DRegister last,SpacingType spacing,int lane)733*f5c631daSSadaf Ebrahimi   NeonRegisterList(DRegister first,
734*f5c631daSSadaf Ebrahimi                    DRegister last,
735*f5c631daSSadaf Ebrahimi                    SpacingType spacing,
736*f5c631daSSadaf Ebrahimi                    int lane)
737*f5c631daSSadaf Ebrahimi       : first_(first.GetCode()),
738*f5c631daSSadaf Ebrahimi         spacing_(spacing),
739*f5c631daSSadaf Ebrahimi         type_(kOneLane),
740*f5c631daSSadaf Ebrahimi         lane_(lane) {
741*f5c631daSSadaf Ebrahimi     VIXL_ASSERT((lane >= 0) && (lane < 8));
742*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(first.GetCode() <= last.GetCode());
743*f5c631daSSadaf Ebrahimi 
744*f5c631daSSadaf Ebrahimi     int range = last.GetCode() - first.GetCode();
745*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(IsSingleSpaced() || IsMultiple(range, 2));
746*f5c631daSSadaf Ebrahimi     length_ = (IsDoubleSpaced() ? (range / 2) : range) + 1;
747*f5c631daSSadaf Ebrahimi 
748*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(length_ <= 4);
749*f5c631daSSadaf Ebrahimi   }
GetDRegister(int n)750*f5c631daSSadaf Ebrahimi   DRegister GetDRegister(int n) const {
751*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(n >= 0);
752*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(n < length_);
753*f5c631daSSadaf Ebrahimi     unsigned code = first_.GetCode() + (IsDoubleSpaced() ? (2 * n) : n);
754*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(code < kMaxNumberOfDRegisters);
755*f5c631daSSadaf Ebrahimi     return DRegister(code);
756*f5c631daSSadaf Ebrahimi   }
GetFirstDRegister()757*f5c631daSSadaf Ebrahimi   const DRegister& GetFirstDRegister() const { return first_; }
GetLastDRegister()758*f5c631daSSadaf Ebrahimi   DRegister GetLastDRegister() const { return GetDRegister(length_ - 1); }
GetLength()759*f5c631daSSadaf Ebrahimi   int GetLength() const { return length_; }
IsSingleSpaced()760*f5c631daSSadaf Ebrahimi   bool IsSingleSpaced() const { return spacing_ == kSingle; }
IsDoubleSpaced()761*f5c631daSSadaf Ebrahimi   bool IsDoubleSpaced() const { return spacing_ == kDouble; }
IsTransferAllLanes()762*f5c631daSSadaf Ebrahimi   bool IsTransferAllLanes() const { return type_ == kAllLanes; }
IsTransferOneLane()763*f5c631daSSadaf Ebrahimi   bool IsTransferOneLane() const { return type_ == kOneLane; }
IsTransferMultipleLanes()764*f5c631daSSadaf Ebrahimi   bool IsTransferMultipleLanes() const { return type_ == kMultipleLanes; }
GetTransferLane()765*f5c631daSSadaf Ebrahimi   int GetTransferLane() const { return lane_; }
766*f5c631daSSadaf Ebrahimi };
767*f5c631daSSadaf Ebrahimi 
768*f5c631daSSadaf Ebrahimi std::ostream& operator<<(std::ostream& os, NeonRegisterList registers);
769*f5c631daSSadaf Ebrahimi 
770*f5c631daSSadaf Ebrahimi enum SpecialRegisterType { APSR = 0, CPSR = 0, SPSR = 1 };
771*f5c631daSSadaf Ebrahimi 
772*f5c631daSSadaf Ebrahimi class SpecialRegister {
773*f5c631daSSadaf Ebrahimi   uint32_t reg_;
774*f5c631daSSadaf Ebrahimi 
775*f5c631daSSadaf Ebrahimi  public:
SpecialRegister(uint32_t reg)776*f5c631daSSadaf Ebrahimi   explicit SpecialRegister(uint32_t reg) : reg_(reg) {}
SpecialRegister(SpecialRegisterType reg)777*f5c631daSSadaf Ebrahimi   SpecialRegister(SpecialRegisterType reg)  // NOLINT(runtime/explicit)
778*f5c631daSSadaf Ebrahimi       : reg_(reg) {}
GetReg()779*f5c631daSSadaf Ebrahimi   uint32_t GetReg() const { return reg_; }
780*f5c631daSSadaf Ebrahimi   const char* GetName() const;
Is(SpecialRegister value)781*f5c631daSSadaf Ebrahimi   bool Is(SpecialRegister value) const { return reg_ == value.reg_; }
Is(uint32_t value)782*f5c631daSSadaf Ebrahimi   bool Is(uint32_t value) const { return reg_ == value; }
IsNot(uint32_t value)783*f5c631daSSadaf Ebrahimi   bool IsNot(uint32_t value) const { return reg_ != value; }
784*f5c631daSSadaf Ebrahimi };
785*f5c631daSSadaf Ebrahimi 
786*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, SpecialRegister reg) {
787*f5c631daSSadaf Ebrahimi   return os << reg.GetName();
788*f5c631daSSadaf Ebrahimi }
789*f5c631daSSadaf Ebrahimi 
790*f5c631daSSadaf Ebrahimi enum BankedRegisterType {
791*f5c631daSSadaf Ebrahimi   R8_usr = 0x00,
792*f5c631daSSadaf Ebrahimi   R9_usr = 0x01,
793*f5c631daSSadaf Ebrahimi   R10_usr = 0x02,
794*f5c631daSSadaf Ebrahimi   R11_usr = 0x03,
795*f5c631daSSadaf Ebrahimi   R12_usr = 0x04,
796*f5c631daSSadaf Ebrahimi   SP_usr = 0x05,
797*f5c631daSSadaf Ebrahimi   LR_usr = 0x06,
798*f5c631daSSadaf Ebrahimi   R8_fiq = 0x08,
799*f5c631daSSadaf Ebrahimi   R9_fiq = 0x09,
800*f5c631daSSadaf Ebrahimi   R10_fiq = 0x0a,
801*f5c631daSSadaf Ebrahimi   R11_fiq = 0x0b,
802*f5c631daSSadaf Ebrahimi   R12_fiq = 0x0c,
803*f5c631daSSadaf Ebrahimi   SP_fiq = 0x0d,
804*f5c631daSSadaf Ebrahimi   LR_fiq = 0x0e,
805*f5c631daSSadaf Ebrahimi   LR_irq = 0x10,
806*f5c631daSSadaf Ebrahimi   SP_irq = 0x11,
807*f5c631daSSadaf Ebrahimi   LR_svc = 0x12,
808*f5c631daSSadaf Ebrahimi   SP_svc = 0x13,
809*f5c631daSSadaf Ebrahimi   LR_abt = 0x14,
810*f5c631daSSadaf Ebrahimi   SP_abt = 0x15,
811*f5c631daSSadaf Ebrahimi   LR_und = 0x16,
812*f5c631daSSadaf Ebrahimi   SP_und = 0x17,
813*f5c631daSSadaf Ebrahimi   LR_mon = 0x1c,
814*f5c631daSSadaf Ebrahimi   SP_mon = 0x1d,
815*f5c631daSSadaf Ebrahimi   ELR_hyp = 0x1e,
816*f5c631daSSadaf Ebrahimi   SP_hyp = 0x1f,
817*f5c631daSSadaf Ebrahimi   SPSR_fiq = 0x2e,
818*f5c631daSSadaf Ebrahimi   SPSR_irq = 0x30,
819*f5c631daSSadaf Ebrahimi   SPSR_svc = 0x32,
820*f5c631daSSadaf Ebrahimi   SPSR_abt = 0x34,
821*f5c631daSSadaf Ebrahimi   SPSR_und = 0x36,
822*f5c631daSSadaf Ebrahimi   SPSR_mon = 0x3c,
823*f5c631daSSadaf Ebrahimi   SPSR_hyp = 0x3e
824*f5c631daSSadaf Ebrahimi };
825*f5c631daSSadaf Ebrahimi 
826*f5c631daSSadaf Ebrahimi class BankedRegister {
827*f5c631daSSadaf Ebrahimi   uint32_t reg_;
828*f5c631daSSadaf Ebrahimi 
829*f5c631daSSadaf Ebrahimi  public:
BankedRegister(unsigned reg)830*f5c631daSSadaf Ebrahimi   explicit BankedRegister(unsigned reg) : reg_(reg) {}
BankedRegister(BankedRegisterType reg)831*f5c631daSSadaf Ebrahimi   BankedRegister(BankedRegisterType reg)  // NOLINT(runtime/explicit)
832*f5c631daSSadaf Ebrahimi       : reg_(reg) {}
GetCode()833*f5c631daSSadaf Ebrahimi   uint32_t GetCode() const { return reg_; }
834*f5c631daSSadaf Ebrahimi   const char* GetName() const;
835*f5c631daSSadaf Ebrahimi };
836*f5c631daSSadaf Ebrahimi 
837*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, BankedRegister reg) {
838*f5c631daSSadaf Ebrahimi   return os << reg.GetName();
839*f5c631daSSadaf Ebrahimi }
840*f5c631daSSadaf Ebrahimi 
841*f5c631daSSadaf Ebrahimi enum MaskedSpecialRegisterType {
842*f5c631daSSadaf Ebrahimi   APSR_nzcvq = 0x08,
843*f5c631daSSadaf Ebrahimi   APSR_g = 0x04,
844*f5c631daSSadaf Ebrahimi   APSR_nzcvqg = 0x0c,
845*f5c631daSSadaf Ebrahimi   CPSR_c = 0x01,
846*f5c631daSSadaf Ebrahimi   CPSR_x = 0x02,
847*f5c631daSSadaf Ebrahimi   CPSR_xc = 0x03,
848*f5c631daSSadaf Ebrahimi   CPSR_s = APSR_g,
849*f5c631daSSadaf Ebrahimi   CPSR_sc = 0x05,
850*f5c631daSSadaf Ebrahimi   CPSR_sx = 0x06,
851*f5c631daSSadaf Ebrahimi   CPSR_sxc = 0x07,
852*f5c631daSSadaf Ebrahimi   CPSR_f = APSR_nzcvq,
853*f5c631daSSadaf Ebrahimi   CPSR_fc = 0x09,
854*f5c631daSSadaf Ebrahimi   CPSR_fx = 0x0a,
855*f5c631daSSadaf Ebrahimi   CPSR_fxc = 0x0b,
856*f5c631daSSadaf Ebrahimi   CPSR_fs = APSR_nzcvqg,
857*f5c631daSSadaf Ebrahimi   CPSR_fsc = 0x0d,
858*f5c631daSSadaf Ebrahimi   CPSR_fsx = 0x0e,
859*f5c631daSSadaf Ebrahimi   CPSR_fsxc = 0x0f,
860*f5c631daSSadaf Ebrahimi   SPSR_c = 0x11,
861*f5c631daSSadaf Ebrahimi   SPSR_x = 0x12,
862*f5c631daSSadaf Ebrahimi   SPSR_xc = 0x13,
863*f5c631daSSadaf Ebrahimi   SPSR_s = 0x14,
864*f5c631daSSadaf Ebrahimi   SPSR_sc = 0x15,
865*f5c631daSSadaf Ebrahimi   SPSR_sx = 0x16,
866*f5c631daSSadaf Ebrahimi   SPSR_sxc = 0x17,
867*f5c631daSSadaf Ebrahimi   SPSR_f = 0x18,
868*f5c631daSSadaf Ebrahimi   SPSR_fc = 0x19,
869*f5c631daSSadaf Ebrahimi   SPSR_fx = 0x1a,
870*f5c631daSSadaf Ebrahimi   SPSR_fxc = 0x1b,
871*f5c631daSSadaf Ebrahimi   SPSR_fs = 0x1c,
872*f5c631daSSadaf Ebrahimi   SPSR_fsc = 0x1d,
873*f5c631daSSadaf Ebrahimi   SPSR_fsx = 0x1e,
874*f5c631daSSadaf Ebrahimi   SPSR_fsxc = 0x1f
875*f5c631daSSadaf Ebrahimi };
876*f5c631daSSadaf Ebrahimi 
877*f5c631daSSadaf Ebrahimi class MaskedSpecialRegister {
878*f5c631daSSadaf Ebrahimi   uint32_t reg_;
879*f5c631daSSadaf Ebrahimi 
880*f5c631daSSadaf Ebrahimi  public:
MaskedSpecialRegister(uint32_t reg)881*f5c631daSSadaf Ebrahimi   explicit MaskedSpecialRegister(uint32_t reg) : reg_(reg) {
882*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(reg <= SPSR_fsxc);
883*f5c631daSSadaf Ebrahimi   }
MaskedSpecialRegister(MaskedSpecialRegisterType reg)884*f5c631daSSadaf Ebrahimi   MaskedSpecialRegister(
885*f5c631daSSadaf Ebrahimi       MaskedSpecialRegisterType reg)  // NOLINT(runtime/explicit)
886*f5c631daSSadaf Ebrahimi       : reg_(reg) {}
GetReg()887*f5c631daSSadaf Ebrahimi   uint32_t GetReg() const { return reg_; }
888*f5c631daSSadaf Ebrahimi   const char* GetName() const;
Is(MaskedSpecialRegister value)889*f5c631daSSadaf Ebrahimi   bool Is(MaskedSpecialRegister value) const { return reg_ == value.reg_; }
Is(uint32_t value)890*f5c631daSSadaf Ebrahimi   bool Is(uint32_t value) const { return reg_ == value; }
IsNot(uint32_t value)891*f5c631daSSadaf Ebrahimi   bool IsNot(uint32_t value) const { return reg_ != value; }
892*f5c631daSSadaf Ebrahimi };
893*f5c631daSSadaf Ebrahimi 
894*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, MaskedSpecialRegister reg) {
895*f5c631daSSadaf Ebrahimi   return os << reg.GetName();
896*f5c631daSSadaf Ebrahimi }
897*f5c631daSSadaf Ebrahimi 
898*f5c631daSSadaf Ebrahimi enum SpecialFPRegisterType {
899*f5c631daSSadaf Ebrahimi   FPSID = 0x0,
900*f5c631daSSadaf Ebrahimi   FPSCR = 0x1,
901*f5c631daSSadaf Ebrahimi   MVFR2 = 0x5,
902*f5c631daSSadaf Ebrahimi   MVFR1 = 0x6,
903*f5c631daSSadaf Ebrahimi   MVFR0 = 0x7,
904*f5c631daSSadaf Ebrahimi   FPEXC = 0x8
905*f5c631daSSadaf Ebrahimi };
906*f5c631daSSadaf Ebrahimi 
907*f5c631daSSadaf Ebrahimi class SpecialFPRegister {
908*f5c631daSSadaf Ebrahimi   uint32_t reg_;
909*f5c631daSSadaf Ebrahimi 
910*f5c631daSSadaf Ebrahimi  public:
SpecialFPRegister(uint32_t reg)911*f5c631daSSadaf Ebrahimi   explicit SpecialFPRegister(uint32_t reg) : reg_(reg) {
912*f5c631daSSadaf Ebrahimi #ifdef VIXL_DEBUG
913*f5c631daSSadaf Ebrahimi     switch (reg) {
914*f5c631daSSadaf Ebrahimi       case FPSID:
915*f5c631daSSadaf Ebrahimi       case FPSCR:
916*f5c631daSSadaf Ebrahimi       case MVFR2:
917*f5c631daSSadaf Ebrahimi       case MVFR1:
918*f5c631daSSadaf Ebrahimi       case MVFR0:
919*f5c631daSSadaf Ebrahimi       case FPEXC:
920*f5c631daSSadaf Ebrahimi         break;
921*f5c631daSSadaf Ebrahimi       default:
922*f5c631daSSadaf Ebrahimi         VIXL_UNREACHABLE();
923*f5c631daSSadaf Ebrahimi     }
924*f5c631daSSadaf Ebrahimi #endif
925*f5c631daSSadaf Ebrahimi   }
SpecialFPRegister(SpecialFPRegisterType reg)926*f5c631daSSadaf Ebrahimi   SpecialFPRegister(SpecialFPRegisterType reg)  // NOLINT(runtime/explicit)
927*f5c631daSSadaf Ebrahimi       : reg_(reg) {}
GetReg()928*f5c631daSSadaf Ebrahimi   uint32_t GetReg() const { return reg_; }
929*f5c631daSSadaf Ebrahimi   const char* GetName() const;
Is(SpecialFPRegister value)930*f5c631daSSadaf Ebrahimi   bool Is(SpecialFPRegister value) const { return reg_ == value.reg_; }
Is(uint32_t value)931*f5c631daSSadaf Ebrahimi   bool Is(uint32_t value) const { return reg_ == value; }
IsNot(uint32_t value)932*f5c631daSSadaf Ebrahimi   bool IsNot(uint32_t value) const { return reg_ != value; }
933*f5c631daSSadaf Ebrahimi };
934*f5c631daSSadaf Ebrahimi 
935*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, SpecialFPRegister reg) {
936*f5c631daSSadaf Ebrahimi   return os << reg.GetName();
937*f5c631daSSadaf Ebrahimi }
938*f5c631daSSadaf Ebrahimi 
939*f5c631daSSadaf Ebrahimi class CRegister {
940*f5c631daSSadaf Ebrahimi   uint32_t code_;
941*f5c631daSSadaf Ebrahimi 
942*f5c631daSSadaf Ebrahimi  public:
CRegister(uint32_t code)943*f5c631daSSadaf Ebrahimi   explicit CRegister(uint32_t code) : code_(code) {
944*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(code < kNumberOfRegisters);
945*f5c631daSSadaf Ebrahimi   }
GetCode()946*f5c631daSSadaf Ebrahimi   uint32_t GetCode() const { return code_; }
Is(CRegister value)947*f5c631daSSadaf Ebrahimi   bool Is(CRegister value) const { return code_ == value.code_; }
948*f5c631daSSadaf Ebrahimi };
949*f5c631daSSadaf Ebrahimi 
950*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, const CRegister reg) {
951*f5c631daSSadaf Ebrahimi   return os << "c" << reg.GetCode();
952*f5c631daSSadaf Ebrahimi }
953*f5c631daSSadaf Ebrahimi 
954*f5c631daSSadaf Ebrahimi // clang-format off
955*f5c631daSSadaf Ebrahimi #define CREGISTER_CODE_LIST(R)                                                 \
956*f5c631daSSadaf Ebrahimi   R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)                               \
957*f5c631daSSadaf Ebrahimi   R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)
958*f5c631daSSadaf Ebrahimi // clang-format on
959*f5c631daSSadaf Ebrahimi #define DEFINE_CREGISTER(N) const CRegister c##N(N);
960*f5c631daSSadaf Ebrahimi CREGISTER_CODE_LIST(DEFINE_CREGISTER)
961*f5c631daSSadaf Ebrahimi 
962*f5c631daSSadaf Ebrahimi enum CoprocessorName { p10 = 10, p11 = 11, p14 = 14, p15 = 15 };
963*f5c631daSSadaf Ebrahimi 
964*f5c631daSSadaf Ebrahimi class Coprocessor {
965*f5c631daSSadaf Ebrahimi   uint32_t coproc_;
966*f5c631daSSadaf Ebrahimi 
967*f5c631daSSadaf Ebrahimi  public:
Coprocessor(uint32_t coproc)968*f5c631daSSadaf Ebrahimi   explicit Coprocessor(uint32_t coproc) : coproc_(coproc) {}
Coprocessor(CoprocessorName coproc)969*f5c631daSSadaf Ebrahimi   Coprocessor(CoprocessorName coproc)  // NOLINT(runtime/explicit)
970*f5c631daSSadaf Ebrahimi       : coproc_(static_cast<uint32_t>(coproc)) {}
Is(Coprocessor coproc)971*f5c631daSSadaf Ebrahimi   bool Is(Coprocessor coproc) const { return coproc_ == coproc.coproc_; }
Is(CoprocessorName coproc)972*f5c631daSSadaf Ebrahimi   bool Is(CoprocessorName coproc) const { return coproc_ == coproc; }
GetCoprocessor()973*f5c631daSSadaf Ebrahimi   uint32_t GetCoprocessor() const { return coproc_; }
974*f5c631daSSadaf Ebrahimi };
975*f5c631daSSadaf Ebrahimi 
976*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, Coprocessor coproc) {
977*f5c631daSSadaf Ebrahimi   return os << "p" << coproc.GetCoprocessor();
978*f5c631daSSadaf Ebrahimi }
979*f5c631daSSadaf Ebrahimi 
980*f5c631daSSadaf Ebrahimi enum ConditionType {
981*f5c631daSSadaf Ebrahimi   eq = 0,
982*f5c631daSSadaf Ebrahimi   ne = 1,
983*f5c631daSSadaf Ebrahimi   cs = 2,
984*f5c631daSSadaf Ebrahimi   cc = 3,
985*f5c631daSSadaf Ebrahimi   mi = 4,
986*f5c631daSSadaf Ebrahimi   pl = 5,
987*f5c631daSSadaf Ebrahimi   vs = 6,
988*f5c631daSSadaf Ebrahimi   vc = 7,
989*f5c631daSSadaf Ebrahimi   hi = 8,
990*f5c631daSSadaf Ebrahimi   ls = 9,
991*f5c631daSSadaf Ebrahimi   ge = 10,
992*f5c631daSSadaf Ebrahimi   lt = 11,
993*f5c631daSSadaf Ebrahimi   gt = 12,
994*f5c631daSSadaf Ebrahimi   le = 13,
995*f5c631daSSadaf Ebrahimi   al = 14,
996*f5c631daSSadaf Ebrahimi   hs = cs,
997*f5c631daSSadaf Ebrahimi   lo = cc
998*f5c631daSSadaf Ebrahimi };
999*f5c631daSSadaf Ebrahimi 
1000*f5c631daSSadaf Ebrahimi class Condition {
1001*f5c631daSSadaf Ebrahimi   uint32_t condition_;
1002*f5c631daSSadaf Ebrahimi   static const uint32_t kNever = 15;
1003*f5c631daSSadaf Ebrahimi   static const uint32_t kMask = 0xf;
1004*f5c631daSSadaf Ebrahimi   static const uint32_t kNone = 0x10 | al;
1005*f5c631daSSadaf Ebrahimi 
1006*f5c631daSSadaf Ebrahimi  public:
None()1007*f5c631daSSadaf Ebrahimi   static const Condition None() { return Condition(kNone); }
Never()1008*f5c631daSSadaf Ebrahimi   static const Condition Never() { return Condition(kNever); }
Condition(uint32_t condition)1009*f5c631daSSadaf Ebrahimi   explicit Condition(uint32_t condition) : condition_(condition) {
1010*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(condition <= kNone);
1011*f5c631daSSadaf Ebrahimi   }
1012*f5c631daSSadaf Ebrahimi   // Users should be able to use "eq", "ne" and so forth to instantiate this
1013*f5c631daSSadaf Ebrahimi   // class.
Condition(ConditionType condition)1014*f5c631daSSadaf Ebrahimi   Condition(ConditionType condition)  // NOLINT(runtime/explicit)
1015*f5c631daSSadaf Ebrahimi       : condition_(condition) {}
GetCondition()1016*f5c631daSSadaf Ebrahimi   uint32_t GetCondition() const { return condition_ & kMask; }
IsNone()1017*f5c631daSSadaf Ebrahimi   bool IsNone() const { return condition_ == kNone; }
1018*f5c631daSSadaf Ebrahimi   const char* GetName() const;
Is(Condition value)1019*f5c631daSSadaf Ebrahimi   bool Is(Condition value) const { return condition_ == value.condition_; }
Is(uint32_t value)1020*f5c631daSSadaf Ebrahimi   bool Is(uint32_t value) const { return condition_ == value; }
IsNot(uint32_t value)1021*f5c631daSSadaf Ebrahimi   bool IsNot(uint32_t value) const { return condition_ != value; }
IsNever()1022*f5c631daSSadaf Ebrahimi   bool IsNever() const { return condition_ == kNever; }
IsNotNever()1023*f5c631daSSadaf Ebrahimi   bool IsNotNever() const { return condition_ != kNever; }
Negate()1024*f5c631daSSadaf Ebrahimi   Condition Negate() const {
1025*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(IsNot(al) && IsNot(kNever));
1026*f5c631daSSadaf Ebrahimi     return Condition(condition_ ^ 1);
1027*f5c631daSSadaf Ebrahimi   }
1028*f5c631daSSadaf Ebrahimi };
1029*f5c631daSSadaf Ebrahimi 
1030*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, Condition condition) {
1031*f5c631daSSadaf Ebrahimi   return os << condition.GetName();
1032*f5c631daSSadaf Ebrahimi }
1033*f5c631daSSadaf Ebrahimi 
1034*f5c631daSSadaf Ebrahimi enum SignType { plus, minus };
1035*f5c631daSSadaf Ebrahimi 
1036*f5c631daSSadaf Ebrahimi class Sign {
1037*f5c631daSSadaf Ebrahimi  public:
Sign()1038*f5c631daSSadaf Ebrahimi   Sign() : sign_(plus) {}
Sign(SignType sign)1039*f5c631daSSadaf Ebrahimi   Sign(SignType sign) : sign_(sign) {}  // NOLINT(runtime/explicit)
GetName()1040*f5c631daSSadaf Ebrahimi   const char* GetName() const { return (IsPlus() ? "" : "-"); }
IsPlus()1041*f5c631daSSadaf Ebrahimi   bool IsPlus() const { return sign_ == plus; }
IsMinus()1042*f5c631daSSadaf Ebrahimi   bool IsMinus() const { return sign_ == minus; }
ApplyTo(uint32_t value)1043*f5c631daSSadaf Ebrahimi   int32_t ApplyTo(uint32_t value) { return IsPlus() ? value : -value; }
1044*f5c631daSSadaf Ebrahimi 
1045*f5c631daSSadaf Ebrahimi  private:
1046*f5c631daSSadaf Ebrahimi   SignType sign_;
1047*f5c631daSSadaf Ebrahimi };
1048*f5c631daSSadaf Ebrahimi 
1049*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, Sign sign) {
1050*f5c631daSSadaf Ebrahimi   return os << sign.GetName();
1051*f5c631daSSadaf Ebrahimi }
1052*f5c631daSSadaf Ebrahimi 
1053*f5c631daSSadaf Ebrahimi enum ShiftType { LSL = 0x0, LSR = 0x1, ASR = 0x2, ROR = 0x3, RRX = 0x4 };
1054*f5c631daSSadaf Ebrahimi 
1055*f5c631daSSadaf Ebrahimi class Shift {
1056*f5c631daSSadaf Ebrahimi  public:
Shift()1057*f5c631daSSadaf Ebrahimi   Shift() : shift_(LSL) {}
Shift(ShiftType shift)1058*f5c631daSSadaf Ebrahimi   Shift(ShiftType shift) : shift_(shift) {}  // NOLINT(runtime/explicit)
Shift(uint32_t shift)1059*f5c631daSSadaf Ebrahimi   explicit Shift(uint32_t shift) : shift_(static_cast<ShiftType>(shift)) {}
GetShift()1060*f5c631daSSadaf Ebrahimi   const Shift& GetShift() const { return *this; }
GetType()1061*f5c631daSSadaf Ebrahimi   ShiftType GetType() const { return shift_; }
GetValue()1062*f5c631daSSadaf Ebrahimi   uint32_t GetValue() const { return shift_; }
1063*f5c631daSSadaf Ebrahimi   const char* GetName() const;
IsLSL()1064*f5c631daSSadaf Ebrahimi   bool IsLSL() const { return shift_ == LSL; }
IsLSR()1065*f5c631daSSadaf Ebrahimi   bool IsLSR() const { return shift_ == LSR; }
IsASR()1066*f5c631daSSadaf Ebrahimi   bool IsASR() const { return shift_ == ASR; }
IsROR()1067*f5c631daSSadaf Ebrahimi   bool IsROR() const { return shift_ == ROR; }
IsRRX()1068*f5c631daSSadaf Ebrahimi   bool IsRRX() const { return shift_ == RRX; }
Is(Shift value)1069*f5c631daSSadaf Ebrahimi   bool Is(Shift value) const { return shift_ == value.shift_; }
IsNot(Shift value)1070*f5c631daSSadaf Ebrahimi   bool IsNot(Shift value) const { return shift_ != value.shift_; }
1071*f5c631daSSadaf Ebrahimi   bool IsValidAmount(uint32_t amount) const;
1072*f5c631daSSadaf Ebrahimi   static const Shift NoShift;
1073*f5c631daSSadaf Ebrahimi 
1074*f5c631daSSadaf Ebrahimi  protected:
SetType(ShiftType s)1075*f5c631daSSadaf Ebrahimi   void SetType(ShiftType s) { shift_ = s; }
1076*f5c631daSSadaf Ebrahimi 
1077*f5c631daSSadaf Ebrahimi  private:
1078*f5c631daSSadaf Ebrahimi   ShiftType shift_;
1079*f5c631daSSadaf Ebrahimi };
1080*f5c631daSSadaf Ebrahimi 
1081*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, Shift shift) {
1082*f5c631daSSadaf Ebrahimi   return os << shift.GetName();
1083*f5c631daSSadaf Ebrahimi }
1084*f5c631daSSadaf Ebrahimi 
1085*f5c631daSSadaf Ebrahimi class ImmediateShiftOperand : public Shift {
1086*f5c631daSSadaf Ebrahimi  public:
1087*f5c631daSSadaf Ebrahimi   // Constructor used for assembly.
ImmediateShiftOperand(Shift shift,uint32_t amount)1088*f5c631daSSadaf Ebrahimi   ImmediateShiftOperand(Shift shift, uint32_t amount)
1089*f5c631daSSadaf Ebrahimi       : Shift(shift), amount_(amount) {
1090*f5c631daSSadaf Ebrahimi #ifdef VIXL_DEBUG
1091*f5c631daSSadaf Ebrahimi     switch (shift.GetType()) {
1092*f5c631daSSadaf Ebrahimi       case LSL:
1093*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(amount <= 31);
1094*f5c631daSSadaf Ebrahimi         break;
1095*f5c631daSSadaf Ebrahimi       case ROR:
1096*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(amount > 0);
1097*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(amount <= 31);
1098*f5c631daSSadaf Ebrahimi         break;
1099*f5c631daSSadaf Ebrahimi       case LSR:
1100*f5c631daSSadaf Ebrahimi       case ASR:
1101*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(amount > 0);
1102*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(amount <= 32);
1103*f5c631daSSadaf Ebrahimi         break;
1104*f5c631daSSadaf Ebrahimi       case RRX:
1105*f5c631daSSadaf Ebrahimi         VIXL_ASSERT(amount == 0);
1106*f5c631daSSadaf Ebrahimi         break;
1107*f5c631daSSadaf Ebrahimi       default:
1108*f5c631daSSadaf Ebrahimi         VIXL_UNREACHABLE();
1109*f5c631daSSadaf Ebrahimi         break;
1110*f5c631daSSadaf Ebrahimi     }
1111*f5c631daSSadaf Ebrahimi #endif
1112*f5c631daSSadaf Ebrahimi   }
1113*f5c631daSSadaf Ebrahimi   // Constructor used for disassembly.
1114*f5c631daSSadaf Ebrahimi   ImmediateShiftOperand(int shift, int amount);
GetAmount()1115*f5c631daSSadaf Ebrahimi   uint32_t GetAmount() const { return amount_; }
Is(const ImmediateShiftOperand & rhs)1116*f5c631daSSadaf Ebrahimi   bool Is(const ImmediateShiftOperand& rhs) const {
1117*f5c631daSSadaf Ebrahimi     return amount_ == (rhs.amount_) && Shift::Is(*this);
1118*f5c631daSSadaf Ebrahimi   }
1119*f5c631daSSadaf Ebrahimi 
1120*f5c631daSSadaf Ebrahimi  private:
1121*f5c631daSSadaf Ebrahimi   uint32_t amount_;
1122*f5c631daSSadaf Ebrahimi };
1123*f5c631daSSadaf Ebrahimi 
1124*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os,
1125*f5c631daSSadaf Ebrahimi                                 ImmediateShiftOperand const& shift_operand) {
1126*f5c631daSSadaf Ebrahimi   if (shift_operand.IsLSL() && shift_operand.GetAmount() == 0) return os;
1127*f5c631daSSadaf Ebrahimi   if (shift_operand.IsRRX()) return os << ", rrx";
1128*f5c631daSSadaf Ebrahimi   return os << ", " << shift_operand.GetName() << " #"
1129*f5c631daSSadaf Ebrahimi             << shift_operand.GetAmount();
1130*f5c631daSSadaf Ebrahimi }
1131*f5c631daSSadaf Ebrahimi 
1132*f5c631daSSadaf Ebrahimi class RegisterShiftOperand : public Shift {
1133*f5c631daSSadaf Ebrahimi  public:
RegisterShiftOperand(ShiftType shift,Register shift_register)1134*f5c631daSSadaf Ebrahimi   RegisterShiftOperand(ShiftType shift, Register shift_register)
1135*f5c631daSSadaf Ebrahimi       : Shift(shift), shift_register_(shift_register) {
1136*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(!IsRRX() && shift_register_.IsValid());
1137*f5c631daSSadaf Ebrahimi   }
GetShiftRegister()1138*f5c631daSSadaf Ebrahimi   const Register GetShiftRegister() const { return shift_register_; }
Is(const RegisterShiftOperand & rhs)1139*f5c631daSSadaf Ebrahimi   bool Is(const RegisterShiftOperand& rhs) const {
1140*f5c631daSSadaf Ebrahimi     return shift_register_.Is(rhs.shift_register_) && Shift::Is(*this);
1141*f5c631daSSadaf Ebrahimi   }
1142*f5c631daSSadaf Ebrahimi 
1143*f5c631daSSadaf Ebrahimi  private:
1144*f5c631daSSadaf Ebrahimi   Register shift_register_;
1145*f5c631daSSadaf Ebrahimi };
1146*f5c631daSSadaf Ebrahimi 
1147*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& s,
1148*f5c631daSSadaf Ebrahimi                                 const RegisterShiftOperand& shift_operand) {
1149*f5c631daSSadaf Ebrahimi   return s << shift_operand.GetName() << " "
1150*f5c631daSSadaf Ebrahimi            << shift_operand.GetShiftRegister();
1151*f5c631daSSadaf Ebrahimi }
1152*f5c631daSSadaf Ebrahimi 
1153*f5c631daSSadaf Ebrahimi enum EncodingSizeType { Best, Narrow, Wide };
1154*f5c631daSSadaf Ebrahimi 
1155*f5c631daSSadaf Ebrahimi class EncodingSize {
1156*f5c631daSSadaf Ebrahimi   uint32_t size_;
1157*f5c631daSSadaf Ebrahimi 
1158*f5c631daSSadaf Ebrahimi  public:
EncodingSize(uint32_t size)1159*f5c631daSSadaf Ebrahimi   explicit EncodingSize(uint32_t size) : size_(size) {}
EncodingSize(EncodingSizeType size)1160*f5c631daSSadaf Ebrahimi   EncodingSize(EncodingSizeType size)  // NOLINT(runtime/explicit)
1161*f5c631daSSadaf Ebrahimi       : size_(size) {}
GetSize()1162*f5c631daSSadaf Ebrahimi   uint32_t GetSize() const { return size_; }
1163*f5c631daSSadaf Ebrahimi   const char* GetName() const;
IsBest()1164*f5c631daSSadaf Ebrahimi   bool IsBest() const { return size_ == Best; }
IsNarrow()1165*f5c631daSSadaf Ebrahimi   bool IsNarrow() const { return size_ == Narrow; }
IsWide()1166*f5c631daSSadaf Ebrahimi   bool IsWide() const { return size_ == Wide; }
1167*f5c631daSSadaf Ebrahimi };
1168*f5c631daSSadaf Ebrahimi 
1169*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, EncodingSize size) {
1170*f5c631daSSadaf Ebrahimi   return os << size.GetName();
1171*f5c631daSSadaf Ebrahimi }
1172*f5c631daSSadaf Ebrahimi 
1173*f5c631daSSadaf Ebrahimi enum WriteBackValue { NO_WRITE_BACK, WRITE_BACK };
1174*f5c631daSSadaf Ebrahimi 
1175*f5c631daSSadaf Ebrahimi class WriteBack {
1176*f5c631daSSadaf Ebrahimi   WriteBackValue value_;
1177*f5c631daSSadaf Ebrahimi 
1178*f5c631daSSadaf Ebrahimi  public:
WriteBack(WriteBackValue value)1179*f5c631daSSadaf Ebrahimi   WriteBack(WriteBackValue value)  // NOLINT(runtime/explicit)
1180*f5c631daSSadaf Ebrahimi       : value_(value) {}
WriteBack(int value)1181*f5c631daSSadaf Ebrahimi   explicit WriteBack(int value)
1182*f5c631daSSadaf Ebrahimi       : value_((value == 0) ? NO_WRITE_BACK : WRITE_BACK) {}
GetWriteBackUint32()1183*f5c631daSSadaf Ebrahimi   uint32_t GetWriteBackUint32() const { return (value_ == WRITE_BACK) ? 1 : 0; }
DoesWriteBack()1184*f5c631daSSadaf Ebrahimi   bool DoesWriteBack() const { return value_ == WRITE_BACK; }
1185*f5c631daSSadaf Ebrahimi };
1186*f5c631daSSadaf Ebrahimi 
1187*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, WriteBack write_back) {
1188*f5c631daSSadaf Ebrahimi   if (write_back.DoesWriteBack()) return os << "!";
1189*f5c631daSSadaf Ebrahimi   return os;
1190*f5c631daSSadaf Ebrahimi }
1191*f5c631daSSadaf Ebrahimi 
1192*f5c631daSSadaf Ebrahimi class EncodingValue {
1193*f5c631daSSadaf Ebrahimi   bool valid_;
1194*f5c631daSSadaf Ebrahimi   uint32_t encoding_value_;
1195*f5c631daSSadaf Ebrahimi 
1196*f5c631daSSadaf Ebrahimi  public:
EncodingValue()1197*f5c631daSSadaf Ebrahimi   EncodingValue() {
1198*f5c631daSSadaf Ebrahimi     valid_ = false;
1199*f5c631daSSadaf Ebrahimi     encoding_value_ = 0;
1200*f5c631daSSadaf Ebrahimi   }
IsValid()1201*f5c631daSSadaf Ebrahimi   bool IsValid() const { return valid_; }
GetEncodingValue()1202*f5c631daSSadaf Ebrahimi   uint32_t GetEncodingValue() const { return encoding_value_; }
SetEncodingValue(uint32_t encoding_value)1203*f5c631daSSadaf Ebrahimi   void SetEncodingValue(uint32_t encoding_value) {
1204*f5c631daSSadaf Ebrahimi     valid_ = true;
1205*f5c631daSSadaf Ebrahimi     encoding_value_ = encoding_value;
1206*f5c631daSSadaf Ebrahimi   }
1207*f5c631daSSadaf Ebrahimi };
1208*f5c631daSSadaf Ebrahimi 
1209*f5c631daSSadaf Ebrahimi class EncodingValueAndImmediate : public EncodingValue {
1210*f5c631daSSadaf Ebrahimi   uint32_t encoded_immediate_;
1211*f5c631daSSadaf Ebrahimi 
1212*f5c631daSSadaf Ebrahimi  public:
EncodingValueAndImmediate()1213*f5c631daSSadaf Ebrahimi   EncodingValueAndImmediate() { encoded_immediate_ = 0; }
GetEncodedImmediate()1214*f5c631daSSadaf Ebrahimi   uint32_t GetEncodedImmediate() const { return encoded_immediate_; }
SetEncodedImmediate(uint32_t encoded_immediate)1215*f5c631daSSadaf Ebrahimi   void SetEncodedImmediate(uint32_t encoded_immediate) {
1216*f5c631daSSadaf Ebrahimi     encoded_immediate_ = encoded_immediate;
1217*f5c631daSSadaf Ebrahimi   }
1218*f5c631daSSadaf Ebrahimi };
1219*f5c631daSSadaf Ebrahimi 
1220*f5c631daSSadaf Ebrahimi class ImmediateT32 : public EncodingValue {
1221*f5c631daSSadaf Ebrahimi  public:
1222*f5c631daSSadaf Ebrahimi   explicit ImmediateT32(uint32_t imm);
1223*f5c631daSSadaf Ebrahimi   static bool IsImmediateT32(uint32_t imm);
1224*f5c631daSSadaf Ebrahimi   static uint32_t Decode(uint32_t value);
1225*f5c631daSSadaf Ebrahimi };
1226*f5c631daSSadaf Ebrahimi 
1227*f5c631daSSadaf Ebrahimi class ImmediateA32 : public EncodingValue {
1228*f5c631daSSadaf Ebrahimi  public:
1229*f5c631daSSadaf Ebrahimi   explicit ImmediateA32(uint32_t imm);
1230*f5c631daSSadaf Ebrahimi   static bool IsImmediateA32(uint32_t imm);
1231*f5c631daSSadaf Ebrahimi   static uint32_t Decode(uint32_t value);
1232*f5c631daSSadaf Ebrahimi };
1233*f5c631daSSadaf Ebrahimi 
1234*f5c631daSSadaf Ebrahimi // Return the encoding value of a shift type.
1235*f5c631daSSadaf Ebrahimi uint32_t TypeEncodingValue(Shift shift);
1236*f5c631daSSadaf Ebrahimi // Return the encoding value for a shift amount depending on the shift type.
1237*f5c631daSSadaf Ebrahimi uint32_t AmountEncodingValue(Shift shift, uint32_t amount);
1238*f5c631daSSadaf Ebrahimi 
1239*f5c631daSSadaf Ebrahimi enum MemoryBarrierType {
1240*f5c631daSSadaf Ebrahimi   OSHLD = 0x1,
1241*f5c631daSSadaf Ebrahimi   OSHST = 0x2,
1242*f5c631daSSadaf Ebrahimi   OSH = 0x3,
1243*f5c631daSSadaf Ebrahimi   NSHLD = 0x5,
1244*f5c631daSSadaf Ebrahimi   NSHST = 0x6,
1245*f5c631daSSadaf Ebrahimi   NSH = 0x7,
1246*f5c631daSSadaf Ebrahimi   ISHLD = 0x9,
1247*f5c631daSSadaf Ebrahimi   ISHST = 0xa,
1248*f5c631daSSadaf Ebrahimi   ISH = 0xb,
1249*f5c631daSSadaf Ebrahimi   LD = 0xd,
1250*f5c631daSSadaf Ebrahimi   ST = 0xe,
1251*f5c631daSSadaf Ebrahimi   SY = 0xf
1252*f5c631daSSadaf Ebrahimi };
1253*f5c631daSSadaf Ebrahimi 
1254*f5c631daSSadaf Ebrahimi class MemoryBarrier {
1255*f5c631daSSadaf Ebrahimi   MemoryBarrierType type_;
1256*f5c631daSSadaf Ebrahimi 
1257*f5c631daSSadaf Ebrahimi  public:
MemoryBarrier(MemoryBarrierType type)1258*f5c631daSSadaf Ebrahimi   MemoryBarrier(MemoryBarrierType type)  // NOLINT(runtime/explicit)
1259*f5c631daSSadaf Ebrahimi       : type_(type) {}
MemoryBarrier(uint32_t type)1260*f5c631daSSadaf Ebrahimi   MemoryBarrier(uint32_t type)  // NOLINT(runtime/explicit)
1261*f5c631daSSadaf Ebrahimi       : type_(static_cast<MemoryBarrierType>(type)) {
1262*f5c631daSSadaf Ebrahimi     VIXL_ASSERT((type & 0x3) != 0);
1263*f5c631daSSadaf Ebrahimi   }
GetType()1264*f5c631daSSadaf Ebrahimi   MemoryBarrierType GetType() const { return type_; }
1265*f5c631daSSadaf Ebrahimi   const char* GetName() const;
1266*f5c631daSSadaf Ebrahimi };
1267*f5c631daSSadaf Ebrahimi 
1268*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, MemoryBarrier option) {
1269*f5c631daSSadaf Ebrahimi   return os << option.GetName();
1270*f5c631daSSadaf Ebrahimi }
1271*f5c631daSSadaf Ebrahimi 
1272*f5c631daSSadaf Ebrahimi enum InterruptFlagsType {
1273*f5c631daSSadaf Ebrahimi   F = 0x1,
1274*f5c631daSSadaf Ebrahimi   I = 0x2,
1275*f5c631daSSadaf Ebrahimi   IF = 0x3,
1276*f5c631daSSadaf Ebrahimi   A = 0x4,
1277*f5c631daSSadaf Ebrahimi   AF = 0x5,
1278*f5c631daSSadaf Ebrahimi   AI = 0x6,
1279*f5c631daSSadaf Ebrahimi   AIF = 0x7
1280*f5c631daSSadaf Ebrahimi };
1281*f5c631daSSadaf Ebrahimi 
1282*f5c631daSSadaf Ebrahimi class InterruptFlags {
1283*f5c631daSSadaf Ebrahimi   InterruptFlagsType type_;
1284*f5c631daSSadaf Ebrahimi 
1285*f5c631daSSadaf Ebrahimi  public:
InterruptFlags(InterruptFlagsType type)1286*f5c631daSSadaf Ebrahimi   InterruptFlags(InterruptFlagsType type)  // NOLINT(runtime/explicit)
1287*f5c631daSSadaf Ebrahimi       : type_(type) {}
InterruptFlags(uint32_t type)1288*f5c631daSSadaf Ebrahimi   InterruptFlags(uint32_t type)  // NOLINT(runtime/explicit)
1289*f5c631daSSadaf Ebrahimi       : type_(static_cast<InterruptFlagsType>(type)) {
1290*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(type <= 7);
1291*f5c631daSSadaf Ebrahimi   }
GetType()1292*f5c631daSSadaf Ebrahimi   InterruptFlagsType GetType() const { return type_; }
1293*f5c631daSSadaf Ebrahimi   const char* GetName() const;
1294*f5c631daSSadaf Ebrahimi };
1295*f5c631daSSadaf Ebrahimi 
1296*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, InterruptFlags option) {
1297*f5c631daSSadaf Ebrahimi   return os << option.GetName();
1298*f5c631daSSadaf Ebrahimi }
1299*f5c631daSSadaf Ebrahimi 
1300*f5c631daSSadaf Ebrahimi enum EndiannessType { LE = 0, BE = 1 };
1301*f5c631daSSadaf Ebrahimi 
1302*f5c631daSSadaf Ebrahimi class Endianness {
1303*f5c631daSSadaf Ebrahimi   EndiannessType type_;
1304*f5c631daSSadaf Ebrahimi 
1305*f5c631daSSadaf Ebrahimi  public:
Endianness(EndiannessType type)1306*f5c631daSSadaf Ebrahimi   Endianness(EndiannessType type) : type_(type) {}  // NOLINT(runtime/explicit)
Endianness(uint32_t type)1307*f5c631daSSadaf Ebrahimi   Endianness(uint32_t type)                         // NOLINT(runtime/explicit)
1308*f5c631daSSadaf Ebrahimi       : type_(static_cast<EndiannessType>(type)) {
1309*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(type <= 1);
1310*f5c631daSSadaf Ebrahimi   }
GetType()1311*f5c631daSSadaf Ebrahimi   EndiannessType GetType() const { return type_; }
1312*f5c631daSSadaf Ebrahimi   const char* GetName() const;
1313*f5c631daSSadaf Ebrahimi };
1314*f5c631daSSadaf Ebrahimi 
1315*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, Endianness endian_specifier) {
1316*f5c631daSSadaf Ebrahimi   return os << endian_specifier.GetName();
1317*f5c631daSSadaf Ebrahimi }
1318*f5c631daSSadaf Ebrahimi 
1319*f5c631daSSadaf Ebrahimi enum AlignmentType {
1320*f5c631daSSadaf Ebrahimi   k16BitAlign = 0,
1321*f5c631daSSadaf Ebrahimi   k32BitAlign = 1,
1322*f5c631daSSadaf Ebrahimi   k64BitAlign = 2,
1323*f5c631daSSadaf Ebrahimi   k128BitAlign = 3,
1324*f5c631daSSadaf Ebrahimi   k256BitAlign = 4,
1325*f5c631daSSadaf Ebrahimi   kNoAlignment = 5,
1326*f5c631daSSadaf Ebrahimi   kBadAlignment = 6
1327*f5c631daSSadaf Ebrahimi };
1328*f5c631daSSadaf Ebrahimi 
1329*f5c631daSSadaf Ebrahimi class Alignment {
1330*f5c631daSSadaf Ebrahimi   AlignmentType align_;
1331*f5c631daSSadaf Ebrahimi 
1332*f5c631daSSadaf Ebrahimi  public:
Alignment(AlignmentType align)1333*f5c631daSSadaf Ebrahimi   Alignment(AlignmentType align)  // NOLINT(runtime/explicit)
1334*f5c631daSSadaf Ebrahimi       : align_(align) {}
Alignment(uint32_t align)1335*f5c631daSSadaf Ebrahimi   Alignment(uint32_t align)  // NOLINT(runtime/explicit)
1336*f5c631daSSadaf Ebrahimi       : align_(static_cast<AlignmentType>(align)) {
1337*f5c631daSSadaf Ebrahimi     VIXL_ASSERT(align <= static_cast<uint32_t>(k256BitAlign));
1338*f5c631daSSadaf Ebrahimi   }
GetType()1339*f5c631daSSadaf Ebrahimi   AlignmentType GetType() const { return align_; }
Is(AlignmentType type)1340*f5c631daSSadaf Ebrahimi   bool Is(AlignmentType type) { return align_ == type; }
1341*f5c631daSSadaf Ebrahimi };
1342*f5c631daSSadaf Ebrahimi 
1343*f5c631daSSadaf Ebrahimi inline std::ostream& operator<<(std::ostream& os, Alignment align) {
1344*f5c631daSSadaf Ebrahimi   if (align.GetType() == kBadAlignment) return os << " :??";
1345*f5c631daSSadaf Ebrahimi   if (align.GetType() == kNoAlignment) return os;
1346*f5c631daSSadaf Ebrahimi   return os << " :" << (0x10 << static_cast<uint32_t>(align.GetType()));
1347*f5c631daSSadaf Ebrahimi }
1348*f5c631daSSadaf Ebrahimi 
1349*f5c631daSSadaf Ebrahimi // Structure containing information on forward references.
1350*f5c631daSSadaf Ebrahimi struct ReferenceInfo {
1351*f5c631daSSadaf Ebrahimi   int size;
1352*f5c631daSSadaf Ebrahimi   int min_offset;
1353*f5c631daSSadaf Ebrahimi   int max_offset;
1354*f5c631daSSadaf Ebrahimi   int alignment;  // As a power of two.
1355*f5c631daSSadaf Ebrahimi   enum { kAlignPc, kDontAlignPc } pc_needs_aligning;
1356*f5c631daSSadaf Ebrahimi };
1357*f5c631daSSadaf Ebrahimi 
1358*f5c631daSSadaf Ebrahimi }  // namespace aarch32
1359*f5c631daSSadaf Ebrahimi }  // namespace vixl
1360*f5c631daSSadaf Ebrahimi 
1361*f5c631daSSadaf Ebrahimi #endif  // VIXL_AARCH32_INSTRUCTIONS_AARCH32_H_
1362