Registers-vixl.h (35996B)
1 // Copyright 2019, 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_A64_REGISTERS_A64_H_ 28 #define VIXL_A64_REGISTERS_A64_H_ 29 30 #include "jit/arm64/Architecture-arm64.h" 31 #include "jit/arm64/vixl/Instructions-vixl.h" 32 #include "jit/Registers.h" 33 34 namespace vixl { 35 36 // An integer type capable of representing a homogeneous, non-overlapping set of 37 // registers as a bitmask of their codes. 38 typedef uint64_t RegList; 39 static const int kRegListSizeInBits = sizeof(RegList) * 8; 40 41 class Register; 42 class WRegister; 43 class XRegister; 44 45 class VRegister; 46 class BRegister; 47 class HRegister; 48 class SRegister; 49 class DRegister; 50 class QRegister; 51 52 class ZRegister; 53 54 class PRegister; 55 class PRegisterWithLaneSize; 56 class PRegisterM; 57 class PRegisterZ; 58 59 // A container for any single register supported by the processor. Selected 60 // qualifications are also supported. Basic registers can be constructed 61 // directly as CPURegister objects. Other variants should be constructed as one 62 // of the derived classes. 63 // 64 // CPURegister aims to support any getter that would also be available to more 65 // specialised register types. However, using the equivalent functions on the 66 // specialised register types can avoid run-time checks, and should therefore be 67 // preferred where run-time polymorphism isn't required. 68 // 69 // Type-specific modifiers are typically implemented only on the derived 70 // classes. 71 // 72 // The encoding is such that CPURegister objects are cheap to pass by value. 73 class CPURegister { 74 public: 75 enum RegisterBank : uint8_t { 76 kNoRegisterBank = 0, 77 kRRegisterBank, 78 kVRegisterBank, 79 kPRegisterBank 80 }; 81 enum RegisterType { 82 kNoRegister, 83 kRegister, 84 kVRegister, 85 kZRegister, 86 kPRegister 87 }; 88 89 static const unsigned kUnknownSize = 0; 90 91 VIXL_CONSTEXPR CPURegister() 92 : code_(0), 93 bank_(kNoRegisterBank), 94 size_(kEncodedUnknownSize), 95 qualifiers_(kNoQualifiers), 96 lane_size_(kEncodedUnknownSize) {} 97 98 constexpr CPURegister(int code, int size_in_bits, RegisterType type) 99 : code_(code), 100 bank_(GetBankFor(type)), 101 size_(EncodeSizeInBits(size_in_bits)), 102 qualifiers_(kNoQualifiers), 103 lane_size_(EncodeSizeInBits(size_in_bits)) { 104 VIXL_ASSERT(IsValid()); 105 } 106 107 // Basic accessors. 108 109 // TODO: Make this return 'int'. 110 unsigned GetCode() const { return code_; } 111 unsigned code() const { return GetCode(); } 112 113 RegisterBank GetBank() const { return bank_; } 114 115 // For scalar registers, the lane size matches the register size, and is 116 // always known. 117 constexpr bool HasSize() const { return size_ != kEncodedUnknownSize; } 118 constexpr bool HasLaneSize() const { return lane_size_ != kEncodedUnknownSize; } 119 120 RegList GetBit() const { 121 if (IsNone()) return 0; 122 VIXL_ASSERT(code_ < kRegListSizeInBits); 123 return static_cast<RegList>(1) << code_; 124 } 125 RegList Bit() const { return GetBit(); } 126 127 // Return the highest valid register code for this type, to allow generic 128 // loops to be written. This excludes kSPRegInternalCode, since it is not 129 // contiguous, and sp usually requires special handling anyway. 130 unsigned GetMaxCode() const { return GetMaxCodeFor(GetBank()); } 131 132 // Registers without a known size report kUnknownSize. 133 int GetSizeInBits() const { return DecodeSizeInBits(size_); } 134 unsigned size() const { return GetSizeInBits(); } 135 int SizeInBits() const { return GetSizeInBits(); } 136 int GetSizeInBytes() const { return DecodeSizeInBytes(size_); } 137 int SizeInBytes() const { return GetSizeInBytes(); } 138 // TODO: Make these return 'int'. 139 unsigned GetLaneSizeInBits() const { return DecodeSizeInBits(lane_size_); } 140 unsigned LaneSizeInBits() const { return GetLaneSizeInBits(); } 141 unsigned GetLaneSizeInBytes() const { return DecodeSizeInBytes(lane_size_); } 142 unsigned LaneSizeInBytes() const { return GetLaneSizeInBytes(); } 143 unsigned GetLaneSizeInBytesLog2() const { 144 VIXL_ASSERT(HasLaneSize()); 145 return DecodeSizeInBytesLog2(lane_size_); 146 } 147 unsigned LaneSizeInBytesLog2() const { return GetLaneSizeInBytesLog2(); } 148 149 int GetLanes() const { 150 if (HasSize() && HasLaneSize()) { 151 // Take advantage of the size encoding to calculate this efficiently. 152 VIXL_STATIC_ASSERT(kEncodedHRegSize == (kEncodedBRegSize + 1)); 153 VIXL_STATIC_ASSERT(kEncodedSRegSize == (kEncodedHRegSize + 1)); 154 VIXL_STATIC_ASSERT(kEncodedDRegSize == (kEncodedSRegSize + 1)); 155 VIXL_STATIC_ASSERT(kEncodedQRegSize == (kEncodedDRegSize + 1)); 156 int log2_delta = static_cast<int>(size_) - static_cast<int>(lane_size_); 157 VIXL_ASSERT(log2_delta >= 0); 158 return 1 << log2_delta; 159 } 160 return kUnknownSize; 161 } 162 int lanes() const { return GetLanes(); } 163 164 bool Is8Bits() const { return size_ == kEncodedBRegSize; } 165 bool Is16Bits() const { return size_ == kEncodedHRegSize; } 166 bool Is32Bits() const { return size_ == kEncodedSRegSize; } 167 bool Is64Bits() const { return size_ == kEncodedDRegSize; } 168 bool Is128Bits() const { return size_ == kEncodedQRegSize; } 169 170 bool IsLaneSizeB() const { return lane_size_ == kEncodedBRegSize; } 171 bool IsLaneSizeH() const { return lane_size_ == kEncodedHRegSize; } 172 bool IsLaneSizeS() const { return lane_size_ == kEncodedSRegSize; } 173 bool IsLaneSizeD() const { return lane_size_ == kEncodedDRegSize; } 174 bool IsLaneSizeQ() const { return lane_size_ == kEncodedQRegSize; } 175 176 // If Is<Foo>Register(), then it is valid to convert the CPURegister to some 177 // <Foo>Register<Bar> type. 178 // 179 // If... ... then it is safe to construct ... 180 // r.IsRegister() -> Register(r) 181 // r.IsVRegister() -> VRegister(r) 182 // r.IsZRegister() -> ZRegister(r) 183 // r.IsPRegister() -> PRegister(r) 184 // 185 // r.IsPRegister() && HasLaneSize() -> PRegisterWithLaneSize(r) 186 // r.IsPRegister() && IsMerging() -> PRegisterM(r) 187 // r.IsPRegister() && IsZeroing() -> PRegisterZ(r) 188 bool IsRegister() const { return GetType() == kRegister; } 189 bool IsVRegister() const { return GetType() == kVRegister; } 190 bool IsZRegister() const { return GetType() == kZRegister; } 191 bool IsPRegister() const { return GetType() == kPRegister; } 192 193 bool IsNone() const { return GetType() == kNoRegister; } 194 195 // `GetType() == kNoRegister` implies IsNone(), and vice-versa. 196 // `GetType() == k<Foo>Register` implies Is<Foo>Register(), and vice-versa. 197 RegisterType GetType() const { 198 switch (bank_) { 199 case kNoRegisterBank: 200 return kNoRegister; 201 case kRRegisterBank: 202 return kRegister; 203 case kVRegisterBank: 204 return HasSize() ? kVRegister : kZRegister; 205 case kPRegisterBank: 206 return kPRegister; 207 } 208 VIXL_UNREACHABLE(); 209 return kNoRegister; 210 } 211 212 // IsFPRegister() is true for scalar FP types (and therefore implies 213 // IsVRegister()). There is no corresponding FPRegister type. 214 bool IsFPRegister() const { return Is1H() || Is1S() || Is1D(); } 215 216 // TODO: These are stricter forms of the helpers above. We should make the 217 // basic helpers strict, and remove these. 218 constexpr bool IsValidRegister() const { 219 return ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode)) && 220 (bank_ == kRRegisterBank) && 221 ((size_ == kEncodedWRegSize) || (size_ == kEncodedXRegSize)) && 222 (qualifiers_ == kNoQualifiers) && (lane_size_ == size_); 223 } 224 constexpr bool IsValidVRegister() const { 225 VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize); 226 return (code_ < kNumberOfVRegisters) && (bank_ == kVRegisterBank) && 227 ((size_ >= kEncodedBRegSize) && (size_ <= kEncodedQRegSize)) && 228 (qualifiers_ == kNoQualifiers) && 229 (lane_size_ != kEncodedUnknownSize) && (lane_size_ <= size_); 230 } 231 constexpr bool IsValidFPRegister() const { 232 return IsValidVRegister() && IsFPRegister(); 233 } 234 constexpr bool IsValidZRegister() const { 235 VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize); 236 // Z registers are valid with or without a lane size, so we don't need to 237 // check lane_size_. 238 return (code_ < kNumberOfZRegisters) && (bank_ == kVRegisterBank) && 239 (size_ == kEncodedUnknownSize) && (qualifiers_ == kNoQualifiers); 240 } 241 constexpr bool IsValidPRegister() const { 242 VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize); 243 // P registers are valid with or without a lane size, so we don't need to 244 // check lane_size_. 245 return (code_ < kNumberOfPRegisters) && (bank_ == kPRegisterBank) && 246 (size_ == kEncodedUnknownSize) && 247 ((qualifiers_ == kNoQualifiers) || (qualifiers_ == kMerging) || 248 (qualifiers_ == kZeroing)); 249 } 250 251 constexpr bool IsValid() const { 252 return IsValidRegister() || IsValidVRegister() || IsValidZRegister() || 253 IsValidPRegister(); 254 } 255 bool IsValidOrNone() const { return IsNone() || IsValid(); } 256 257 bool IsVector() const { return HasLaneSize() && (size_ != lane_size_); } 258 bool IsScalar() const { return HasLaneSize() && (size_ == lane_size_); } 259 260 bool IsSameType(const CPURegister& other) const { 261 return GetType() == other.GetType(); 262 } 263 264 bool IsSameBank(const CPURegister& other) const { 265 return GetBank() == other.GetBank(); 266 } 267 268 // Two registers with unknown size are considered to have the same size if 269 // they also have the same type. For example, all Z registers have the same 270 // size, even though we don't know what that is. 271 bool IsSameSizeAndType(const CPURegister& other) const { 272 return IsSameType(other) && (size_ == other.size_); 273 } 274 275 bool IsSameFormat(const CPURegister& other) const { 276 return IsSameSizeAndType(other) && (lane_size_ == other.lane_size_); 277 } 278 279 // Note that NoReg aliases itself, so that 'Is' implies 'Aliases'. 280 bool Aliases(const CPURegister& other) const { 281 return IsSameBank(other) && (code_ == other.code_); 282 } 283 284 bool Is(const CPURegister& other) const { 285 if (IsRegister() || IsVRegister()) { 286 // For core (W, X) and FP/NEON registers, we only consider the code, size 287 // and type. This is legacy behaviour. 288 // TODO: We should probably check every field for all registers. 289 return Aliases(other) && (size_ == other.size_); 290 } else { 291 // For Z and P registers, we require all fields to match exactly. 292 VIXL_ASSERT(IsNone() || IsZRegister() || IsPRegister()); 293 return (code_ == other.code_) && (bank_ == other.bank_) && 294 (size_ == other.size_) && (qualifiers_ == other.qualifiers_) && 295 (lane_size_ == other.lane_size_); 296 } 297 } 298 299 // Conversions to specific register types. The result is a register that 300 // aliases the original CPURegister. That is, the original register bank 301 // (`GetBank()`) is checked and the code (`GetCode()`) preserved, but all 302 // other properties are ignored. 303 // 304 // Typical usage: 305 // 306 // if (reg.GetBank() == kVRegisterBank) { 307 // DRegister d = reg.D(); 308 // ... 309 // } 310 // 311 // These could all return types with compile-time guarantees (like XRegister), 312 // but this breaks backwards-compatibility quite severely, particularly with 313 // code like `cond ? reg.W() : reg.X()`, which would have indeterminate type. 314 315 // Core registers, like "w0". 316 Register W() const; 317 Register X() const; 318 // FP/NEON registers, like "b0". 319 VRegister B() const; 320 VRegister H() const; 321 VRegister S() const; 322 VRegister D() const; 323 VRegister Q() const; 324 VRegister V() const; 325 // SVE registers, like "z0". 326 ZRegister Z() const; 327 PRegister P() const; 328 329 // Utilities for kRegister types. 330 331 bool IsZero() const { return IsRegister() && (code_ == kZeroRegCode); } 332 bool IsSP() const { return IsRegister() && (code_ == kSPRegInternalCode); } 333 bool IsW() const { return IsRegister() && Is32Bits(); } 334 bool IsX() const { return IsRegister() && Is64Bits(); } 335 336 // Utilities for FP/NEON kVRegister types. 337 338 // These helpers ensure that the size and type of the register are as 339 // described. They do not consider the number of lanes that make up a vector. 340 // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD() 341 // does not imply Is1D() or Is8B(). 342 // Check the number of lanes, ie. the format of the vector, using methods such 343 // as Is8B(), Is1D(), etc. 344 bool IsB() const { return IsVRegister() && Is8Bits(); } 345 bool IsH() const { return IsVRegister() && Is16Bits(); } 346 bool IsS() const { return IsVRegister() && Is32Bits(); } 347 bool IsD() const { return IsVRegister() && Is64Bits(); } 348 bool IsQ() const { return IsVRegister() && Is128Bits(); } 349 350 // As above, but also check that the register has exactly one lane. For 351 // example, reg.Is1D() implies DRegister(reg).IsValid(), but reg.IsD() does 352 // not. 353 bool Is1B() const { return IsB() && IsScalar(); } 354 bool Is1H() const { return IsH() && IsScalar(); } 355 bool Is1S() const { return IsS() && IsScalar(); } 356 bool Is1D() const { return IsD() && IsScalar(); } 357 bool Is1Q() const { return IsQ() && IsScalar(); } 358 359 // Check the specific NEON format. 360 bool Is8B() const { return IsD() && IsLaneSizeB(); } 361 bool Is16B() const { return IsQ() && IsLaneSizeB(); } 362 bool Is2H() const { return IsS() && IsLaneSizeH(); } 363 bool Is4H() const { return IsD() && IsLaneSizeH(); } 364 bool Is8H() const { return IsQ() && IsLaneSizeH(); } 365 bool Is2S() const { return IsD() && IsLaneSizeS(); } 366 bool Is4S() const { return IsQ() && IsLaneSizeS(); } 367 bool Is2D() const { return IsQ() && IsLaneSizeD(); } 368 369 // A semantic alias for sdot and udot (indexed and by element) instructions. 370 // The current CPURegister implementation cannot not tell this from Is1S(), 371 // but it might do later. 372 // TODO: Do this with the qualifiers_ field. 373 bool Is1S4B() const { return Is1S(); } 374 375 // Utilities for SVE registers. 376 377 constexpr bool IsUnqualified() const { return qualifiers_ == kNoQualifiers; } 378 constexpr bool IsMerging() const { return IsPRegister() && (qualifiers_ == kMerging); } 379 constexpr bool IsZeroing() const { return IsPRegister() && (qualifiers_ == kZeroing); } 380 381 // SVE types have unknown sizes, but within known bounds. 382 383 int GetMaxSizeInBytes() const { 384 switch (GetType()) { 385 case kZRegister: 386 return kZRegMaxSizeInBytes; 387 case kPRegister: 388 return kPRegMaxSizeInBytes; 389 default: 390 VIXL_ASSERT(HasSize()); 391 return GetSizeInBits(); 392 } 393 } 394 395 int GetMinSizeInBytes() const { 396 switch (GetType()) { 397 case kZRegister: 398 return kZRegMinSizeInBytes; 399 case kPRegister: 400 return kPRegMinSizeInBytes; 401 default: 402 VIXL_ASSERT(HasSize()); 403 return GetSizeInBits(); 404 } 405 } 406 407 int GetMaxSizeInBits() const { return GetMaxSizeInBytes() * kBitsPerByte; } 408 int GetMinSizeInBits() const { return GetMinSizeInBytes() * kBitsPerByte; } 409 410 static constexpr RegisterBank GetBankFor(RegisterType type) { 411 switch (type) { 412 case kNoRegister: 413 return kNoRegisterBank; 414 case kRegister: 415 return kRRegisterBank; 416 case kVRegister: 417 case kZRegister: 418 return kVRegisterBank; 419 case kPRegister: 420 return kPRegisterBank; 421 } 422 VIXL_UNREACHABLE(); 423 return kNoRegisterBank; 424 } 425 426 static unsigned GetMaxCodeFor(CPURegister::RegisterType type) { 427 return GetMaxCodeFor(GetBankFor(type)); 428 } 429 430 protected: 431 enum EncodedSize : uint8_t { 432 // Ensure that kUnknownSize (and therefore kNoRegister) is encoded as zero. 433 kEncodedUnknownSize = 0, 434 435 // The implementation assumes that the remaining sizes are encoded as 436 // `log2(size) + c`, so the following names must remain in sequence. 437 kEncodedBRegSize, 438 kEncodedHRegSize, 439 kEncodedSRegSize, 440 kEncodedDRegSize, 441 kEncodedQRegSize, 442 443 kEncodedWRegSize = kEncodedSRegSize, 444 kEncodedXRegSize = kEncodedDRegSize 445 }; 446 VIXL_STATIC_ASSERT(kSRegSize == kWRegSize); 447 VIXL_STATIC_ASSERT(kDRegSize == kXRegSize); 448 449 char GetLaneSizeSymbol() const { 450 switch (lane_size_) { 451 case kEncodedBRegSize: 452 return 'B'; 453 case kEncodedHRegSize: 454 return 'H'; 455 case kEncodedSRegSize: 456 return 'S'; 457 case kEncodedDRegSize: 458 return 'D'; 459 case kEncodedQRegSize: 460 return 'Q'; 461 case kEncodedUnknownSize: 462 break; 463 } 464 VIXL_UNREACHABLE(); 465 return '?'; 466 } 467 468 static constexpr EncodedSize EncodeSizeInBits(int size_in_bits) { 469 switch (size_in_bits) { 470 case kUnknownSize: 471 return kEncodedUnknownSize; 472 case kBRegSize: 473 return kEncodedBRegSize; 474 case kHRegSize: 475 return kEncodedHRegSize; 476 case kSRegSize: 477 return kEncodedSRegSize; 478 case kDRegSize: 479 return kEncodedDRegSize; 480 case kQRegSize: 481 return kEncodedQRegSize; 482 } 483 VIXL_UNREACHABLE(); 484 return kEncodedUnknownSize; 485 } 486 487 static int DecodeSizeInBytesLog2(EncodedSize encoded_size) { 488 switch (encoded_size) { 489 case kEncodedUnknownSize: 490 // Log2 of B-sized lane in bytes is 0, so we can't just return 0 here. 491 VIXL_UNREACHABLE(); 492 return -1; 493 case kEncodedBRegSize: 494 return kBRegSizeInBytesLog2; 495 case kEncodedHRegSize: 496 return kHRegSizeInBytesLog2; 497 case kEncodedSRegSize: 498 return kSRegSizeInBytesLog2; 499 case kEncodedDRegSize: 500 return kDRegSizeInBytesLog2; 501 case kEncodedQRegSize: 502 return kQRegSizeInBytesLog2; 503 } 504 VIXL_UNREACHABLE(); 505 return kUnknownSize; 506 } 507 508 static int DecodeSizeInBytes(EncodedSize encoded_size) { 509 if (encoded_size == kEncodedUnknownSize) { 510 return kUnknownSize; 511 } 512 return 1 << DecodeSizeInBytesLog2(encoded_size); 513 } 514 515 static int DecodeSizeInBits(EncodedSize encoded_size) { 516 VIXL_STATIC_ASSERT(kUnknownSize == 0); 517 return DecodeSizeInBytes(encoded_size) * kBitsPerByte; 518 } 519 520 static unsigned GetMaxCodeFor(CPURegister::RegisterBank bank); 521 522 enum Qualifiers : uint8_t { 523 kNoQualifiers = 0, 524 // Used by P registers. 525 kMerging, 526 kZeroing 527 }; 528 529 // An unchecked constructor, for use by derived classes. 530 constexpr CPURegister(int code, 531 EncodedSize size, 532 RegisterBank bank, 533 EncodedSize lane_size, 534 Qualifiers qualifiers = kNoQualifiers) 535 : code_(code), 536 bank_(bank), 537 size_(size), 538 qualifiers_(qualifiers), 539 lane_size_(lane_size) {} 540 541 // TODO: Check that access to these fields is reasonably efficient. 542 uint8_t code_; 543 RegisterBank bank_; 544 EncodedSize size_; 545 Qualifiers qualifiers_; 546 EncodedSize lane_size_; 547 }; 548 // Ensure that CPURegisters can fit in a single (64-bit) register. This is a 549 // proxy for being "cheap to pass by value", which is hard to check directly. 550 VIXL_STATIC_ASSERT(sizeof(CPURegister) <= sizeof(uint64_t)); 551 552 // TODO: Add constexpr constructors. 553 #define VIXL_DECLARE_REGISTER_COMMON(NAME, REGISTER_TYPE, PARENT_TYPE) \ 554 VIXL_CONSTEXPR NAME() : PARENT_TYPE() {} \ 555 \ 556 explicit constexpr NAME(CPURegister other) : PARENT_TYPE(other) { \ 557 VIXL_ASSERT(IsValid()); \ 558 } \ 559 \ 560 VIXL_CONSTEXPR static unsigned GetMaxCode() { \ 561 return kNumberOf##REGISTER_TYPE##s - 1; \ 562 } 563 564 // Any W or X register, including the zero register and the stack pointer. 565 class Register : public CPURegister { 566 public: 567 VIXL_DECLARE_REGISTER_COMMON(Register, Register, CPURegister) 568 569 constexpr Register(int code, int size_in_bits) 570 : CPURegister(code, size_in_bits, kRegister) { 571 VIXL_ASSERT(IsValidRegister()); 572 } 573 574 constexpr Register(js::jit::Register r, unsigned size_in_bits) 575 : CPURegister(r.code(), size_in_bits, kRegister) { 576 VIXL_ASSERT(IsValidRegister()); 577 } 578 579 constexpr bool IsValid() const { return IsValidRegister(); } 580 581 js::jit::Register asUnsized() const { 582 // asUnsized() is only ever used on temp registers or on registers that 583 // are known not to be SP, and there should be no risk of it being 584 // applied to SP. Check anyway. 585 VIXL_ASSERT(code_ != kSPRegInternalCode); 586 return js::jit::Register::FromCode((js::jit::Register::Code)code_); 587 } 588 }; 589 590 // Any FP or NEON V register, including vector (V.<T>) and scalar forms 591 // (B, H, S, D, Q). 592 class VRegister : public CPURegister { 593 public: 594 VIXL_DECLARE_REGISTER_COMMON(VRegister, VRegister, CPURegister) 595 596 // For historical reasons, VRegister(0) returns v0.1Q (or equivalently, q0). 597 explicit constexpr VRegister(int code, int size_in_bits = kQRegSize, int lanes = 1) 598 : CPURegister(code, 599 EncodeSizeInBits(size_in_bits), 600 kVRegisterBank, 601 EncodeLaneSizeInBits(size_in_bits, lanes)) { 602 VIXL_ASSERT(IsValidVRegister()); 603 } 604 605 VRegister(int code, VectorFormat format) 606 : CPURegister(code, 607 EncodeSizeInBits(RegisterSizeInBitsFromFormat(format)), 608 kVRegisterBank, 609 EncodeSizeInBits(LaneSizeInBitsFromFormat(format)), 610 kNoQualifiers) { 611 VIXL_ASSERT(IsValid()); 612 } 613 614 constexpr VRegister(js::jit::FloatRegister r) 615 : CPURegister(r.encoding(), r.size() * 8, kVRegister) { 616 VIXL_ASSERT(IsValid()); 617 } 618 constexpr VRegister(js::jit::FloatRegister r, unsigned size_in_bits) 619 : CPURegister(r.encoding(), size_in_bits, kVRegister) { 620 VIXL_ASSERT(IsValid()); 621 } 622 623 VRegister V8B() const; 624 VRegister V16B() const; 625 VRegister V2H() const; 626 VRegister V4H() const; 627 VRegister V8H() const; 628 VRegister V2S() const; 629 VRegister V4S() const; 630 VRegister V1D() const; 631 VRegister V2D() const; 632 VRegister V1Q() const; 633 VRegister S4B() const; 634 635 constexpr bool IsValid() const { return IsValidVRegister(); } 636 637 protected: 638 static constexpr EncodedSize EncodeLaneSizeInBits(int size_in_bits, int lanes) { 639 VIXL_ASSERT(lanes >= 1); 640 VIXL_ASSERT((size_in_bits % lanes) == 0); 641 return EncodeSizeInBits(size_in_bits / lanes); 642 } 643 }; 644 645 // Backward compatibility for FPRegisters. 646 typedef VRegister FPRegister; 647 648 // Any SVE Z register, with or without a lane size specifier. 649 class ZRegister : public CPURegister { 650 public: 651 VIXL_DECLARE_REGISTER_COMMON(ZRegister, ZRegister, CPURegister) 652 653 explicit constexpr ZRegister(int code, int lane_size_in_bits = kUnknownSize) 654 : CPURegister(code, 655 kEncodedUnknownSize, 656 kVRegisterBank, 657 EncodeSizeInBits(lane_size_in_bits)) { 658 VIXL_ASSERT(IsValid()); 659 } 660 661 ZRegister(int code, VectorFormat format) 662 : CPURegister(code, 663 kEncodedUnknownSize, 664 kVRegisterBank, 665 EncodeSizeInBits(LaneSizeInBitsFromFormat(format)), 666 kNoQualifiers) { 667 VIXL_ASSERT(IsValid()); 668 } 669 670 // Return a Z register with a known lane size (like "z0.B"). 671 ZRegister VnB() const { return ZRegister(GetCode(), kBRegSize); } 672 ZRegister VnH() const { return ZRegister(GetCode(), kHRegSize); } 673 ZRegister VnS() const { return ZRegister(GetCode(), kSRegSize); } 674 ZRegister VnD() const { return ZRegister(GetCode(), kDRegSize); } 675 ZRegister VnQ() const { return ZRegister(GetCode(), kQRegSize); } 676 677 template <typename T> 678 ZRegister WithLaneSize(T format) const { 679 return ZRegister(GetCode(), format); 680 } 681 682 ZRegister WithSameLaneSizeAs(const CPURegister& other) const { 683 VIXL_ASSERT(other.HasLaneSize()); 684 return this->WithLaneSize(other.GetLaneSizeInBits()); 685 } 686 687 constexpr bool IsValid() const { return IsValidZRegister(); } 688 }; 689 690 // Any SVE P register, with or without a qualifier or lane size specifier. 691 class PRegister : public CPURegister { 692 public: 693 VIXL_DECLARE_REGISTER_COMMON(PRegister, PRegister, CPURegister) 694 695 explicit constexpr PRegister(int code) : CPURegister(code, kUnknownSize, kPRegister) { 696 VIXL_ASSERT(IsValid()); 697 } 698 699 constexpr bool IsValid() const { 700 return IsValidPRegister() && !HasLaneSize() && IsUnqualified(); 701 } 702 703 // Return a P register with a known lane size (like "p0.B"). 704 PRegisterWithLaneSize VnB() const; 705 PRegisterWithLaneSize VnH() const; 706 PRegisterWithLaneSize VnS() const; 707 PRegisterWithLaneSize VnD() const; 708 709 template <typename T> 710 PRegisterWithLaneSize WithLaneSize(T format) const; 711 712 PRegisterWithLaneSize WithSameLaneSizeAs(const CPURegister& other) const; 713 714 // SVE predicates are specified (in normal assembly) with a "/z" (zeroing) or 715 // "/m" (merging) suffix. These methods are VIXL's equivalents. 716 PRegisterZ Zeroing() const; 717 PRegisterM Merging() const; 718 719 protected: 720 // Unchecked constructors, for use by derived classes. 721 constexpr PRegister(int code, EncodedSize encoded_lane_size) 722 : CPURegister(code, 723 kEncodedUnknownSize, 724 kPRegisterBank, 725 encoded_lane_size, 726 kNoQualifiers) {} 727 728 constexpr PRegister(int code, Qualifiers qualifiers) 729 : CPURegister(code, 730 kEncodedUnknownSize, 731 kPRegisterBank, 732 kEncodedUnknownSize, 733 qualifiers) {} 734 }; 735 736 // Any SVE P register with a known lane size (like "p0.B"). 737 class PRegisterWithLaneSize : public PRegister { 738 public: 739 VIXL_DECLARE_REGISTER_COMMON(PRegisterWithLaneSize, PRegister, PRegister) 740 741 constexpr PRegisterWithLaneSize(int code, int lane_size_in_bits) 742 : PRegister(code, EncodeSizeInBits(lane_size_in_bits)) { 743 VIXL_ASSERT(IsValid()); 744 } 745 746 PRegisterWithLaneSize(int code, VectorFormat format) 747 : PRegister(code, EncodeSizeInBits(LaneSizeInBitsFromFormat(format))) { 748 VIXL_ASSERT(IsValid()); 749 } 750 751 bool IsValid() const { 752 return IsValidPRegister() && HasLaneSize() && IsUnqualified(); 753 } 754 755 // Overload lane size accessors so we can assert `HasLaneSize()`. This allows 756 // tools such as clang-tidy to prove that the result of GetLaneSize* is 757 // non-zero. 758 759 // TODO: Make these return 'int'. 760 unsigned GetLaneSizeInBits() const { 761 VIXL_ASSERT(HasLaneSize()); 762 return PRegister::GetLaneSizeInBits(); 763 } 764 765 unsigned GetLaneSizeInBytes() const { 766 VIXL_ASSERT(HasLaneSize()); 767 return PRegister::GetLaneSizeInBytes(); 768 } 769 }; 770 771 // Any SVE P register with the zeroing qualifier (like "p0/z"). 772 class PRegisterZ : public PRegister { 773 public: 774 VIXL_DECLARE_REGISTER_COMMON(PRegisterZ, PRegister, PRegister) 775 776 explicit constexpr PRegisterZ(int code) : PRegister(code, kZeroing) { 777 VIXL_ASSERT(IsValid()); 778 } 779 780 bool IsValid() const { 781 return IsValidPRegister() && !HasLaneSize() && IsZeroing(); 782 } 783 }; 784 785 // Any SVE P register with the merging qualifier (like "p0/m"). 786 class PRegisterM : public PRegister { 787 public: 788 VIXL_DECLARE_REGISTER_COMMON(PRegisterM, PRegister, PRegister) 789 790 explicit constexpr PRegisterM(int code) : PRegister(code, kMerging) { 791 VIXL_ASSERT(IsValid()); 792 } 793 794 bool IsValid() const { 795 return IsValidPRegister() && !HasLaneSize() && IsMerging(); 796 } 797 }; 798 799 inline PRegisterWithLaneSize PRegister::VnB() const { 800 return PRegisterWithLaneSize(GetCode(), kBRegSize); 801 } 802 inline PRegisterWithLaneSize PRegister::VnH() const { 803 return PRegisterWithLaneSize(GetCode(), kHRegSize); 804 } 805 inline PRegisterWithLaneSize PRegister::VnS() const { 806 return PRegisterWithLaneSize(GetCode(), kSRegSize); 807 } 808 inline PRegisterWithLaneSize PRegister::VnD() const { 809 return PRegisterWithLaneSize(GetCode(), kDRegSize); 810 } 811 812 template <typename T> 813 inline PRegisterWithLaneSize PRegister::WithLaneSize(T format) const { 814 return PRegisterWithLaneSize(GetCode(), format); 815 } 816 817 inline PRegisterWithLaneSize PRegister::WithSameLaneSizeAs( 818 const CPURegister& other) const { 819 VIXL_ASSERT(other.HasLaneSize()); 820 return this->WithLaneSize(other.GetLaneSizeInBits()); 821 } 822 823 inline PRegisterZ PRegister::Zeroing() const { return PRegisterZ(GetCode()); } 824 inline PRegisterM PRegister::Merging() const { return PRegisterM(GetCode()); } 825 826 #define VIXL_REGISTER_WITH_SIZE_LIST(V) \ 827 V(WRegister, kWRegSize, Register) \ 828 V(XRegister, kXRegSize, Register) \ 829 V(QRegister, kQRegSize, VRegister) \ 830 V(DRegister, kDRegSize, VRegister) \ 831 V(SRegister, kSRegSize, VRegister) \ 832 V(HRegister, kHRegSize, VRegister) \ 833 V(BRegister, kBRegSize, VRegister) 834 835 #define VIXL_DEFINE_REGISTER_WITH_SIZE(NAME, SIZE, PARENT) \ 836 class NAME : public PARENT { \ 837 public: \ 838 VIXL_CONSTEXPR NAME() : PARENT() {} \ 839 explicit constexpr NAME(int code) : PARENT(code, SIZE) {} \ 840 \ 841 explicit constexpr NAME(PARENT other) : PARENT(other) { \ 842 VIXL_ASSERT(GetSizeInBits() == SIZE); \ 843 } \ 844 \ 845 PARENT As##PARENT() const { return *this; } \ 846 \ 847 VIXL_CONSTEXPR int GetSizeInBits() const { return SIZE; } \ 848 \ 849 constexpr bool IsValid() const { \ 850 return PARENT::IsValid() && (PARENT::GetSizeInBits() == SIZE); \ 851 } \ 852 }; 853 854 VIXL_REGISTER_WITH_SIZE_LIST(VIXL_DEFINE_REGISTER_WITH_SIZE) 855 856 // No*Reg is used to provide default values for unused arguments, error cases 857 // and so on. Note that these (and the default constructors) all compare equal 858 // (using the Is() method). 859 constexpr Register NoReg; 860 constexpr VRegister NoVReg; 861 constexpr CPURegister NoCPUReg; 862 constexpr ZRegister NoZReg; 863 864 // TODO: Ideally, these would use specialised register types (like XRegister and 865 // so on). However, doing so throws up template overloading problems elsewhere. 866 #define VIXL_DEFINE_REGISTERS(N) \ 867 constexpr Register w##N = WRegister(N); \ 868 constexpr Register x##N = XRegister(N); \ 869 constexpr VRegister b##N = BRegister(N); \ 870 constexpr VRegister h##N = HRegister(N); \ 871 constexpr VRegister s##N = SRegister(N); \ 872 constexpr VRegister d##N = DRegister(N); \ 873 constexpr VRegister q##N = QRegister(N); \ 874 constexpr VRegister v##N(N); \ 875 constexpr ZRegister z##N(N); 876 AARCH64_REGISTER_CODE_LIST(VIXL_DEFINE_REGISTERS) 877 #undef VIXL_DEFINE_REGISTERS 878 879 #define VIXL_DEFINE_P_REGISTERS(N) const PRegister p##N(N); 880 AARCH64_P_REGISTER_CODE_LIST(VIXL_DEFINE_P_REGISTERS) 881 #undef VIXL_DEFINE_P_REGISTERS 882 883 // VIXL represents 'sp' with a unique code, to tell it apart from 'xzr'. 884 constexpr Register wsp = WRegister(kSPRegInternalCode); 885 constexpr Register sp = XRegister(kSPRegInternalCode); 886 887 // Standard aliases. 888 constexpr Register ip0 = x16; 889 constexpr Register ip1 = x17; 890 constexpr Register lr = x30; 891 constexpr Register xzr = x31; 892 constexpr Register wzr = w31; 893 894 // AreAliased returns true if any of the named registers overlap. Arguments 895 // set to NoReg are ignored. The system stack pointer may be specified. 896 bool AreAliased(const CPURegister& reg1, 897 const CPURegister& reg2, 898 const CPURegister& reg3 = NoReg, 899 const CPURegister& reg4 = NoReg, 900 const CPURegister& reg5 = NoReg, 901 const CPURegister& reg6 = NoReg, 902 const CPURegister& reg7 = NoReg, 903 const CPURegister& reg8 = NoReg); 904 905 // AreSameSizeAndType returns true if all of the specified registers have the 906 // same size, and are of the same type. The system stack pointer may be 907 // specified. Arguments set to NoReg are ignored, as are any subsequent 908 // arguments. At least one argument (reg1) must be valid (not NoCPUReg). 909 bool AreSameSizeAndType(const CPURegister& reg1, 910 const CPURegister& reg2, 911 const CPURegister& reg3 = NoCPUReg, 912 const CPURegister& reg4 = NoCPUReg, 913 const CPURegister& reg5 = NoCPUReg, 914 const CPURegister& reg6 = NoCPUReg, 915 const CPURegister& reg7 = NoCPUReg, 916 const CPURegister& reg8 = NoCPUReg); 917 918 // AreEven returns true if all of the specified registers have even register 919 // indices. Arguments set to NoReg are ignored, as are any subsequent 920 // arguments. At least one argument (reg1) must be valid (not NoCPUReg). 921 bool AreEven(const CPURegister& reg1, 922 const CPURegister& reg2, 923 const CPURegister& reg3 = NoReg, 924 const CPURegister& reg4 = NoReg, 925 const CPURegister& reg5 = NoReg, 926 const CPURegister& reg6 = NoReg, 927 const CPURegister& reg7 = NoReg, 928 const CPURegister& reg8 = NoReg); 929 930 // AreConsecutive returns true if all of the specified registers are 931 // consecutive in the register file. Arguments set to NoReg are ignored, as are 932 // any subsequent arguments. At least one argument (reg1) must be valid 933 // (not NoCPUReg). 934 bool AreConsecutive(const CPURegister& reg1, 935 const CPURegister& reg2, 936 const CPURegister& reg3 = NoCPUReg, 937 const CPURegister& reg4 = NoCPUReg); 938 939 // AreSameFormat returns true if all of the specified registers have the same 940 // vector format. Arguments set to NoReg are ignored, as are any subsequent 941 // arguments. At least one argument (reg1) must be valid (not NoVReg). 942 bool AreSameFormat(const CPURegister& reg1, 943 const CPURegister& reg2, 944 const CPURegister& reg3 = NoCPUReg, 945 const CPURegister& reg4 = NoCPUReg); 946 947 // AreSameLaneSize returns true if all of the specified registers have the same 948 // element lane size, B, H, S or D. It doesn't compare the type of registers. 949 // Arguments set to NoReg are ignored, as are any subsequent arguments. 950 // At least one argument (reg1) must be valid (not NoVReg). 951 // TODO: Remove this, and replace its uses with AreSameFormat. 952 bool AreSameLaneSize(const CPURegister& reg1, 953 const CPURegister& reg2, 954 const CPURegister& reg3 = NoCPUReg, 955 const CPURegister& reg4 = NoCPUReg); 956 } // namespace vixl 957 958 #endif // VIXL_A64_REGISTERS_A64_H_