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 kNoRegister 55 }; 56 CPURegister()57 CPURegister() : code_(0), size_(0), type_(kNoRegister) { 58 VIXL_ASSERT(!IsValid()); 59 VIXL_ASSERT(IsNone()); 60 } 61 CPURegister(unsigned code,unsigned size,RegisterType type)62 CPURegister(unsigned code, unsigned size, RegisterType type) 63 : code_(code), size_(size), type_(type) { 64 VIXL_ASSERT(IsValidOrNone()); 65 } 66 GetCode()67 unsigned GetCode() const { 68 VIXL_ASSERT(IsValid()); 69 return code_; 70 } code()71 VIXL_DEPRECATED("GetCode", unsigned code() const) { return GetCode(); } 72 GetType()73 RegisterType GetType() const { 74 VIXL_ASSERT(IsValidOrNone()); 75 return type_; 76 } 77 VIXL_DEPRECATED("GetType", RegisterType type() const) { return GetType(); } 78 GetBit()79 RegList GetBit() const { 80 VIXL_ASSERT(code_ < (sizeof(RegList) * 8)); 81 return IsValid() ? (static_cast<RegList>(1) << code_) : 0; 82 } 83 VIXL_DEPRECATED("GetBit", RegList Bit() const) { return GetBit(); } 84 GetSizeInBytes()85 int GetSizeInBytes() const { 86 VIXL_ASSERT(IsValid()); 87 VIXL_ASSERT(size_ % 8 == 0); 88 return size_ / 8; 89 } SizeInBytes()90 VIXL_DEPRECATED("GetSizeInBytes", int SizeInBytes() const) { 91 return GetSizeInBytes(); 92 } 93 GetSizeInBits()94 int GetSizeInBits() const { 95 VIXL_ASSERT(IsValid()); 96 return size_; 97 } size()98 VIXL_DEPRECATED("GetSizeInBits", unsigned size() const) { 99 return GetSizeInBits(); 100 } SizeInBits()101 VIXL_DEPRECATED("GetSizeInBits", int SizeInBits() const) { 102 return GetSizeInBits(); 103 } 104 Is8Bits()105 bool Is8Bits() const { 106 VIXL_ASSERT(IsValid()); 107 return size_ == 8; 108 } 109 Is16Bits()110 bool Is16Bits() const { 111 VIXL_ASSERT(IsValid()); 112 return size_ == 16; 113 } 114 Is32Bits()115 bool Is32Bits() const { 116 VIXL_ASSERT(IsValid()); 117 return size_ == 32; 118 } 119 Is64Bits()120 bool Is64Bits() const { 121 VIXL_ASSERT(IsValid()); 122 return size_ == 64; 123 } 124 Is128Bits()125 bool Is128Bits() const { 126 VIXL_ASSERT(IsValid()); 127 return size_ == 128; 128 } 129 IsValid()130 bool IsValid() const { 131 if (IsValidRegister() || IsValidVRegister()) { 132 VIXL_ASSERT(!IsNone()); 133 return true; 134 } else { 135 // This assert is hit when the register has not been properly initialized. 136 // One cause for this can be an initialisation order fiasco. See 137 // https://isocpp.org/wiki/faq/ctors#static-init-order for some details. 138 VIXL_ASSERT(IsNone()); 139 return false; 140 } 141 } 142 IsValidRegister()143 bool IsValidRegister() const { 144 return IsRegister() && ((size_ == kWRegSize) || (size_ == kXRegSize)) && 145 ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode)); 146 } 147 IsValidVRegister()148 bool IsValidVRegister() const { 149 return IsVRegister() && ((size_ == kBRegSize) || (size_ == kHRegSize) || 150 (size_ == kSRegSize) || (size_ == kDRegSize) || 151 (size_ == kQRegSize)) && 152 (code_ < kNumberOfVRegisters); 153 } 154 IsValidFPRegister()155 bool IsValidFPRegister() const { 156 return IsValidVRegister() && IsFPRegister(); 157 } 158 IsNone()159 bool IsNone() const { 160 // kNoRegister types should always have size 0 and code 0. 161 VIXL_ASSERT((type_ != kNoRegister) || (code_ == 0)); 162 VIXL_ASSERT((type_ != kNoRegister) || (size_ == 0)); 163 164 return type_ == kNoRegister; 165 } 166 Aliases(const CPURegister & other)167 bool Aliases(const CPURegister& other) const { 168 VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone()); 169 return (code_ == other.code_) && (type_ == other.type_); 170 } 171 Is(const CPURegister & other)172 bool Is(const CPURegister& other) const { 173 VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone()); 174 return Aliases(other) && (size_ == other.size_); 175 } 176 IsZero()177 bool IsZero() const { 178 VIXL_ASSERT(IsValid()); 179 return IsRegister() && (code_ == kZeroRegCode); 180 } 181 IsSP()182 bool IsSP() const { 183 VIXL_ASSERT(IsValid()); 184 return IsRegister() && (code_ == kSPRegInternalCode); 185 } 186 IsRegister()187 bool IsRegister() const { return type_ == kRegister; } 188 IsVRegister()189 bool IsVRegister() const { return type_ == kVRegister; } 190 191 // CPURegister does not track lanes like VRegister does, so we have to assume 192 // that we have scalar types here. 193 // TODO: Encode lane information in CPURegister so that we can be consistent. IsFPRegister()194 bool IsFPRegister() const { return IsH() || IsS() || IsD(); } 195 IsW()196 bool IsW() const { return IsValidRegister() && Is32Bits(); } IsX()197 bool IsX() const { return IsValidRegister() && Is64Bits(); } 198 199 // These assertions ensure that the size and type of the register are as 200 // described. They do not consider the number of lanes that make up a vector. 201 // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD() 202 // does not imply Is1D() or Is8B(). 203 // Check the number of lanes, ie. the format of the vector, using methods such 204 // as Is8B(), Is1D(), etc. in the VRegister class. IsV()205 bool IsV() const { return IsVRegister(); } IsB()206 bool IsB() const { return IsV() && Is8Bits(); } IsH()207 bool IsH() const { return IsV() && Is16Bits(); } IsS()208 bool IsS() const { return IsV() && Is32Bits(); } IsD()209 bool IsD() const { return IsV() && Is64Bits(); } IsQ()210 bool IsQ() const { return IsV() && Is128Bits(); } 211 212 // Semantic type for sdot and udot instructions. IsS4B()213 bool IsS4B() const { return IsS(); } S4B()214 const VRegister& S4B() const { return S(); } 215 216 const Register& W() const; 217 const Register& X() const; 218 const VRegister& V() const; 219 const VRegister& B() const; 220 const VRegister& H() const; 221 const VRegister& S() const; 222 const VRegister& D() const; 223 const VRegister& Q() const; 224 IsSameType(const CPURegister & other)225 bool IsSameType(const CPURegister& other) const { 226 return type_ == other.type_; 227 } 228 IsSameSizeAndType(const CPURegister & other)229 bool IsSameSizeAndType(const CPURegister& other) const { 230 return (size_ == other.size_) && IsSameType(other); 231 } 232 233 protected: 234 unsigned code_; 235 int size_; 236 RegisterType type_; 237 238 private: IsValidOrNone()239 bool IsValidOrNone() const { return IsValid() || IsNone(); } 240 }; 241 242 243 class Register : public CPURegister { 244 public: Register()245 Register() : CPURegister() {} Register(const CPURegister & other)246 explicit Register(const CPURegister& other) 247 : CPURegister(other.GetCode(), other.GetSizeInBits(), other.GetType()) { 248 VIXL_ASSERT(IsValidRegister()); 249 } Register(unsigned code,unsigned size)250 Register(unsigned code, unsigned size) : CPURegister(code, size, kRegister) {} 251 IsValid()252 bool IsValid() const { 253 VIXL_ASSERT(IsRegister() || IsNone()); 254 return IsValidRegister(); 255 } 256 257 static const Register& GetWRegFromCode(unsigned code); 258 VIXL_DEPRECATED("GetWRegFromCode", 259 static const Register& WRegFromCode(unsigned code)) { 260 return GetWRegFromCode(code); 261 } 262 263 static const Register& GetXRegFromCode(unsigned code); 264 VIXL_DEPRECATED("GetXRegFromCode", 265 static const Register& XRegFromCode(unsigned code)) { 266 return GetXRegFromCode(code); 267 } 268 269 private: 270 static const Register wregisters[]; 271 static const Register xregisters[]; 272 }; 273 274 275 namespace internal { 276 277 template <int size_in_bits> 278 class FixedSizeRegister : public Register { 279 public: FixedSizeRegister()280 FixedSizeRegister() : Register() {} FixedSizeRegister(unsigned code)281 explicit FixedSizeRegister(unsigned code) : Register(code, size_in_bits) { 282 VIXL_ASSERT(IsValidRegister()); 283 } FixedSizeRegister(const Register & other)284 explicit FixedSizeRegister(const Register& other) 285 : Register(other.GetCode(), size_in_bits) { 286 VIXL_ASSERT(other.GetSizeInBits() == size_in_bits); 287 VIXL_ASSERT(IsValidRegister()); 288 } FixedSizeRegister(const CPURegister & other)289 explicit FixedSizeRegister(const CPURegister& other) 290 : Register(other.GetCode(), other.GetSizeInBits()) { 291 VIXL_ASSERT(other.GetType() == kRegister); 292 VIXL_ASSERT(other.GetSizeInBits() == size_in_bits); 293 VIXL_ASSERT(IsValidRegister()); 294 } 295 IsValid()296 bool IsValid() const { 297 return Register::IsValid() && (GetSizeInBits() == size_in_bits); 298 } 299 }; 300 301 } // namespace internal 302 303 typedef internal::FixedSizeRegister<kXRegSize> XRegister; 304 typedef internal::FixedSizeRegister<kWRegSize> WRegister; 305 306 307 class VRegister : public CPURegister { 308 public: VRegister()309 VRegister() : CPURegister(), lanes_(1) {} VRegister(const CPURegister & other)310 explicit VRegister(const CPURegister& other) 311 : CPURegister(other.GetCode(), other.GetSizeInBits(), other.GetType()), 312 lanes_(1) { 313 VIXL_ASSERT(IsValidVRegister()); 314 VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16)); 315 } 316 VRegister(unsigned code, unsigned size, unsigned lanes = 1) CPURegister(code,size,kVRegister)317 : CPURegister(code, size, kVRegister), lanes_(lanes) { 318 VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16)); 319 } VRegister(unsigned code,VectorFormat format)320 VRegister(unsigned code, VectorFormat format) 321 : CPURegister(code, RegisterSizeInBitsFromFormat(format), kVRegister), 322 lanes_(IsVectorFormat(format) ? LaneCountFromFormat(format) : 1) { 323 VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16)); 324 } 325 IsValid()326 bool IsValid() const { 327 VIXL_ASSERT(IsVRegister() || IsNone()); 328 return IsValidVRegister(); 329 } 330 331 static const VRegister& GetBRegFromCode(unsigned code); 332 VIXL_DEPRECATED("GetBRegFromCode", 333 static const VRegister& BRegFromCode(unsigned code)) { 334 return GetBRegFromCode(code); 335 } 336 337 static const VRegister& GetHRegFromCode(unsigned code); 338 VIXL_DEPRECATED("GetHRegFromCode", 339 static const VRegister& HRegFromCode(unsigned code)) { 340 return GetHRegFromCode(code); 341 } 342 343 static const VRegister& GetSRegFromCode(unsigned code); 344 VIXL_DEPRECATED("GetSRegFromCode", 345 static const VRegister& SRegFromCode(unsigned code)) { 346 return GetSRegFromCode(code); 347 } 348 349 static const VRegister& GetDRegFromCode(unsigned code); 350 VIXL_DEPRECATED("GetDRegFromCode", 351 static const VRegister& DRegFromCode(unsigned code)) { 352 return GetDRegFromCode(code); 353 } 354 355 static const VRegister& GetQRegFromCode(unsigned code); 356 VIXL_DEPRECATED("GetQRegFromCode", 357 static const VRegister& QRegFromCode(unsigned code)) { 358 return GetQRegFromCode(code); 359 } 360 361 static const VRegister& GetVRegFromCode(unsigned code); 362 VIXL_DEPRECATED("GetVRegFromCode", 363 static const VRegister& VRegFromCode(unsigned code)) { 364 return GetVRegFromCode(code); 365 } 366 V8B()367 VRegister V8B() const { return VRegister(code_, kDRegSize, 8); } V16B()368 VRegister V16B() const { return VRegister(code_, kQRegSize, 16); } V2H()369 VRegister V2H() const { return VRegister(code_, kSRegSize, 2); } V4H()370 VRegister V4H() const { return VRegister(code_, kDRegSize, 4); } V8H()371 VRegister V8H() const { return VRegister(code_, kQRegSize, 8); } V2S()372 VRegister V2S() const { return VRegister(code_, kDRegSize, 2); } V4S()373 VRegister V4S() const { return VRegister(code_, kQRegSize, 4); } V2D()374 VRegister V2D() const { return VRegister(code_, kQRegSize, 2); } V1D()375 VRegister V1D() const { return VRegister(code_, kDRegSize, 1); } 376 Is8B()377 bool Is8B() const { return (Is64Bits() && (lanes_ == 8)); } Is16B()378 bool Is16B() const { return (Is128Bits() && (lanes_ == 16)); } Is2H()379 bool Is2H() const { return (Is32Bits() && (lanes_ == 2)); } Is4H()380 bool Is4H() const { return (Is64Bits() && (lanes_ == 4)); } Is8H()381 bool Is8H() const { return (Is128Bits() && (lanes_ == 8)); } Is1S()382 bool Is1S() const { return (Is32Bits() && (lanes_ == 1)); } Is2S()383 bool Is2S() const { return (Is64Bits() && (lanes_ == 2)); } Is4S()384 bool Is4S() const { return (Is128Bits() && (lanes_ == 4)); } Is1D()385 bool Is1D() const { return (Is64Bits() && (lanes_ == 1)); } Is2D()386 bool Is2D() const { return (Is128Bits() && (lanes_ == 2)); } 387 388 // For consistency, we assert the number of lanes of these scalar registers, 389 // even though there are no vectors of equivalent total size with which they 390 // could alias. Is1B()391 bool Is1B() const { 392 VIXL_ASSERT(!(Is8Bits() && IsVector())); 393 return Is8Bits(); 394 } Is1H()395 bool Is1H() const { 396 VIXL_ASSERT(!(Is16Bits() && IsVector())); 397 return Is16Bits(); 398 } 399 400 // Semantic type for sdot and udot instructions. Is1S4B()401 bool Is1S4B() const { return Is1S(); } 402 403 IsLaneSizeB()404 bool IsLaneSizeB() const { return GetLaneSizeInBits() == kBRegSize; } IsLaneSizeH()405 bool IsLaneSizeH() const { return GetLaneSizeInBits() == kHRegSize; } IsLaneSizeS()406 bool IsLaneSizeS() const { return GetLaneSizeInBits() == kSRegSize; } IsLaneSizeD()407 bool IsLaneSizeD() const { return GetLaneSizeInBits() == kDRegSize; } 408 GetLanes()409 int GetLanes() const { return lanes_; } lanes()410 VIXL_DEPRECATED("GetLanes", int lanes() const) { return GetLanes(); } 411 IsFPRegister()412 bool IsFPRegister() const { return Is1H() || Is1S() || Is1D(); } IsValidFPRegister()413 bool IsValidFPRegister() const { 414 return IsValidVRegister() && IsFPRegister(); 415 } 416 IsScalar()417 bool IsScalar() const { return lanes_ == 1; } 418 IsVector()419 bool IsVector() const { return lanes_ > 1; } 420 IsSameFormat(const VRegister & other)421 bool IsSameFormat(const VRegister& other) const { 422 return (size_ == other.size_) && (lanes_ == other.lanes_); 423 } 424 GetLaneSizeInBytes()425 unsigned GetLaneSizeInBytes() const { return GetSizeInBytes() / lanes_; } LaneSizeInBytes()426 VIXL_DEPRECATED("GetLaneSizeInBytes", unsigned LaneSizeInBytes() const) { 427 return GetLaneSizeInBytes(); 428 } 429 GetLaneSizeInBits()430 unsigned GetLaneSizeInBits() const { return GetLaneSizeInBytes() * 8; } LaneSizeInBits()431 VIXL_DEPRECATED("GetLaneSizeInBits", unsigned LaneSizeInBits() const) { 432 return GetLaneSizeInBits(); 433 } 434 435 private: 436 static const VRegister bregisters[]; 437 static const VRegister hregisters[]; 438 static const VRegister sregisters[]; 439 static const VRegister dregisters[]; 440 static const VRegister qregisters[]; 441 static const VRegister vregisters[]; 442 int lanes_; 443 }; 444 445 446 // No*Reg is used to indicate an unused argument, or an error case. Note that 447 // these all compare equal (using the Is() method). The Register and VRegister 448 // variants are provided for convenience. 449 const Register NoReg; 450 const VRegister NoVReg; 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()) && IncludesAliasOf(other.GetCode()); 708 } 709 IncludesAliasOf(int code)710 bool IncludesAliasOf(int code) const { 711 VIXL_ASSERT(IsValid()); 712 return (((static_cast<RegList>(1) << 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 // In assembly syntax, MemOperands are normally denoted by one or more elements 848 // inside or around square brackets. 849 class MemOperand { 850 public: 851 // Creates an invalid `MemOperand`. 852 MemOperand(); 853 explicit MemOperand(Register base, 854 int64_t offset = 0, 855 AddrMode addrmode = Offset); 856 MemOperand(Register base, 857 Register regoffset, 858 Shift shift = LSL, 859 unsigned shift_amount = 0); 860 MemOperand(Register base, 861 Register regoffset, 862 Extend extend, 863 unsigned shift_amount = 0); 864 MemOperand(Register base, const Operand& offset, AddrMode addrmode = Offset); 865 GetBaseRegister()866 const Register& GetBaseRegister() const { return base_; } 867 868 // If the MemOperand has a register offset, return it. (This also applies to 869 // pre- and post-index modes.) Otherwise, return NoReg. GetRegisterOffset()870 const Register& GetRegisterOffset() const { return regoffset_; } 871 872 // If the MemOperand has an immediate offset, return it. (This also applies to 873 // pre- and post-index modes.) Otherwise, return 0. GetOffset()874 int64_t GetOffset() const { return offset_; } 875 GetAddrMode()876 AddrMode GetAddrMode() const { return addrmode_; } GetShift()877 Shift GetShift() const { return shift_; } GetExtend()878 Extend GetExtend() const { return extend_; } 879 GetShiftAmount()880 unsigned GetShiftAmount() const { 881 // Extend modes can also encode a shift for some instructions. 882 VIXL_ASSERT((GetShift() != NO_SHIFT) || (GetExtend() != NO_EXTEND)); 883 return shift_amount_; 884 } 885 886 // True for immediate-offset (but not indexed) MemOperands. 887 bool IsImmediateOffset() const; 888 // True for register-offset (but not indexed) MemOperands. 889 bool IsRegisterOffset() const; 890 891 bool IsPreIndex() const; 892 bool IsPostIndex() const; 893 894 void AddOffset(int64_t offset); 895 IsValid()896 bool IsValid() const { 897 return base_.IsValid() && 898 ((addrmode_ == Offset) || (addrmode_ == PreIndex) || 899 (addrmode_ == PostIndex)) && 900 ((shift_ == NO_SHIFT) || (extend_ == NO_EXTEND)) && 901 ((offset_ == 0) || !regoffset_.IsValid()); 902 } 903 Equals(const MemOperand & other)904 bool Equals(const MemOperand& other) const { 905 return base_.Is(other.base_) && regoffset_.Is(other.regoffset_) && 906 (offset_ == other.offset_) && (addrmode_ == other.addrmode_) && 907 (shift_ == other.shift_) && (extend_ == other.extend_) && 908 (shift_amount_ == other.shift_amount_); 909 } 910 911 private: 912 Register base_; 913 Register regoffset_; 914 int64_t offset_; 915 AddrMode addrmode_; 916 Shift shift_; 917 Extend extend_; 918 unsigned shift_amount_; 919 }; 920 921 // This an abstraction that can represent a register or memory location. The 922 // `MacroAssembler` provides helpers to move data between generic operands. 923 class GenericOperand { 924 public: GenericOperand()925 GenericOperand() { VIXL_ASSERT(!IsValid()); } 926 GenericOperand(const CPURegister& reg); // NOLINT(runtime/explicit) 927 GenericOperand(const MemOperand& mem_op, 928 size_t mem_op_size = 0); // NOLINT(runtime/explicit) 929 IsValid()930 bool IsValid() const { return cpu_register_.IsValid() != mem_op_.IsValid(); } 931 932 bool Equals(const GenericOperand& other) const; 933 IsCPURegister()934 bool IsCPURegister() const { 935 VIXL_ASSERT(IsValid()); 936 return cpu_register_.IsValid(); 937 } 938 IsRegister()939 bool IsRegister() const { 940 return IsCPURegister() && cpu_register_.IsRegister(); 941 } 942 IsVRegister()943 bool IsVRegister() const { 944 return IsCPURegister() && cpu_register_.IsVRegister(); 945 } 946 IsSameCPURegisterType(const GenericOperand & other)947 bool IsSameCPURegisterType(const GenericOperand& other) { 948 return IsCPURegister() && other.IsCPURegister() && 949 GetCPURegister().IsSameType(other.GetCPURegister()); 950 } 951 IsMemOperand()952 bool IsMemOperand() const { 953 VIXL_ASSERT(IsValid()); 954 return mem_op_.IsValid(); 955 } 956 GetCPURegister()957 CPURegister GetCPURegister() const { 958 VIXL_ASSERT(IsCPURegister()); 959 return cpu_register_; 960 } 961 GetMemOperand()962 MemOperand GetMemOperand() const { 963 VIXL_ASSERT(IsMemOperand()); 964 return mem_op_; 965 } 966 GetMemOperandSizeInBytes()967 size_t GetMemOperandSizeInBytes() const { 968 VIXL_ASSERT(IsMemOperand()); 969 return mem_op_size_; 970 } 971 GetSizeInBytes()972 size_t GetSizeInBytes() const { 973 return IsCPURegister() ? cpu_register_.GetSizeInBytes() 974 : GetMemOperandSizeInBytes(); 975 } 976 GetSizeInBits()977 size_t GetSizeInBits() const { return GetSizeInBytes() * kBitsPerByte; } 978 979 private: 980 CPURegister cpu_register_; 981 MemOperand mem_op_; 982 // The size of the memory region pointed to, in bytes. 983 // We only support sizes up to X/D register sizes. 984 size_t mem_op_size_; 985 }; 986 } 987 } // namespace vixl::aarch64 988 989 #endif // VIXL_AARCH64_OPERANDS_AARCH64_H_ 990