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(__arm__) && !defined(__SOFTFP__)
42 #define HARDFLOAT __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 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 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 Register() : CPURegister(kNoRegister, 0, kRegSizeInBits) {}
Register(uint32_t code)140 explicit 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 RegisterList() : list_(0) {}
463 RegisterList(Register reg) // NOLINT(runtime/explicit)
464 : list_(RegisterToList(reg)) {}
465 RegisterList(Register reg1, Register reg2)
466 : list_(RegisterToList(reg1) | RegisterToList(reg2)) {}
467 RegisterList(Register reg1, Register reg2, Register reg3)
468 : list_(RegisterToList(reg1) | RegisterToList(reg2) |
469 RegisterToList(reg3)) {}
470 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 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 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_; }
SetList(uint64_t list)566 void SetList(uint64_t list) { list_ = list; }
567 // Because differently-sized V registers overlap with one another, there is no
568 // way to implement a single 'Includes' function in a way that is unsurprising
569 // for all existing uses.
IncludesAllOf(const VRegister & reg)570 bool IncludesAllOf(const VRegister& reg) const {
571 return (list_ & RegisterToList(reg)) == RegisterToList(reg);
572 }
IncludesAliasOf(const VRegister & reg)573 bool IncludesAliasOf(const VRegister& reg) const {
574 return (list_ & RegisterToList(reg)) != 0;
575 }
Combine(const VRegisterList & other)576 void Combine(const VRegisterList& other) { list_ |= other.GetList(); }
Combine(const VRegister & reg)577 void Combine(const VRegister& reg) { list_ |= RegisterToList(reg); }
Remove(const VRegisterList & other)578 void Remove(const VRegisterList& other) { list_ &= ~other.GetList(); }
Remove(const VRegister & reg)579 void Remove(const VRegister& reg) { list_ &= ~RegisterToList(reg); }
Overlaps(const VRegisterList & other)580 bool Overlaps(const VRegisterList& other) const {
581 return (list_ & other.list_) != 0;
582 }
583 QRegister GetFirstAvailableQRegister() const;
584 DRegister GetFirstAvailableDRegister() const;
585 SRegister GetFirstAvailableSRegister() const;
IsEmpty()586 bool IsEmpty() const { return list_ == 0; }
Union(const VRegisterList & list_1,const VRegisterList & list_2)587 static VRegisterList Union(const VRegisterList& list_1,
588 const VRegisterList& list_2) {
589 return VRegisterList(list_1.list_ | list_2.list_);
590 }
Union(const VRegisterList & list_1,const VRegisterList & list_2,const VRegisterList & list_3)591 static VRegisterList Union(const VRegisterList& list_1,
592 const VRegisterList& list_2,
593 const VRegisterList& list_3) {
594 return Union(list_1, Union(list_2, list_3));
595 }
Union(const VRegisterList & list_1,const VRegisterList & list_2,const VRegisterList & list_3,const VRegisterList & list_4)596 static VRegisterList Union(const VRegisterList& list_1,
597 const VRegisterList& list_2,
598 const VRegisterList& list_3,
599 const VRegisterList& list_4) {
600 return Union(Union(list_1, list_2), Union(list_3, list_4));
601 }
Intersection(const VRegisterList & list_1,const VRegisterList & list_2)602 static VRegisterList Intersection(const VRegisterList& list_1,
603 const VRegisterList& list_2) {
604 return VRegisterList(list_1.list_ & list_2.list_);
605 }
Intersection(const VRegisterList & list_1,const VRegisterList & list_2,const VRegisterList & list_3)606 static VRegisterList Intersection(const VRegisterList& list_1,
607 const VRegisterList& list_2,
608 const VRegisterList& list_3) {
609 return Intersection(list_1, Intersection(list_2, list_3));
610 }
Intersection(const VRegisterList & list_1,const VRegisterList & list_2,const VRegisterList & list_3,const VRegisterList & list_4)611 static VRegisterList Intersection(const VRegisterList& list_1,
612 const VRegisterList& list_2,
613 const VRegisterList& list_3,
614 const VRegisterList& list_4) {
615 return Intersection(Intersection(list_1, list_2),
616 Intersection(list_3, list_4));
617 }
618
619 private:
RegisterToList(VRegister reg)620 static uint64_t RegisterToList(VRegister reg) {
621 if (reg.GetType() == CPURegister::kNoRegister) {
622 return 0;
623 } else {
624 switch (reg.GetSizeInBits()) {
625 case kQRegSizeInBits:
626 return UINT64_C(0xf) << (reg.GetCode() * 4);
627 case kDRegSizeInBits:
628 return UINT64_C(0x3) << (reg.GetCode() * 2);
629 case kSRegSizeInBits:
630 return UINT64_C(0x1) << reg.GetCode();
631 default:
632 VIXL_UNREACHABLE();
633 return 0;
634 }
635 }
636 }
637
638 // Bitfield representation of all registers in the list.
639 // (0x3 for d0, 0xc0 for d1, 0x30 for d2, ...). We have one, two or four bits
640 // per register according to their size. This way we can make sure that we
641 // account for overlapping registers.
642 // A register is wholly included in this list only if all of its bits are set.
643 // A register is aliased by the list if at least one of its bits are set.
644 // The IncludesAllOf and IncludesAliasOf helpers are provided to make this
645 // distinction clear.
646 uint64_t list_;
647 };
648
649 class SRegisterList {
650 SRegister first_;
651 int length_;
652
653 public:
SRegisterList(SRegister reg)654 explicit SRegisterList(SRegister reg) : first_(reg.GetCode()), length_(1) {}
SRegisterList(SRegister first,int length)655 SRegisterList(SRegister first, int length)
656 : first_(first.GetCode()), length_(length) {
657 VIXL_ASSERT(length >= 0);
658 }
GetSRegister(int n)659 SRegister GetSRegister(int n) const {
660 VIXL_ASSERT(n >= 0);
661 VIXL_ASSERT(n < length_);
662 return SRegister((first_.GetCode() + n) % kNumberOfSRegisters);
663 }
GetFirstSRegister()664 const SRegister& GetFirstSRegister() const { return first_; }
GetLastSRegister()665 SRegister GetLastSRegister() const { return GetSRegister(length_ - 1); }
GetLength()666 int GetLength() const { return length_; }
667 };
668
669 std::ostream& operator<<(std::ostream& os, SRegisterList registers);
670
671 class DRegisterList {
672 DRegister first_;
673 int length_;
674
675 public:
DRegisterList(DRegister reg)676 explicit DRegisterList(DRegister reg) : first_(reg.GetCode()), length_(1) {}
DRegisterList(DRegister first,int length)677 DRegisterList(DRegister first, int length)
678 : first_(first.GetCode()), length_(length) {
679 VIXL_ASSERT(length >= 0);
680 }
GetDRegister(int n)681 DRegister GetDRegister(int n) const {
682 VIXL_ASSERT(n >= 0);
683 VIXL_ASSERT(n < length_);
684 return DRegister((first_.GetCode() + n) % kMaxNumberOfDRegisters);
685 }
GetFirstDRegister()686 const DRegister& GetFirstDRegister() const { return first_; }
GetLastDRegister()687 DRegister GetLastDRegister() const { return GetDRegister(length_ - 1); }
GetLength()688 int GetLength() const { return length_; }
689 };
690
691 std::ostream& operator<<(std::ostream& os, DRegisterList registers);
692
693 enum SpacingType { kSingle, kDouble };
694
695 enum TransferType { kMultipleLanes, kOneLane, kAllLanes };
696
697 class NeonRegisterList {
698 DRegister first_;
699 SpacingType spacing_;
700 TransferType type_;
701 int lane_;
702 int length_;
703
704 public:
NeonRegisterList(DRegister reg,TransferType type)705 NeonRegisterList(DRegister reg, TransferType type)
706 : first_(reg.GetCode()),
707 spacing_(kSingle),
708 type_(type),
709 lane_(-1),
710 length_(1) {
711 VIXL_ASSERT(type_ != kOneLane);
712 }
NeonRegisterList(DRegister reg,int lane)713 NeonRegisterList(DRegister reg, int lane)
714 : first_(reg.GetCode()),
715 spacing_(kSingle),
716 type_(kOneLane),
717 lane_(lane),
718 length_(1) {
719 VIXL_ASSERT((lane_ >= 0) && (lane_ < 8));
720 }
NeonRegisterList(DRegister first,DRegister last,SpacingType spacing,TransferType type)721 NeonRegisterList(DRegister first,
722 DRegister last,
723 SpacingType spacing,
724 TransferType type)
725 : first_(first.GetCode()), spacing_(spacing), type_(type), lane_(-1) {
726 VIXL_ASSERT(type != kOneLane);
727 VIXL_ASSERT(first.GetCode() <= last.GetCode());
728
729 int range = last.GetCode() - first.GetCode();
730 VIXL_ASSERT(IsSingleSpaced() || IsMultiple(range, 2));
731 length_ = (IsDoubleSpaced() ? (range / 2) : range) + 1;
732
733 VIXL_ASSERT(length_ <= 4);
734 }
NeonRegisterList(DRegister first,DRegister last,SpacingType spacing,int lane)735 NeonRegisterList(DRegister first,
736 DRegister last,
737 SpacingType spacing,
738 int lane)
739 : first_(first.GetCode()),
740 spacing_(spacing),
741 type_(kOneLane),
742 lane_(lane) {
743 VIXL_ASSERT((lane >= 0) && (lane < 8));
744 VIXL_ASSERT(first.GetCode() <= last.GetCode());
745
746 int range = last.GetCode() - first.GetCode();
747 VIXL_ASSERT(IsSingleSpaced() || IsMultiple(range, 2));
748 length_ = (IsDoubleSpaced() ? (range / 2) : range) + 1;
749
750 VIXL_ASSERT(length_ <= 4);
751 }
GetDRegister(int n)752 DRegister GetDRegister(int n) const {
753 VIXL_ASSERT(n >= 0);
754 VIXL_ASSERT(n < length_);
755 unsigned code = first_.GetCode() + (IsDoubleSpaced() ? (2 * n) : n);
756 VIXL_ASSERT(code < kMaxNumberOfDRegisters);
757 return DRegister(code);
758 }
GetFirstDRegister()759 const DRegister& GetFirstDRegister() const { return first_; }
GetLastDRegister()760 DRegister GetLastDRegister() const { return GetDRegister(length_ - 1); }
GetLength()761 int GetLength() const { return length_; }
IsSingleSpaced()762 bool IsSingleSpaced() const { return spacing_ == kSingle; }
IsDoubleSpaced()763 bool IsDoubleSpaced() const { return spacing_ == kDouble; }
IsTransferAllLanes()764 bool IsTransferAllLanes() const { return type_ == kAllLanes; }
IsTransferOneLane()765 bool IsTransferOneLane() const { return type_ == kOneLane; }
IsTransferMultipleLanes()766 bool IsTransferMultipleLanes() const { return type_ == kMultipleLanes; }
GetTransferLane()767 int GetTransferLane() const { return lane_; }
768 };
769
770 std::ostream& operator<<(std::ostream& os, NeonRegisterList registers);
771
772 enum SpecialRegisterType { APSR = 0, CPSR = 0, SPSR = 1 };
773
774 class SpecialRegister {
775 uint32_t reg_;
776
777 public:
SpecialRegister(uint32_t reg)778 explicit SpecialRegister(uint32_t reg) : reg_(reg) {}
SpecialRegister(SpecialRegisterType reg)779 SpecialRegister(SpecialRegisterType reg) // NOLINT(runtime/explicit)
780 : reg_(reg) {}
GetReg()781 uint32_t GetReg() const { return reg_; }
782 const char* GetName() const;
Is(SpecialRegister value)783 bool Is(SpecialRegister value) const { return reg_ == value.reg_; }
Is(uint32_t value)784 bool Is(uint32_t value) const { return reg_ == value; }
IsNot(uint32_t value)785 bool IsNot(uint32_t value) const { return reg_ != value; }
786 };
787
788 inline std::ostream& operator<<(std::ostream& os, SpecialRegister reg) {
789 return os << reg.GetName();
790 }
791
792 enum BankedRegisterType {
793 R8_usr = 0x00,
794 R9_usr = 0x01,
795 R10_usr = 0x02,
796 R11_usr = 0x03,
797 R12_usr = 0x04,
798 SP_usr = 0x05,
799 LR_usr = 0x06,
800 R8_fiq = 0x08,
801 R9_fiq = 0x09,
802 R10_fiq = 0x0a,
803 R11_fiq = 0x0b,
804 R12_fiq = 0x0c,
805 SP_fiq = 0x0d,
806 LR_fiq = 0x0e,
807 LR_irq = 0x10,
808 SP_irq = 0x11,
809 LR_svc = 0x12,
810 SP_svc = 0x13,
811 LR_abt = 0x14,
812 SP_abt = 0x15,
813 LR_und = 0x16,
814 SP_und = 0x17,
815 LR_mon = 0x1c,
816 SP_mon = 0x1d,
817 ELR_hyp = 0x1e,
818 SP_hyp = 0x1f,
819 SPSR_fiq = 0x2e,
820 SPSR_irq = 0x30,
821 SPSR_svc = 0x32,
822 SPSR_abt = 0x34,
823 SPSR_und = 0x36,
824 SPSR_mon = 0x3c,
825 SPSR_hyp = 0x3e
826 };
827
828 class BankedRegister {
829 uint32_t reg_;
830
831 public:
BankedRegister(unsigned reg)832 explicit BankedRegister(unsigned reg) : reg_(reg) {}
BankedRegister(BankedRegisterType reg)833 BankedRegister(BankedRegisterType reg) // NOLINT(runtime/explicit)
834 : reg_(reg) {}
GetCode()835 uint32_t GetCode() const { return reg_; }
836 const char* GetName() const;
837 };
838
839 inline std::ostream& operator<<(std::ostream& os, BankedRegister reg) {
840 return os << reg.GetName();
841 }
842
843 enum MaskedSpecialRegisterType {
844 APSR_nzcvq = 0x08,
845 APSR_g = 0x04,
846 APSR_nzcvqg = 0x0c,
847 CPSR_c = 0x01,
848 CPSR_x = 0x02,
849 CPSR_xc = 0x03,
850 CPSR_s = APSR_g,
851 CPSR_sc = 0x05,
852 CPSR_sx = 0x06,
853 CPSR_sxc = 0x07,
854 CPSR_f = APSR_nzcvq,
855 CPSR_fc = 0x09,
856 CPSR_fx = 0x0a,
857 CPSR_fxc = 0x0b,
858 CPSR_fs = APSR_nzcvqg,
859 CPSR_fsc = 0x0d,
860 CPSR_fsx = 0x0e,
861 CPSR_fsxc = 0x0f,
862 SPSR_c = 0x11,
863 SPSR_x = 0x12,
864 SPSR_xc = 0x13,
865 SPSR_s = 0x14,
866 SPSR_sc = 0x15,
867 SPSR_sx = 0x16,
868 SPSR_sxc = 0x17,
869 SPSR_f = 0x18,
870 SPSR_fc = 0x19,
871 SPSR_fx = 0x1a,
872 SPSR_fxc = 0x1b,
873 SPSR_fs = 0x1c,
874 SPSR_fsc = 0x1d,
875 SPSR_fsx = 0x1e,
876 SPSR_fsxc = 0x1f
877 };
878
879 class MaskedSpecialRegister {
880 uint32_t reg_;
881
882 public:
MaskedSpecialRegister(uint32_t reg)883 explicit MaskedSpecialRegister(uint32_t reg) : reg_(reg) {
884 VIXL_ASSERT(reg <= SPSR_fsxc);
885 }
MaskedSpecialRegister(MaskedSpecialRegisterType reg)886 MaskedSpecialRegister(
887 MaskedSpecialRegisterType reg) // NOLINT(runtime/explicit)
888 : reg_(reg) {}
GetReg()889 uint32_t GetReg() const { return reg_; }
890 const char* GetName() const;
Is(MaskedSpecialRegister value)891 bool Is(MaskedSpecialRegister value) const { return reg_ == value.reg_; }
Is(uint32_t value)892 bool Is(uint32_t value) const { return reg_ == value; }
IsNot(uint32_t value)893 bool IsNot(uint32_t value) const { return reg_ != value; }
894 };
895
896 inline std::ostream& operator<<(std::ostream& os, MaskedSpecialRegister reg) {
897 return os << reg.GetName();
898 }
899
900 enum SpecialFPRegisterType {
901 FPSID = 0x0,
902 FPSCR = 0x1,
903 MVFR2 = 0x5,
904 MVFR1 = 0x6,
905 MVFR0 = 0x7,
906 FPEXC = 0x8
907 };
908
909 class SpecialFPRegister {
910 uint32_t reg_;
911
912 public:
SpecialFPRegister(uint32_t reg)913 explicit SpecialFPRegister(uint32_t reg) : reg_(reg) {
914 #ifdef VIXL_DEBUG
915 switch (reg) {
916 case FPSID:
917 case FPSCR:
918 case MVFR2:
919 case MVFR1:
920 case MVFR0:
921 case FPEXC:
922 break;
923 default:
924 VIXL_UNREACHABLE();
925 }
926 #endif
927 }
SpecialFPRegister(SpecialFPRegisterType reg)928 SpecialFPRegister(SpecialFPRegisterType reg) // NOLINT(runtime/explicit)
929 : reg_(reg) {}
GetReg()930 uint32_t GetReg() const { return reg_; }
931 const char* GetName() const;
Is(SpecialFPRegister value)932 bool Is(SpecialFPRegister value) const { return reg_ == value.reg_; }
Is(uint32_t value)933 bool Is(uint32_t value) const { return reg_ == value; }
IsNot(uint32_t value)934 bool IsNot(uint32_t value) const { return reg_ != value; }
935 };
936
937 inline std::ostream& operator<<(std::ostream& os, SpecialFPRegister reg) {
938 return os << reg.GetName();
939 }
940
941 class CRegister {
942 uint32_t code_;
943
944 public:
CRegister(uint32_t code)945 explicit CRegister(uint32_t code) : code_(code) {
946 VIXL_ASSERT(code < kNumberOfRegisters);
947 }
GetCode()948 uint32_t GetCode() const { return code_; }
Is(CRegister value)949 bool Is(CRegister value) const { return code_ == value.code_; }
950 };
951
952 inline std::ostream& operator<<(std::ostream& os, const CRegister reg) {
953 return os << "c" << reg.GetCode();
954 }
955
956 // clang-format off
957 #define CREGISTER_CODE_LIST(R) \
958 R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
959 R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15)
960 // clang-format on
961 #define DEFINE_CREGISTER(N) const CRegister c##N(N);
962 CREGISTER_CODE_LIST(DEFINE_CREGISTER)
963
964 enum CoprocessorName { p10 = 10, p11 = 11, p14 = 14, p15 = 15 };
965
966 class Coprocessor {
967 uint32_t coproc_;
968
969 public:
Coprocessor(uint32_t coproc)970 explicit Coprocessor(uint32_t coproc) : coproc_(coproc) {}
Coprocessor(CoprocessorName coproc)971 Coprocessor(CoprocessorName coproc) // NOLINT(runtime/explicit)
972 : coproc_(static_cast<uint32_t>(coproc)) {}
Is(Coprocessor coproc)973 bool Is(Coprocessor coproc) const { return coproc_ == coproc.coproc_; }
Is(CoprocessorName coproc)974 bool Is(CoprocessorName coproc) const { return coproc_ == coproc; }
GetCoprocessor()975 uint32_t GetCoprocessor() const { return coproc_; }
976 };
977
978 inline std::ostream& operator<<(std::ostream& os, Coprocessor coproc) {
979 return os << "p" << coproc.GetCoprocessor();
980 }
981
982 enum ConditionType {
983 eq = 0,
984 ne = 1,
985 cs = 2,
986 cc = 3,
987 mi = 4,
988 pl = 5,
989 vs = 6,
990 vc = 7,
991 hi = 8,
992 ls = 9,
993 ge = 10,
994 lt = 11,
995 gt = 12,
996 le = 13,
997 al = 14,
998 hs = cs,
999 lo = cc
1000 };
1001
1002 class Condition {
1003 uint32_t condition_;
1004 static const uint32_t kNever = 15;
1005 static const uint32_t kMask = 0xf;
1006 static const uint32_t kNone = 0x10 | al;
1007
1008 public:
None()1009 static const Condition None() { return Condition(kNone); }
Never()1010 static const Condition Never() { return Condition(kNever); }
Condition(uint32_t condition)1011 explicit Condition(uint32_t condition) : condition_(condition) {
1012 VIXL_ASSERT(condition <= kNone);
1013 }
1014 // Users should be able to use "eq", "ne" and so forth to instantiate this
1015 // class.
Condition(ConditionType condition)1016 Condition(ConditionType condition) // NOLINT(runtime/explicit)
1017 : condition_(condition) {}
GetCondition()1018 uint32_t GetCondition() const { return condition_ & kMask; }
IsNone()1019 bool IsNone() const { return condition_ == kNone; }
1020 const char* GetName() const;
Is(Condition value)1021 bool Is(Condition value) const { return condition_ == value.condition_; }
Is(uint32_t value)1022 bool Is(uint32_t value) const { return condition_ == value; }
IsNot(uint32_t value)1023 bool IsNot(uint32_t value) const { return condition_ != value; }
IsNever()1024 bool IsNever() const { return condition_ == kNever; }
IsNotNever()1025 bool IsNotNever() const { return condition_ != kNever; }
Negate()1026 Condition Negate() const {
1027 VIXL_ASSERT(IsNot(al) && IsNot(kNever));
1028 return Condition(condition_ ^ 1);
1029 }
1030 };
1031
1032 inline std::ostream& operator<<(std::ostream& os, Condition condition) {
1033 return os << condition.GetName();
1034 }
1035
1036 enum SignType { plus, minus };
1037
1038 class Sign {
1039 public:
Sign()1040 Sign() : sign_(plus) {}
Sign(SignType sign)1041 Sign(SignType sign) : sign_(sign) {} // NOLINT(runtime/explicit)
GetName()1042 const char* GetName() const { return (IsPlus() ? "" : "-"); }
IsPlus()1043 bool IsPlus() const { return sign_ == plus; }
IsMinus()1044 bool IsMinus() const { return sign_ == minus; }
ApplyTo(uint32_t value)1045 int32_t ApplyTo(uint32_t value) {
1046 return IsPlus() ? value : UnsignedNegate(value);
1047 }
1048
1049 private:
1050 SignType sign_;
1051 };
1052
1053 inline std::ostream& operator<<(std::ostream& os, Sign sign) {
1054 return os << sign.GetName();
1055 }
1056
1057 enum ShiftType { LSL = 0x0, LSR = 0x1, ASR = 0x2, ROR = 0x3, RRX = 0x4 };
1058
1059 class Shift {
1060 public:
Shift()1061 Shift() : shift_(LSL) {}
Shift(ShiftType shift)1062 Shift(ShiftType shift) : shift_(shift) {} // NOLINT(runtime/explicit)
Shift(uint32_t shift)1063 explicit Shift(uint32_t shift) : shift_(static_cast<ShiftType>(shift)) {}
GetShift()1064 const Shift& GetShift() const { return *this; }
GetType()1065 ShiftType GetType() const { return shift_; }
GetValue()1066 uint32_t GetValue() const { return shift_; }
1067 const char* GetName() const;
IsLSL()1068 bool IsLSL() const { return shift_ == LSL; }
IsLSR()1069 bool IsLSR() const { return shift_ == LSR; }
IsASR()1070 bool IsASR() const { return shift_ == ASR; }
IsROR()1071 bool IsROR() const { return shift_ == ROR; }
IsRRX()1072 bool IsRRX() const { return shift_ == RRX; }
Is(Shift value)1073 bool Is(Shift value) const { return shift_ == value.shift_; }
IsNot(Shift value)1074 bool IsNot(Shift value) const { return shift_ != value.shift_; }
1075 bool IsValidAmount(uint32_t amount) const;
1076 static const Shift NoShift;
1077
1078 protected:
SetType(ShiftType s)1079 void SetType(ShiftType s) { shift_ = s; }
1080
1081 private:
1082 ShiftType shift_;
1083 };
1084
1085 inline std::ostream& operator<<(std::ostream& os, Shift shift) {
1086 return os << shift.GetName();
1087 }
1088
1089 class ImmediateShiftOperand : public Shift {
1090 public:
1091 // Constructor used for assembly.
ImmediateShiftOperand(Shift shift,uint32_t amount)1092 ImmediateShiftOperand(Shift shift, uint32_t amount)
1093 : Shift(shift), amount_(amount) {
1094 #ifdef VIXL_DEBUG
1095 switch (shift.GetType()) {
1096 case LSL:
1097 VIXL_ASSERT(amount <= 31);
1098 break;
1099 case ROR:
1100 VIXL_ASSERT(amount > 0);
1101 VIXL_ASSERT(amount <= 31);
1102 break;
1103 case LSR:
1104 case ASR:
1105 VIXL_ASSERT(amount > 0);
1106 VIXL_ASSERT(amount <= 32);
1107 break;
1108 case RRX:
1109 VIXL_ASSERT(amount == 0);
1110 break;
1111 default:
1112 VIXL_UNREACHABLE();
1113 break;
1114 }
1115 #endif
1116 }
1117 // Constructor used for disassembly.
1118 ImmediateShiftOperand(int shift, int amount);
GetAmount()1119 uint32_t GetAmount() const { return amount_; }
Is(const ImmediateShiftOperand & rhs)1120 bool Is(const ImmediateShiftOperand& rhs) const {
1121 return amount_ == (rhs.amount_) && Shift::Is(*this);
1122 }
1123
1124 private:
1125 uint32_t amount_;
1126 };
1127
1128 inline std::ostream& operator<<(std::ostream& os,
1129 ImmediateShiftOperand const& shift_operand) {
1130 if (shift_operand.IsLSL() && shift_operand.GetAmount() == 0) return os;
1131 if (shift_operand.IsRRX()) return os << ", rrx";
1132 return os << ", " << shift_operand.GetName() << " #"
1133 << shift_operand.GetAmount();
1134 }
1135
1136 class RegisterShiftOperand : public Shift {
1137 public:
RegisterShiftOperand(ShiftType shift,Register shift_register)1138 RegisterShiftOperand(ShiftType shift, Register shift_register)
1139 : Shift(shift), shift_register_(shift_register) {
1140 VIXL_ASSERT(!IsRRX() && shift_register_.IsValid());
1141 }
GetShiftRegister()1142 const Register GetShiftRegister() const { return shift_register_; }
Is(const RegisterShiftOperand & rhs)1143 bool Is(const RegisterShiftOperand& rhs) const {
1144 return shift_register_.Is(rhs.shift_register_) && Shift::Is(*this);
1145 }
1146
1147 private:
1148 Register shift_register_;
1149 };
1150
1151 inline std::ostream& operator<<(std::ostream& s,
1152 const RegisterShiftOperand& shift_operand) {
1153 return s << shift_operand.GetName() << " "
1154 << shift_operand.GetShiftRegister();
1155 }
1156
1157 enum EncodingSizeType { Best, Narrow, Wide };
1158
1159 class EncodingSize {
1160 uint32_t size_;
1161
1162 public:
EncodingSize(uint32_t size)1163 explicit EncodingSize(uint32_t size) : size_(size) {}
EncodingSize(EncodingSizeType size)1164 EncodingSize(EncodingSizeType size) // NOLINT(runtime/explicit)
1165 : size_(size) {}
GetSize()1166 uint32_t GetSize() const { return size_; }
1167 const char* GetName() const;
IsBest()1168 bool IsBest() const { return size_ == Best; }
IsNarrow()1169 bool IsNarrow() const { return size_ == Narrow; }
IsWide()1170 bool IsWide() const { return size_ == Wide; }
1171 };
1172
1173 inline std::ostream& operator<<(std::ostream& os, EncodingSize size) {
1174 return os << size.GetName();
1175 }
1176
1177 enum WriteBackValue { NO_WRITE_BACK, WRITE_BACK };
1178
1179 class WriteBack {
1180 WriteBackValue value_;
1181
1182 public:
WriteBack(WriteBackValue value)1183 WriteBack(WriteBackValue value) // NOLINT(runtime/explicit)
1184 : value_(value) {}
WriteBack(int value)1185 explicit WriteBack(int value)
1186 : value_((value == 0) ? NO_WRITE_BACK : WRITE_BACK) {}
GetWriteBackUint32()1187 uint32_t GetWriteBackUint32() const { return (value_ == WRITE_BACK) ? 1 : 0; }
DoesWriteBack()1188 bool DoesWriteBack() const { return value_ == WRITE_BACK; }
1189 };
1190
1191 inline std::ostream& operator<<(std::ostream& os, WriteBack write_back) {
1192 if (write_back.DoesWriteBack()) return os << "!";
1193 return os;
1194 }
1195
1196 class EncodingValue {
1197 bool valid_;
1198 uint32_t encoding_value_;
1199
1200 public:
EncodingValue()1201 EncodingValue() {
1202 valid_ = false;
1203 encoding_value_ = 0;
1204 }
IsValid()1205 bool IsValid() const { return valid_; }
GetEncodingValue()1206 uint32_t GetEncodingValue() const { return encoding_value_; }
SetEncodingValue(uint32_t encoding_value)1207 void SetEncodingValue(uint32_t encoding_value) {
1208 valid_ = true;
1209 encoding_value_ = encoding_value;
1210 }
1211 };
1212
1213 class EncodingValueAndImmediate : public EncodingValue {
1214 uint32_t encoded_immediate_;
1215
1216 public:
EncodingValueAndImmediate()1217 EncodingValueAndImmediate() { encoded_immediate_ = 0; }
GetEncodedImmediate()1218 uint32_t GetEncodedImmediate() const { return encoded_immediate_; }
SetEncodedImmediate(uint32_t encoded_immediate)1219 void SetEncodedImmediate(uint32_t encoded_immediate) {
1220 encoded_immediate_ = encoded_immediate;
1221 }
1222 };
1223
1224 class ImmediateT32 : public EncodingValue {
1225 public:
1226 explicit ImmediateT32(uint32_t imm);
1227 static bool IsImmediateT32(uint32_t imm);
1228 static uint32_t Decode(uint32_t value);
1229 };
1230
1231 class ImmediateA32 : public EncodingValue {
1232 public:
1233 explicit ImmediateA32(uint32_t imm);
1234 static bool IsImmediateA32(uint32_t imm);
1235 static uint32_t Decode(uint32_t value);
1236 };
1237
1238 // Return the encoding value of a shift type.
1239 uint32_t TypeEncodingValue(Shift shift);
1240 // Return the encoding value for a shift amount depending on the shift type.
1241 uint32_t AmountEncodingValue(Shift shift, uint32_t amount);
1242
1243 enum MemoryBarrierType {
1244 OSHLD = 0x1,
1245 OSHST = 0x2,
1246 OSH = 0x3,
1247 NSHLD = 0x5,
1248 NSHST = 0x6,
1249 NSH = 0x7,
1250 ISHLD = 0x9,
1251 ISHST = 0xa,
1252 ISH = 0xb,
1253 LD = 0xd,
1254 ST = 0xe,
1255 SY = 0xf
1256 };
1257
1258 class MemoryBarrier {
1259 MemoryBarrierType type_;
1260
1261 public:
MemoryBarrier(MemoryBarrierType type)1262 MemoryBarrier(MemoryBarrierType type) // NOLINT(runtime/explicit)
1263 : type_(type) {}
MemoryBarrier(uint32_t type)1264 MemoryBarrier(uint32_t type) // NOLINT(runtime/explicit)
1265 : type_(static_cast<MemoryBarrierType>(type)) {
1266 VIXL_ASSERT((type & 0x3) != 0);
1267 }
GetType()1268 MemoryBarrierType GetType() const { return type_; }
1269 const char* GetName() const;
1270 };
1271
1272 inline std::ostream& operator<<(std::ostream& os, MemoryBarrier option) {
1273 return os << option.GetName();
1274 }
1275
1276 enum InterruptFlagsType {
1277 F = 0x1,
1278 I = 0x2,
1279 IF = 0x3,
1280 A = 0x4,
1281 AF = 0x5,
1282 AI = 0x6,
1283 AIF = 0x7
1284 };
1285
1286 class InterruptFlags {
1287 InterruptFlagsType type_;
1288
1289 public:
InterruptFlags(InterruptFlagsType type)1290 InterruptFlags(InterruptFlagsType type) // NOLINT(runtime/explicit)
1291 : type_(type) {}
InterruptFlags(uint32_t type)1292 InterruptFlags(uint32_t type) // NOLINT(runtime/explicit)
1293 : type_(static_cast<InterruptFlagsType>(type)) {
1294 VIXL_ASSERT(type <= 7);
1295 }
GetType()1296 InterruptFlagsType GetType() const { return type_; }
1297 const char* GetName() const;
1298 };
1299
1300 inline std::ostream& operator<<(std::ostream& os, InterruptFlags option) {
1301 return os << option.GetName();
1302 }
1303
1304 enum EndiannessType { LE = 0, BE = 1 };
1305
1306 class Endianness {
1307 EndiannessType type_;
1308
1309 public:
Endianness(EndiannessType type)1310 Endianness(EndiannessType type) : type_(type) {} // NOLINT(runtime/explicit)
Endianness(uint32_t type)1311 Endianness(uint32_t type) // NOLINT(runtime/explicit)
1312 : type_(static_cast<EndiannessType>(type)) {
1313 VIXL_ASSERT(type <= 1);
1314 }
GetType()1315 EndiannessType GetType() const { return type_; }
1316 const char* GetName() const;
1317 };
1318
1319 inline std::ostream& operator<<(std::ostream& os, Endianness endian_specifier) {
1320 return os << endian_specifier.GetName();
1321 }
1322
1323 enum AlignmentType {
1324 k16BitAlign = 0,
1325 k32BitAlign = 1,
1326 k64BitAlign = 2,
1327 k128BitAlign = 3,
1328 k256BitAlign = 4,
1329 kNoAlignment = 5,
1330 kBadAlignment = 6
1331 };
1332
1333 class Alignment {
1334 AlignmentType align_;
1335
1336 public:
Alignment(AlignmentType align)1337 Alignment(AlignmentType align) // NOLINT(runtime/explicit)
1338 : align_(align) {}
Alignment(uint32_t align)1339 Alignment(uint32_t align) // NOLINT(runtime/explicit)
1340 : align_(static_cast<AlignmentType>(align)) {
1341 VIXL_ASSERT(align <= static_cast<uint32_t>(k256BitAlign));
1342 }
GetType()1343 AlignmentType GetType() const { return align_; }
Is(AlignmentType type)1344 bool Is(AlignmentType type) { return align_ == type; }
1345 };
1346
1347 inline std::ostream& operator<<(std::ostream& os, Alignment align) {
1348 if (align.GetType() == kBadAlignment) return os << " :??";
1349 if (align.GetType() == kNoAlignment) return os;
1350 return os << " :" << (0x10 << static_cast<uint32_t>(align.GetType()));
1351 }
1352
1353 // Structure containing information on forward references.
1354 struct ReferenceInfo {
1355 int size;
1356 int min_offset;
1357 int max_offset;
1358 int alignment; // As a power of two.
1359 enum { kAlignPc, kDontAlignPc } pc_needs_aligning;
1360 };
1361
1362 } // namespace aarch32
1363 } // namespace vixl
1364
1365 #endif // VIXL_AARCH32_INSTRUCTIONS_AARCH32_H_
1366