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