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