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