1 // Copyright 2016, 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_OPERANDS_AARCH64_H_ 28 #define VIXL_AARCH64_OPERANDS_AARCH64_H_ 29 30 #include "instructions-aarch64.h" 31 32 namespace vixl { 33 namespace aarch64 { 34 35 typedef uint64_t RegList; 36 static const int kRegListSizeInBits = sizeof(RegList) * 8; 37 38 39 // Registers. 40 41 // Some CPURegister methods can return Register or VRegister types, so we need 42 // to declare them in advance. 43 class Register; 44 class VRegister; 45 46 class CPURegister { 47 public: 48 enum RegisterType { 49 // The kInvalid value is used to detect uninitialized static instances, 50 // which are always zero-initialized before any constructors are called. 51 kInvalid = 0, 52 kRegister, 53 kVRegister, 54 kFPRegister = kVRegister, 55 kNoRegister 56 }; 57 CPURegister()58 CPURegister() : code_(0), size_(0), type_(kNoRegister) { 59 VIXL_ASSERT(!IsValid()); 60 VIXL_ASSERT(IsNone()); 61 } 62 CPURegister(unsigned code,unsigned size,RegisterType type)63 CPURegister(unsigned code, unsigned size, RegisterType type) 64 : code_(code), size_(size), type_(type) { 65 VIXL_ASSERT(IsValidOrNone()); 66 } 67 GetCode()68 unsigned GetCode() const { 69 VIXL_ASSERT(IsValid()); 70 return code_; 71 } code()72 VIXL_DEPRECATED("GetCode", unsigned code() const) { return GetCode(); } 73 GetType()74 RegisterType GetType() const { 75 VIXL_ASSERT(IsValidOrNone()); 76 return type_; 77 } 78 VIXL_DEPRECATED("GetType", RegisterType type() const) { return GetType(); } 79 GetBit()80 RegList GetBit() const { 81 VIXL_ASSERT(code_ < (sizeof(RegList) * 8)); 82 return IsValid() ? (static_cast<RegList>(1) << code_) : 0; 83 } 84 VIXL_DEPRECATED("GetBit", RegList Bit() const) { return GetBit(); } 85 GetSizeInBytes()86 int GetSizeInBytes() const { 87 VIXL_ASSERT(IsValid()); 88 VIXL_ASSERT(size_ % 8 == 0); 89 return size_ / 8; 90 } SizeInBytes()91 VIXL_DEPRECATED("GetSizeInBytes", int SizeInBytes() const) { 92 return GetSizeInBytes(); 93 } 94 GetSizeInBits()95 int GetSizeInBits() const { 96 VIXL_ASSERT(IsValid()); 97 return size_; 98 } size()99 VIXL_DEPRECATED("GetSizeInBits", unsigned size() const) { 100 return GetSizeInBits(); 101 } SizeInBits()102 VIXL_DEPRECATED("GetSizeInBits", int SizeInBits() const) { 103 return GetSizeInBits(); 104 } 105 Is8Bits()106 bool Is8Bits() const { 107 VIXL_ASSERT(IsValid()); 108 return size_ == 8; 109 } 110 Is16Bits()111 bool Is16Bits() const { 112 VIXL_ASSERT(IsValid()); 113 return size_ == 16; 114 } 115 Is32Bits()116 bool Is32Bits() const { 117 VIXL_ASSERT(IsValid()); 118 return size_ == 32; 119 } 120 Is64Bits()121 bool Is64Bits() const { 122 VIXL_ASSERT(IsValid()); 123 return size_ == 64; 124 } 125 Is128Bits()126 bool Is128Bits() const { 127 VIXL_ASSERT(IsValid()); 128 return size_ == 128; 129 } 130 IsValid()131 bool IsValid() const { 132 if (IsValidRegister() || IsValidVRegister()) { 133 VIXL_ASSERT(!IsNone()); 134 return true; 135 } else { 136 // This assert is hit when the register has not been properly initialized. 137 // One cause for this can be an initialisation order fiasco. See 138 // https://isocpp.org/wiki/faq/ctors#static-init-order for some details. 139 VIXL_ASSERT(IsNone()); 140 return false; 141 } 142 } 143 IsValidRegister()144 bool IsValidRegister() const { 145 return IsRegister() && ((size_ == kWRegSize) || (size_ == kXRegSize)) && 146 ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode)); 147 } 148 IsValidVRegister()149 bool IsValidVRegister() const { 150 return IsVRegister() && ((size_ == kBRegSize) || (size_ == kHRegSize) || 151 (size_ == kSRegSize) || (size_ == kDRegSize) || 152 (size_ == kQRegSize)) && 153 (code_ < kNumberOfVRegisters); 154 } 155 IsValidFPRegister()156 bool IsValidFPRegister() const { 157 return IsFPRegister() && (code_ < kNumberOfVRegisters); 158 } 159 IsNone()160 bool IsNone() const { 161 // kNoRegister types should always have size 0 and code 0. 162 VIXL_ASSERT((type_ != kNoRegister) || (code_ == 0)); 163 VIXL_ASSERT((type_ != kNoRegister) || (size_ == 0)); 164 165 return type_ == kNoRegister; 166 } 167 Aliases(const CPURegister & other)168 bool Aliases(const CPURegister& other) const { 169 VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone()); 170 return (code_ == other.code_) && (type_ == other.type_); 171 } 172 Is(const CPURegister & other)173 bool Is(const CPURegister& other) const { 174 VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone()); 175 return Aliases(other) && (size_ == other.size_); 176 } 177 IsZero()178 bool IsZero() const { 179 VIXL_ASSERT(IsValid()); 180 return IsRegister() && (code_ == kZeroRegCode); 181 } 182 IsSP()183 bool IsSP() const { 184 VIXL_ASSERT(IsValid()); 185 return IsRegister() && (code_ == kSPRegInternalCode); 186 } 187 IsRegister()188 bool IsRegister() const { return type_ == kRegister; } 189 IsVRegister()190 bool IsVRegister() const { return type_ == kVRegister; } 191 IsFPRegister()192 bool IsFPRegister() const { return IsS() || IsD(); } 193 IsW()194 bool IsW() const { return IsValidRegister() && Is32Bits(); } IsX()195 bool IsX() const { return IsValidRegister() && Is64Bits(); } 196 197 // These assertions ensure that the size and type of the register are as 198 // described. They do not consider the number of lanes that make up a vector. 199 // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD() 200 // does not imply Is1D() or Is8B(). 201 // Check the number of lanes, ie. the format of the vector, using methods such 202 // as Is8B(), Is1D(), etc. in the VRegister class. IsV()203 bool IsV() const { return IsVRegister(); } IsB()204 bool IsB() const { return IsV() && Is8Bits(); } IsH()205 bool IsH() const { return IsV() && Is16Bits(); } IsS()206 bool IsS() const { return IsV() && Is32Bits(); } IsD()207 bool IsD() const { return IsV() && Is64Bits(); } IsQ()208 bool IsQ() const { return IsV() && Is128Bits(); } 209 210 // Semantic type for sdot and udot instructions. IsS4B()211 bool IsS4B() const { return IsS(); } S4B()212 const VRegister& S4B() const { return S(); } 213 214 const Register& W() const; 215 const Register& X() const; 216 const VRegister& V() const; 217 const VRegister& B() const; 218 const VRegister& H() const; 219 const VRegister& S() const; 220 const VRegister& D() const; 221 const VRegister& Q() const; 222 IsSameType(const CPURegister & other)223 bool IsSameType(const CPURegister& other) const { 224 return type_ == other.type_; 225 } 226 IsSameSizeAndType(const CPURegister & other)227 bool IsSameSizeAndType(const CPURegister& other) const { 228 return (size_ == other.size_) && IsSameType(other); 229 } 230 231 protected: 232 unsigned code_; 233 int size_; 234 RegisterType type_; 235 236 private: IsValidOrNone()237 bool IsValidOrNone() const { return IsValid() || IsNone(); } 238 }; 239 240 241 class Register : public CPURegister { 242 public: Register()243 Register() : CPURegister() {} Register(const CPURegister & other)244 explicit Register(const CPURegister& other) 245 : CPURegister(other.GetCode(), other.GetSizeInBits(), other.GetType()) { 246 VIXL_ASSERT(IsValidRegister()); 247 } Register(unsigned code,unsigned size)248 Register(unsigned code, unsigned size) : CPURegister(code, size, kRegister) {} 249 IsValid()250 bool IsValid() const { 251 VIXL_ASSERT(IsRegister() || IsNone()); 252 return IsValidRegister(); 253 } 254 255 static const Register& GetWRegFromCode(unsigned code); 256 VIXL_DEPRECATED("GetWRegFromCode", 257 static const Register& WRegFromCode(unsigned code)) { 258 return GetWRegFromCode(code); 259 } 260 261 static const Register& GetXRegFromCode(unsigned code); 262 VIXL_DEPRECATED("GetXRegFromCode", 263 static const Register& XRegFromCode(unsigned code)) { 264 return GetXRegFromCode(code); 265 } 266 267 private: 268 static const Register wregisters[]; 269 static const Register xregisters[]; 270 }; 271 272 273 namespace internal { 274 275 template <int size_in_bits> 276 class FixedSizeRegister : public Register { 277 public: FixedSizeRegister()278 FixedSizeRegister() : Register() {} FixedSizeRegister(unsigned code)279 explicit FixedSizeRegister(unsigned code) : Register(code, size_in_bits) { 280 VIXL_ASSERT(IsValidRegister()); 281 } FixedSizeRegister(const Register & other)282 explicit FixedSizeRegister(const Register& other) 283 : Register(other.GetCode(), size_in_bits) { 284 VIXL_ASSERT(other.GetSizeInBits() == size_in_bits); 285 VIXL_ASSERT(IsValidRegister()); 286 } FixedSizeRegister(const CPURegister & other)287 explicit FixedSizeRegister(const CPURegister& other) 288 : Register(other.GetCode(), other.GetSizeInBits()) { 289 VIXL_ASSERT(other.GetType() == kRegister); 290 VIXL_ASSERT(other.GetSizeInBits() == size_in_bits); 291 VIXL_ASSERT(IsValidRegister()); 292 } 293 IsValid()294 bool IsValid() const { 295 return Register::IsValid() && (GetSizeInBits() == size_in_bits); 296 } 297 }; 298 299 } // namespace internal 300 301 typedef internal::FixedSizeRegister<kXRegSize> XRegister; 302 typedef internal::FixedSizeRegister<kWRegSize> WRegister; 303 304 305 class VRegister : public CPURegister { 306 public: VRegister()307 VRegister() : CPURegister(), lanes_(1) {} VRegister(const CPURegister & other)308 explicit VRegister(const CPURegister& other) 309 : CPURegister(other.GetCode(), other.GetSizeInBits(), other.GetType()), 310 lanes_(1) { 311 VIXL_ASSERT(IsValidVRegister()); 312 VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16)); 313 } 314 VRegister(unsigned code, unsigned size, unsigned lanes = 1) CPURegister(code,size,kVRegister)315 : CPURegister(code, size, kVRegister), lanes_(lanes) { 316 VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16)); 317 } VRegister(unsigned code,VectorFormat format)318 VRegister(unsigned code, VectorFormat format) 319 : CPURegister(code, RegisterSizeInBitsFromFormat(format), kVRegister), 320 lanes_(IsVectorFormat(format) ? LaneCountFromFormat(format) : 1) { 321 VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16)); 322 } 323 IsValid()324 bool IsValid() const { 325 VIXL_ASSERT(IsVRegister() || IsNone()); 326 return IsValidVRegister(); 327 } 328 329 static const VRegister& GetBRegFromCode(unsigned code); 330 VIXL_DEPRECATED("GetBRegFromCode", 331 static const VRegister& BRegFromCode(unsigned code)) { 332 return GetBRegFromCode(code); 333 } 334 335 static const VRegister& GetHRegFromCode(unsigned code); 336 VIXL_DEPRECATED("GetHRegFromCode", 337 static const VRegister& HRegFromCode(unsigned code)) { 338 return GetHRegFromCode(code); 339 } 340 341 static const VRegister& GetSRegFromCode(unsigned code); 342 VIXL_DEPRECATED("GetSRegFromCode", 343 static const VRegister& SRegFromCode(unsigned code)) { 344 return GetSRegFromCode(code); 345 } 346 347 static const VRegister& GetDRegFromCode(unsigned code); 348 VIXL_DEPRECATED("GetDRegFromCode", 349 static const VRegister& DRegFromCode(unsigned code)) { 350 return GetDRegFromCode(code); 351 } 352 353 static const VRegister& GetQRegFromCode(unsigned code); 354 VIXL_DEPRECATED("GetQRegFromCode", 355 static const VRegister& QRegFromCode(unsigned code)) { 356 return GetQRegFromCode(code); 357 } 358 359 static const VRegister& GetVRegFromCode(unsigned code); 360 VIXL_DEPRECATED("GetVRegFromCode", 361 static const VRegister& VRegFromCode(unsigned code)) { 362 return GetVRegFromCode(code); 363 } 364 V8B()365 VRegister V8B() const { return VRegister(code_, kDRegSize, 8); } V16B()366 VRegister V16B() const { return VRegister(code_, kQRegSize, 16); } V2H()367 VRegister V2H() const { return VRegister(code_, kSRegSize, 2); } V4H()368 VRegister V4H() const { return VRegister(code_, kDRegSize, 4); } V8H()369 VRegister V8H() const { return VRegister(code_, kQRegSize, 8); } V2S()370 VRegister V2S() const { return VRegister(code_, kDRegSize, 2); } V4S()371 VRegister V4S() const { return VRegister(code_, kQRegSize, 4); } V2D()372 VRegister V2D() const { return VRegister(code_, kQRegSize, 2); } V1D()373 VRegister V1D() const { return VRegister(code_, kDRegSize, 1); } 374 Is8B()375 bool Is8B() const { return (Is64Bits() && (lanes_ == 8)); } Is16B()376 bool Is16B() const { return (Is128Bits() && (lanes_ == 16)); } Is2H()377 bool Is2H() const { return (Is32Bits() && (lanes_ == 2)); } Is4H()378 bool Is4H() const { return (Is64Bits() && (lanes_ == 4)); } Is8H()379 bool Is8H() const { return (Is128Bits() && (lanes_ == 8)); } Is2S()380 bool Is2S() const { return (Is64Bits() && (lanes_ == 2)); } Is4S()381 bool Is4S() const { return (Is128Bits() && (lanes_ == 4)); } Is1D()382 bool Is1D() const { return (Is64Bits() && (lanes_ == 1)); } Is2D()383 bool Is2D() const { return (Is128Bits() && (lanes_ == 2)); } 384 385 // For consistency, we assert the number of lanes of these scalar registers, 386 // even though there are no vectors of equivalent total size with which they 387 // could alias. Is1B()388 bool Is1B() const { 389 VIXL_ASSERT(!(Is8Bits() && IsVector())); 390 return Is8Bits(); 391 } Is1H()392 bool Is1H() const { 393 VIXL_ASSERT(!(Is16Bits() && IsVector())); 394 return Is16Bits(); 395 } Is1S()396 bool Is1S() const { 397 VIXL_ASSERT(!(Is32Bits() && IsVector())); 398 return Is32Bits(); 399 } 400 401 // Semantic type for sdot and udot instructions. Is1S4B()402 bool Is1S4B() const { return Is1S(); } 403 404 IsLaneSizeB()405 bool IsLaneSizeB() const { return GetLaneSizeInBits() == kBRegSize; } IsLaneSizeH()406 bool IsLaneSizeH() const { return GetLaneSizeInBits() == kHRegSize; } IsLaneSizeS()407 bool IsLaneSizeS() const { return GetLaneSizeInBits() == kSRegSize; } IsLaneSizeD()408 bool IsLaneSizeD() const { return GetLaneSizeInBits() == kDRegSize; } 409 GetLanes()410 int GetLanes() const { return lanes_; } lanes()411 VIXL_DEPRECATED("GetLanes", int lanes() const) { return GetLanes(); } 412 IsScalar()413 bool IsScalar() const { return lanes_ == 1; } 414 IsVector()415 bool IsVector() const { return lanes_ > 1; } 416 IsSameFormat(const VRegister & other)417 bool IsSameFormat(const VRegister& other) const { 418 return (size_ == other.size_) && (lanes_ == other.lanes_); 419 } 420 GetLaneSizeInBytes()421 unsigned GetLaneSizeInBytes() const { return GetSizeInBytes() / lanes_; } LaneSizeInBytes()422 VIXL_DEPRECATED("GetLaneSizeInBytes", unsigned LaneSizeInBytes() const) { 423 return GetLaneSizeInBytes(); 424 } 425 GetLaneSizeInBits()426 unsigned GetLaneSizeInBits() const { return GetLaneSizeInBytes() * 8; } LaneSizeInBits()427 VIXL_DEPRECATED("GetLaneSizeInBits", unsigned LaneSizeInBits() const) { 428 return GetLaneSizeInBits(); 429 } 430 431 private: 432 static const VRegister bregisters[]; 433 static const VRegister hregisters[]; 434 static const VRegister sregisters[]; 435 static const VRegister dregisters[]; 436 static const VRegister qregisters[]; 437 static const VRegister vregisters[]; 438 int lanes_; 439 }; 440 441 442 // Backward compatibility for FPRegisters. 443 typedef VRegister FPRegister; 444 445 // No*Reg is used to indicate an unused argument, or an error case. Note that 446 // these all compare equal (using the Is() method). The Register and VRegister 447 // variants are provided for convenience. 448 const Register NoReg; 449 const VRegister NoVReg; 450 const FPRegister NoFPReg; // For backward compatibility. 451 const CPURegister NoCPUReg; 452 453 454 #define DEFINE_REGISTERS(N) \ 455 const WRegister w##N(N); \ 456 const XRegister x##N(N); 457 AARCH64_REGISTER_CODE_LIST(DEFINE_REGISTERS) 458 #undef DEFINE_REGISTERS 459 const WRegister wsp(kSPRegInternalCode); 460 const XRegister sp(kSPRegInternalCode); 461 462 463 #define DEFINE_VREGISTERS(N) \ 464 const VRegister b##N(N, kBRegSize); \ 465 const VRegister h##N(N, kHRegSize); \ 466 const VRegister s##N(N, kSRegSize); \ 467 const VRegister d##N(N, kDRegSize); \ 468 const VRegister q##N(N, kQRegSize); \ 469 const VRegister v##N(N, kQRegSize); 470 AARCH64_REGISTER_CODE_LIST(DEFINE_VREGISTERS) 471 #undef DEFINE_VREGISTERS 472 473 474 // Register aliases. 475 const XRegister ip0 = x16; 476 const XRegister ip1 = x17; 477 const XRegister lr = x30; 478 const XRegister xzr = x31; 479 const WRegister wzr = w31; 480 481 482 // AreAliased returns true if any of the named registers overlap. Arguments 483 // set to NoReg are ignored. The system stack pointer may be specified. 484 bool AreAliased(const CPURegister& reg1, 485 const CPURegister& reg2, 486 const CPURegister& reg3 = NoReg, 487 const CPURegister& reg4 = NoReg, 488 const CPURegister& reg5 = NoReg, 489 const CPURegister& reg6 = NoReg, 490 const CPURegister& reg7 = NoReg, 491 const CPURegister& reg8 = NoReg); 492 493 494 // AreSameSizeAndType returns true if all of the specified registers have the 495 // same size, and are of the same type. The system stack pointer may be 496 // specified. Arguments set to NoReg are ignored, as are any subsequent 497 // arguments. At least one argument (reg1) must be valid (not NoCPUReg). 498 bool AreSameSizeAndType(const CPURegister& reg1, 499 const CPURegister& reg2, 500 const CPURegister& reg3 = NoCPUReg, 501 const CPURegister& reg4 = NoCPUReg, 502 const CPURegister& reg5 = NoCPUReg, 503 const CPURegister& reg6 = NoCPUReg, 504 const CPURegister& reg7 = NoCPUReg, 505 const CPURegister& reg8 = NoCPUReg); 506 507 // AreEven returns true if all of the specified registers have even register 508 // indices. Arguments set to NoReg are ignored, as are any subsequent 509 // arguments. At least one argument (reg1) must be valid (not NoCPUReg). 510 bool AreEven(const CPURegister& reg1, 511 const CPURegister& reg2, 512 const CPURegister& reg3 = NoReg, 513 const CPURegister& reg4 = NoReg, 514 const CPURegister& reg5 = NoReg, 515 const CPURegister& reg6 = NoReg, 516 const CPURegister& reg7 = NoReg, 517 const CPURegister& reg8 = NoReg); 518 519 520 // AreConsecutive returns true if all of the specified registers are 521 // consecutive in the register file. Arguments set to NoReg are ignored, as are 522 // any subsequent arguments. At least one argument (reg1) must be valid 523 // (not NoCPUReg). 524 bool AreConsecutive(const CPURegister& reg1, 525 const CPURegister& reg2, 526 const CPURegister& reg3 = NoCPUReg, 527 const CPURegister& reg4 = NoCPUReg); 528 529 530 // AreSameFormat returns true if all of the specified VRegisters have the same 531 // vector format. Arguments set to NoReg are ignored, as are any subsequent 532 // arguments. At least one argument (reg1) must be valid (not NoVReg). 533 bool AreSameFormat(const VRegister& reg1, 534 const VRegister& reg2, 535 const VRegister& reg3 = NoVReg, 536 const VRegister& reg4 = NoVReg); 537 538 539 // AreConsecutive returns true if all of the specified VRegisters are 540 // consecutive in the register file. Arguments set to NoReg are ignored, as are 541 // any subsequent arguments. At least one argument (reg1) must be valid 542 // (not NoVReg). 543 bool AreConsecutive(const VRegister& reg1, 544 const VRegister& reg2, 545 const VRegister& reg3 = NoVReg, 546 const VRegister& reg4 = NoVReg); 547 548 549 // Lists of registers. 550 class CPURegList { 551 public: 552 explicit CPURegList(CPURegister reg1, 553 CPURegister reg2 = NoCPUReg, 554 CPURegister reg3 = NoCPUReg, 555 CPURegister reg4 = NoCPUReg) 556 : list_(reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit()), 557 size_(reg1.GetSizeInBits()), 558 type_(reg1.GetType()) { 559 VIXL_ASSERT(AreSameSizeAndType(reg1, reg2, reg3, reg4)); 560 VIXL_ASSERT(IsValid()); 561 } 562 CPURegList(CPURegister::RegisterType type,unsigned size,RegList list)563 CPURegList(CPURegister::RegisterType type, unsigned size, RegList list) 564 : list_(list), size_(size), type_(type) { 565 VIXL_ASSERT(IsValid()); 566 } 567 CPURegList(CPURegister::RegisterType type,unsigned size,unsigned first_reg,unsigned last_reg)568 CPURegList(CPURegister::RegisterType type, 569 unsigned size, 570 unsigned first_reg, 571 unsigned last_reg) 572 : size_(size), type_(type) { 573 VIXL_ASSERT( 574 ((type == CPURegister::kRegister) && (last_reg < kNumberOfRegisters)) || 575 ((type == CPURegister::kVRegister) && 576 (last_reg < kNumberOfVRegisters))); 577 VIXL_ASSERT(last_reg >= first_reg); 578 list_ = (UINT64_C(1) << (last_reg + 1)) - 1; 579 list_ &= ~((UINT64_C(1) << first_reg) - 1); 580 VIXL_ASSERT(IsValid()); 581 } 582 GetType()583 CPURegister::RegisterType GetType() const { 584 VIXL_ASSERT(IsValid()); 585 return type_; 586 } 587 VIXL_DEPRECATED("GetType", CPURegister::RegisterType type() const) { 588 return GetType(); 589 } 590 591 // Combine another CPURegList into this one. Registers that already exist in 592 // this list are left unchanged. The type and size of the registers in the 593 // 'other' list must match those in this list. Combine(const CPURegList & other)594 void Combine(const CPURegList& other) { 595 VIXL_ASSERT(IsValid()); 596 VIXL_ASSERT(other.GetType() == type_); 597 VIXL_ASSERT(other.GetRegisterSizeInBits() == size_); 598 list_ |= other.GetList(); 599 } 600 601 // Remove every register in the other CPURegList from this one. Registers that 602 // do not exist in this list are ignored. The type and size of the registers 603 // in the 'other' list must match those in this list. Remove(const CPURegList & other)604 void Remove(const CPURegList& other) { 605 VIXL_ASSERT(IsValid()); 606 VIXL_ASSERT(other.GetType() == type_); 607 VIXL_ASSERT(other.GetRegisterSizeInBits() == size_); 608 list_ &= ~other.GetList(); 609 } 610 611 // Variants of Combine and Remove which take a single register. Combine(const CPURegister & other)612 void Combine(const CPURegister& other) { 613 VIXL_ASSERT(other.GetType() == type_); 614 VIXL_ASSERT(other.GetSizeInBits() == size_); 615 Combine(other.GetCode()); 616 } 617 Remove(const CPURegister & other)618 void Remove(const CPURegister& other) { 619 VIXL_ASSERT(other.GetType() == type_); 620 VIXL_ASSERT(other.GetSizeInBits() == size_); 621 Remove(other.GetCode()); 622 } 623 624 // Variants of Combine and Remove which take a single register by its code; 625 // the type and size of the register is inferred from this list. Combine(int code)626 void Combine(int code) { 627 VIXL_ASSERT(IsValid()); 628 VIXL_ASSERT(CPURegister(code, size_, type_).IsValid()); 629 list_ |= (UINT64_C(1) << code); 630 } 631 Remove(int code)632 void Remove(int code) { 633 VIXL_ASSERT(IsValid()); 634 VIXL_ASSERT(CPURegister(code, size_, type_).IsValid()); 635 list_ &= ~(UINT64_C(1) << code); 636 } 637 Union(const CPURegList & list_1,const CPURegList & list_2)638 static CPURegList Union(const CPURegList& list_1, const CPURegList& list_2) { 639 VIXL_ASSERT(list_1.type_ == list_2.type_); 640 VIXL_ASSERT(list_1.size_ == list_2.size_); 641 return CPURegList(list_1.type_, list_1.size_, list_1.list_ | list_2.list_); 642 } 643 static CPURegList Union(const CPURegList& list_1, 644 const CPURegList& list_2, 645 const CPURegList& list_3); 646 static CPURegList Union(const CPURegList& list_1, 647 const CPURegList& list_2, 648 const CPURegList& list_3, 649 const CPURegList& list_4); 650 Intersection(const CPURegList & list_1,const CPURegList & list_2)651 static CPURegList Intersection(const CPURegList& list_1, 652 const CPURegList& list_2) { 653 VIXL_ASSERT(list_1.type_ == list_2.type_); 654 VIXL_ASSERT(list_1.size_ == list_2.size_); 655 return CPURegList(list_1.type_, list_1.size_, list_1.list_ & list_2.list_); 656 } 657 static CPURegList Intersection(const CPURegList& list_1, 658 const CPURegList& list_2, 659 const CPURegList& list_3); 660 static CPURegList Intersection(const CPURegList& list_1, 661 const CPURegList& list_2, 662 const CPURegList& list_3, 663 const CPURegList& list_4); 664 Overlaps(const CPURegList & other)665 bool Overlaps(const CPURegList& other) const { 666 return (type_ == other.type_) && ((list_ & other.list_) != 0); 667 } 668 GetList()669 RegList GetList() const { 670 VIXL_ASSERT(IsValid()); 671 return list_; 672 } 673 VIXL_DEPRECATED("GetList", RegList list() const) { return GetList(); } 674 SetList(RegList new_list)675 void SetList(RegList new_list) { 676 VIXL_ASSERT(IsValid()); 677 list_ = new_list; 678 } set_list(RegList new_list)679 VIXL_DEPRECATED("SetList", void set_list(RegList new_list)) { 680 return SetList(new_list); 681 } 682 683 // Remove all callee-saved registers from the list. This can be useful when 684 // preparing registers for an AAPCS64 function call, for example. 685 void RemoveCalleeSaved(); 686 687 CPURegister PopLowestIndex(); 688 CPURegister PopHighestIndex(); 689 690 // AAPCS64 callee-saved registers. 691 static CPURegList GetCalleeSaved(unsigned size = kXRegSize); 692 static CPURegList GetCalleeSavedV(unsigned size = kDRegSize); 693 694 // AAPCS64 caller-saved registers. Note that this includes lr. 695 // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top 696 // 64-bits being caller-saved. 697 static CPURegList GetCallerSaved(unsigned size = kXRegSize); 698 static CPURegList GetCallerSavedV(unsigned size = kDRegSize); 699 IsEmpty()700 bool IsEmpty() const { 701 VIXL_ASSERT(IsValid()); 702 return list_ == 0; 703 } 704 IncludesAliasOf(const CPURegister & other)705 bool IncludesAliasOf(const CPURegister& other) const { 706 VIXL_ASSERT(IsValid()); 707 return (type_ == other.GetType()) && ((other.GetBit() & list_) != 0); 708 } 709 IncludesAliasOf(int code)710 bool IncludesAliasOf(int code) const { 711 VIXL_ASSERT(IsValid()); 712 return ((code & list_) != 0); 713 } 714 GetCount()715 int GetCount() const { 716 VIXL_ASSERT(IsValid()); 717 return CountSetBits(list_); 718 } Count()719 VIXL_DEPRECATED("GetCount", int Count()) const { return GetCount(); } 720 GetRegisterSizeInBits()721 int GetRegisterSizeInBits() const { 722 VIXL_ASSERT(IsValid()); 723 return size_; 724 } RegisterSizeInBits()725 VIXL_DEPRECATED("GetRegisterSizeInBits", int RegisterSizeInBits() const) { 726 return GetRegisterSizeInBits(); 727 } 728 GetRegisterSizeInBytes()729 int GetRegisterSizeInBytes() const { 730 int size_in_bits = GetRegisterSizeInBits(); 731 VIXL_ASSERT((size_in_bits % 8) == 0); 732 return size_in_bits / 8; 733 } RegisterSizeInBytes()734 VIXL_DEPRECATED("GetRegisterSizeInBytes", int RegisterSizeInBytes() const) { 735 return GetRegisterSizeInBytes(); 736 } 737 GetTotalSizeInBytes()738 unsigned GetTotalSizeInBytes() const { 739 VIXL_ASSERT(IsValid()); 740 return GetRegisterSizeInBytes() * GetCount(); 741 } TotalSizeInBytes()742 VIXL_DEPRECATED("GetTotalSizeInBytes", unsigned TotalSizeInBytes() const) { 743 return GetTotalSizeInBytes(); 744 } 745 746 private: 747 RegList list_; 748 int size_; 749 CPURegister::RegisterType type_; 750 751 bool IsValid() const; 752 }; 753 754 755 // AAPCS64 callee-saved registers. 756 extern const CPURegList kCalleeSaved; 757 extern const CPURegList kCalleeSavedV; 758 759 760 // AAPCS64 caller-saved registers. Note that this includes lr. 761 extern const CPURegList kCallerSaved; 762 extern const CPURegList kCallerSavedV; 763 764 765 // Operand. 766 class Operand { 767 public: 768 // #<immediate> 769 // where <immediate> is int64_t. 770 // This is allowed to be an implicit constructor because Operand is 771 // a wrapper class that doesn't normally perform any type conversion. 772 Operand(int64_t immediate = 0); // NOLINT(runtime/explicit) 773 774 // rm, {<shift> #<shift_amount>} 775 // where <shift> is one of {LSL, LSR, ASR, ROR}. 776 // <shift_amount> is uint6_t. 777 // This is allowed to be an implicit constructor because Operand is 778 // a wrapper class that doesn't normally perform any type conversion. 779 Operand(Register reg, 780 Shift shift = LSL, 781 unsigned shift_amount = 0); // NOLINT(runtime/explicit) 782 783 // rm, {<extend> {#<shift_amount>}} 784 // where <extend> is one of {UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX}. 785 // <shift_amount> is uint2_t. 786 explicit Operand(Register reg, Extend extend, unsigned shift_amount = 0); 787 788 bool IsImmediate() const; 789 bool IsPlainRegister() const; 790 bool IsShiftedRegister() const; 791 bool IsExtendedRegister() const; 792 bool IsZero() const; 793 794 // This returns an LSL shift (<= 4) operand as an equivalent extend operand, 795 // which helps in the encoding of instructions that use the stack pointer. 796 Operand ToExtendedRegister() const; 797 GetImmediate()798 int64_t GetImmediate() const { 799 VIXL_ASSERT(IsImmediate()); 800 return immediate_; 801 } 802 VIXL_DEPRECATED("GetImmediate", int64_t immediate() const) { 803 return GetImmediate(); 804 } 805 GetEquivalentImmediate()806 int64_t GetEquivalentImmediate() const { 807 return IsZero() ? 0 : GetImmediate(); 808 } 809 GetRegister()810 Register GetRegister() const { 811 VIXL_ASSERT(IsShiftedRegister() || IsExtendedRegister()); 812 return reg_; 813 } 814 VIXL_DEPRECATED("GetRegister", Register reg() const) { return GetRegister(); } GetBaseRegister()815 Register GetBaseRegister() const { return GetRegister(); } 816 GetShift()817 Shift GetShift() const { 818 VIXL_ASSERT(IsShiftedRegister()); 819 return shift_; 820 } 821 VIXL_DEPRECATED("GetShift", Shift shift() const) { return GetShift(); } 822 GetExtend()823 Extend GetExtend() const { 824 VIXL_ASSERT(IsExtendedRegister()); 825 return extend_; 826 } 827 VIXL_DEPRECATED("GetExtend", Extend extend() const) { return GetExtend(); } 828 GetShiftAmount()829 unsigned GetShiftAmount() const { 830 VIXL_ASSERT(IsShiftedRegister() || IsExtendedRegister()); 831 return shift_amount_; 832 } shift_amount()833 VIXL_DEPRECATED("GetShiftAmount", unsigned shift_amount() const) { 834 return GetShiftAmount(); 835 } 836 837 private: 838 int64_t immediate_; 839 Register reg_; 840 Shift shift_; 841 Extend extend_; 842 unsigned shift_amount_; 843 }; 844 845 846 // MemOperand represents the addressing mode of a load or store instruction. 847 class MemOperand { 848 public: 849 // Creates an invalid `MemOperand`. 850 MemOperand(); 851 explicit MemOperand(Register base, 852 int64_t offset = 0, 853 AddrMode addrmode = Offset); 854 MemOperand(Register base, 855 Register regoffset, 856 Shift shift = LSL, 857 unsigned shift_amount = 0); 858 MemOperand(Register base, 859 Register regoffset, 860 Extend extend, 861 unsigned shift_amount = 0); 862 MemOperand(Register base, const Operand& offset, AddrMode addrmode = Offset); 863 GetBaseRegister()864 const Register& GetBaseRegister() const { return base_; } 865 VIXL_DEPRECATED("GetBaseRegister", const Register& base() const) { 866 return GetBaseRegister(); 867 } 868 GetRegisterOffset()869 const Register& GetRegisterOffset() const { return regoffset_; } 870 VIXL_DEPRECATED("GetRegisterOffset", const Register& regoffset() const) { 871 return GetRegisterOffset(); 872 } 873 GetOffset()874 int64_t GetOffset() const { return offset_; } 875 VIXL_DEPRECATED("GetOffset", int64_t offset() const) { return GetOffset(); } 876 GetAddrMode()877 AddrMode GetAddrMode() const { return addrmode_; } 878 VIXL_DEPRECATED("GetAddrMode", AddrMode addrmode() const) { 879 return GetAddrMode(); 880 } 881 GetShift()882 Shift GetShift() const { return shift_; } 883 VIXL_DEPRECATED("GetShift", Shift shift() const) { return GetShift(); } 884 GetExtend()885 Extend GetExtend() const { return extend_; } 886 VIXL_DEPRECATED("GetExtend", Extend extend() const) { return GetExtend(); } 887 GetShiftAmount()888 unsigned GetShiftAmount() const { return shift_amount_; } shift_amount()889 VIXL_DEPRECATED("GetShiftAmount", unsigned shift_amount() const) { 890 return GetShiftAmount(); 891 } 892 893 bool IsImmediateOffset() const; 894 bool IsRegisterOffset() const; 895 bool IsPreIndex() const; 896 bool IsPostIndex() const; 897 898 void AddOffset(int64_t offset); 899 IsValid()900 bool IsValid() const { 901 return base_.IsValid() && 902 ((addrmode_ == Offset) || (addrmode_ == PreIndex) || 903 (addrmode_ == PostIndex)) && 904 ((shift_ == NO_SHIFT) || (extend_ == NO_EXTEND)) && 905 ((offset_ == 0) || !regoffset_.IsValid()); 906 } 907 Equals(const MemOperand & other)908 bool Equals(const MemOperand& other) const { 909 return base_.Is(other.base_) && regoffset_.Is(other.regoffset_) && 910 (offset_ == other.offset_) && (addrmode_ == other.addrmode_) && 911 (shift_ == other.shift_) && (extend_ == other.extend_) && 912 (shift_amount_ == other.shift_amount_); 913 } 914 915 private: 916 Register base_; 917 Register regoffset_; 918 int64_t offset_; 919 AddrMode addrmode_; 920 Shift shift_; 921 Extend extend_; 922 unsigned shift_amount_; 923 }; 924 925 // This an abstraction that can represent a register or memory location. The 926 // `MacroAssembler` provides helpers to move data between generic operands. 927 class GenericOperand { 928 public: GenericOperand()929 GenericOperand() { VIXL_ASSERT(!IsValid()); } 930 GenericOperand(const CPURegister& reg); // NOLINT(runtime/explicit) 931 GenericOperand(const MemOperand& mem_op, 932 size_t mem_op_size = 0); // NOLINT(runtime/explicit) 933 IsValid()934 bool IsValid() const { return cpu_register_.IsValid() != mem_op_.IsValid(); } 935 936 bool Equals(const GenericOperand& other) const; 937 IsCPURegister()938 bool IsCPURegister() const { 939 VIXL_ASSERT(IsValid()); 940 return cpu_register_.IsValid(); 941 } 942 IsRegister()943 bool IsRegister() const { 944 return IsCPURegister() && cpu_register_.IsRegister(); 945 } 946 IsVRegister()947 bool IsVRegister() const { 948 return IsCPURegister() && cpu_register_.IsVRegister(); 949 } 950 IsSameCPURegisterType(const GenericOperand & other)951 bool IsSameCPURegisterType(const GenericOperand& other) { 952 return IsCPURegister() && other.IsCPURegister() && 953 GetCPURegister().IsSameType(other.GetCPURegister()); 954 } 955 IsMemOperand()956 bool IsMemOperand() const { 957 VIXL_ASSERT(IsValid()); 958 return mem_op_.IsValid(); 959 } 960 GetCPURegister()961 CPURegister GetCPURegister() const { 962 VIXL_ASSERT(IsCPURegister()); 963 return cpu_register_; 964 } 965 GetMemOperand()966 MemOperand GetMemOperand() const { 967 VIXL_ASSERT(IsMemOperand()); 968 return mem_op_; 969 } 970 GetMemOperandSizeInBytes()971 size_t GetMemOperandSizeInBytes() const { 972 VIXL_ASSERT(IsMemOperand()); 973 return mem_op_size_; 974 } 975 GetSizeInBytes()976 size_t GetSizeInBytes() const { 977 return IsCPURegister() ? cpu_register_.GetSizeInBytes() 978 : GetMemOperandSizeInBytes(); 979 } 980 GetSizeInBits()981 size_t GetSizeInBits() const { return GetSizeInBytes() * kBitsPerByte; } 982 983 private: 984 CPURegister cpu_register_; 985 MemOperand mem_op_; 986 // The size of the memory region pointed to, in bytes. 987 // We only support sizes up to X/D register sizes. 988 size_t mem_op_size_; 989 }; 990 } 991 } // namespace vixl::aarch64 992 993 #endif // VIXL_AARCH64_OPERANDS_AARCH64_H_ 994