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