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