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 #include "operands-aarch64.h" 28 29 namespace vixl { 30 namespace aarch64 { 31 32 // CPURegList utilities. 33 CPURegister CPURegList::PopLowestIndex() { 34 if (IsEmpty()) { 35 return NoCPUReg; 36 } 37 int index = CountTrailingZeros(list_); 38 VIXL_ASSERT((1 << index) & list_); 39 Remove(index); 40 return CPURegister(index, size_, type_); 41 } 42 43 44 CPURegister CPURegList::PopHighestIndex() { 45 VIXL_ASSERT(IsValid()); 46 if (IsEmpty()) { 47 return NoCPUReg; 48 } 49 int index = CountLeadingZeros(list_); 50 index = kRegListSizeInBits - 1 - index; 51 VIXL_ASSERT((1 << index) & list_); 52 Remove(index); 53 return CPURegister(index, size_, type_); 54 } 55 56 57 bool CPURegList::IsValid() const { 58 if ((type_ == CPURegister::kRegister) || (type_ == CPURegister::kVRegister)) { 59 bool is_valid = true; 60 // Try to create a CPURegister for each element in the list. 61 for (int i = 0; i < kRegListSizeInBits; i++) { 62 if (((list_ >> i) & 1) != 0) { 63 is_valid &= CPURegister(i, size_, type_).IsValid(); 64 } 65 } 66 return is_valid; 67 } else if (type_ == CPURegister::kNoRegister) { 68 // We can't use IsEmpty here because that asserts IsValid(). 69 return list_ == 0; 70 } else { 71 return false; 72 } 73 } 74 75 76 void CPURegList::RemoveCalleeSaved() { 77 if (GetType() == CPURegister::kRegister) { 78 Remove(GetCalleeSaved(GetRegisterSizeInBits())); 79 } else if (GetType() == CPURegister::kVRegister) { 80 Remove(GetCalleeSavedV(GetRegisterSizeInBits())); 81 } else { 82 VIXL_ASSERT(GetType() == CPURegister::kNoRegister); 83 VIXL_ASSERT(IsEmpty()); 84 // The list must already be empty, so do nothing. 85 } 86 } 87 88 89 CPURegList CPURegList::Union(const CPURegList& list_1, 90 const CPURegList& list_2, 91 const CPURegList& list_3) { 92 return Union(list_1, Union(list_2, list_3)); 93 } 94 95 96 CPURegList CPURegList::Union(const CPURegList& list_1, 97 const CPURegList& list_2, 98 const CPURegList& list_3, 99 const CPURegList& list_4) { 100 return Union(Union(list_1, list_2), Union(list_3, list_4)); 101 } 102 103 104 CPURegList CPURegList::Intersection(const CPURegList& list_1, 105 const CPURegList& list_2, 106 const CPURegList& list_3) { 107 return Intersection(list_1, Intersection(list_2, list_3)); 108 } 109 110 111 CPURegList CPURegList::Intersection(const CPURegList& list_1, 112 const CPURegList& list_2, 113 const CPURegList& list_3, 114 const CPURegList& list_4) { 115 return Intersection(Intersection(list_1, list_2), 116 Intersection(list_3, list_4)); 117 } 118 119 120 CPURegList CPURegList::GetCalleeSaved(unsigned size) { 121 return CPURegList(CPURegister::kRegister, size, 19, 29); 122 } 123 124 125 CPURegList CPURegList::GetCalleeSavedV(unsigned size) { 126 return CPURegList(CPURegister::kVRegister, size, 8, 15); 127 } 128 129 130 CPURegList CPURegList::GetCallerSaved(unsigned size) { 131 // Registers x0-x18 and lr (x30) are caller-saved. 132 CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 18); 133 // Do not use lr directly to avoid initialisation order fiasco bugs for users. 134 list.Combine(Register(30, kXRegSize)); 135 return list; 136 } 137 138 139 CPURegList CPURegList::GetCallerSavedV(unsigned size) { 140 // Registers d0-d7 and d16-d31 are caller-saved. 141 CPURegList list = CPURegList(CPURegister::kVRegister, size, 0, 7); 142 list.Combine(CPURegList(CPURegister::kVRegister, size, 16, 31)); 143 return list; 144 } 145 146 147 const CPURegList kCalleeSaved = CPURegList::GetCalleeSaved(); 148 const CPURegList kCalleeSavedV = CPURegList::GetCalleeSavedV(); 149 const CPURegList kCallerSaved = CPURegList::GetCallerSaved(); 150 const CPURegList kCallerSavedV = CPURegList::GetCallerSavedV(); 151 152 153 // Registers. 154 #define WREG(n) w##n, 155 const Register Register::wregisters[] = {AARCH64_REGISTER_CODE_LIST(WREG)}; 156 #undef WREG 157 158 #define XREG(n) x##n, 159 const Register Register::xregisters[] = {AARCH64_REGISTER_CODE_LIST(XREG)}; 160 #undef XREG 161 162 #define BREG(n) b##n, 163 const VRegister VRegister::bregisters[] = {AARCH64_REGISTER_CODE_LIST(BREG)}; 164 #undef BREG 165 166 #define HREG(n) h##n, 167 const VRegister VRegister::hregisters[] = {AARCH64_REGISTER_CODE_LIST(HREG)}; 168 #undef HREG 169 170 #define SREG(n) s##n, 171 const VRegister VRegister::sregisters[] = {AARCH64_REGISTER_CODE_LIST(SREG)}; 172 #undef SREG 173 174 #define DREG(n) d##n, 175 const VRegister VRegister::dregisters[] = {AARCH64_REGISTER_CODE_LIST(DREG)}; 176 #undef DREG 177 178 #define QREG(n) q##n, 179 const VRegister VRegister::qregisters[] = {AARCH64_REGISTER_CODE_LIST(QREG)}; 180 #undef QREG 181 182 #define VREG(n) v##n, 183 const VRegister VRegister::vregisters[] = {AARCH64_REGISTER_CODE_LIST(VREG)}; 184 #undef VREG 185 186 187 const Register& Register::GetWRegFromCode(unsigned code) { 188 if (code == kSPRegInternalCode) { 189 return wsp; 190 } else { 191 VIXL_ASSERT(code < kNumberOfRegisters); 192 return wregisters[code]; 193 } 194 } 195 196 197 const Register& Register::GetXRegFromCode(unsigned code) { 198 if (code == kSPRegInternalCode) { 199 return sp; 200 } else { 201 VIXL_ASSERT(code < kNumberOfRegisters); 202 return xregisters[code]; 203 } 204 } 205 206 207 const VRegister& VRegister::GetBRegFromCode(unsigned code) { 208 VIXL_ASSERT(code < kNumberOfVRegisters); 209 return bregisters[code]; 210 } 211 212 213 const VRegister& VRegister::GetHRegFromCode(unsigned code) { 214 VIXL_ASSERT(code < kNumberOfVRegisters); 215 return hregisters[code]; 216 } 217 218 219 const VRegister& VRegister::GetSRegFromCode(unsigned code) { 220 VIXL_ASSERT(code < kNumberOfVRegisters); 221 return sregisters[code]; 222 } 223 224 225 const VRegister& VRegister::GetDRegFromCode(unsigned code) { 226 VIXL_ASSERT(code < kNumberOfVRegisters); 227 return dregisters[code]; 228 } 229 230 231 const VRegister& VRegister::GetQRegFromCode(unsigned code) { 232 VIXL_ASSERT(code < kNumberOfVRegisters); 233 return qregisters[code]; 234 } 235 236 237 const VRegister& VRegister::GetVRegFromCode(unsigned code) { 238 VIXL_ASSERT(code < kNumberOfVRegisters); 239 return vregisters[code]; 240 } 241 242 243 const Register& CPURegister::W() const { 244 VIXL_ASSERT(IsValidRegister()); 245 return Register::GetWRegFromCode(code_); 246 } 247 248 249 const Register& CPURegister::X() const { 250 VIXL_ASSERT(IsValidRegister()); 251 return Register::GetXRegFromCode(code_); 252 } 253 254 255 const VRegister& CPURegister::B() const { 256 VIXL_ASSERT(IsValidVRegister()); 257 return VRegister::GetBRegFromCode(code_); 258 } 259 260 261 const VRegister& CPURegister::H() const { 262 VIXL_ASSERT(IsValidVRegister()); 263 return VRegister::GetHRegFromCode(code_); 264 } 265 266 267 const VRegister& CPURegister::S() const { 268 VIXL_ASSERT(IsValidVRegister()); 269 return VRegister::GetSRegFromCode(code_); 270 } 271 272 273 const VRegister& CPURegister::D() const { 274 VIXL_ASSERT(IsValidVRegister()); 275 return VRegister::GetDRegFromCode(code_); 276 } 277 278 279 const VRegister& CPURegister::Q() const { 280 VIXL_ASSERT(IsValidVRegister()); 281 return VRegister::GetQRegFromCode(code_); 282 } 283 284 285 const VRegister& CPURegister::V() const { 286 VIXL_ASSERT(IsValidVRegister()); 287 return VRegister::GetVRegFromCode(code_); 288 } 289 290 291 // Operand. 292 Operand::Operand(int64_t immediate) 293 : immediate_(immediate), 294 reg_(NoReg), 295 shift_(NO_SHIFT), 296 extend_(NO_EXTEND), 297 shift_amount_(0) {} 298 299 300 Operand::Operand(Register reg, Shift shift, unsigned shift_amount) 301 : reg_(reg), 302 shift_(shift), 303 extend_(NO_EXTEND), 304 shift_amount_(shift_amount) { 305 VIXL_ASSERT(shift != MSL); 306 VIXL_ASSERT(reg.Is64Bits() || (shift_amount < kWRegSize)); 307 VIXL_ASSERT(reg.Is32Bits() || (shift_amount < kXRegSize)); 308 VIXL_ASSERT(!reg.IsSP()); 309 } 310 311 312 Operand::Operand(Register reg, Extend extend, unsigned shift_amount) 313 : reg_(reg), 314 shift_(NO_SHIFT), 315 extend_(extend), 316 shift_amount_(shift_amount) { 317 VIXL_ASSERT(reg.IsValid()); 318 VIXL_ASSERT(shift_amount <= 4); 319 VIXL_ASSERT(!reg.IsSP()); 320 321 // Extend modes SXTX and UXTX require a 64-bit register. 322 VIXL_ASSERT(reg.Is64Bits() || ((extend != SXTX) && (extend != UXTX))); 323 } 324 325 326 bool Operand::IsImmediate() const { return reg_.Is(NoReg); } 327 328 329 bool Operand::IsPlainRegister() const { 330 return reg_.IsValid() && 331 (((shift_ == NO_SHIFT) && (extend_ == NO_EXTEND)) || 332 // No-op shifts. 333 ((shift_ != NO_SHIFT) && (shift_amount_ == 0)) || 334 // No-op extend operations. 335 ((extend_ == UXTX) || (extend_ == SXTX) || 336 (reg_.IsW() && ((extend_ == UXTW) || (extend_ == SXTW))))); 337 } 338 339 340 bool Operand::IsShiftedRegister() const { 341 return reg_.IsValid() && (shift_ != NO_SHIFT); 342 } 343 344 345 bool Operand::IsExtendedRegister() const { 346 return reg_.IsValid() && (extend_ != NO_EXTEND); 347 } 348 349 350 bool Operand::IsZero() const { 351 if (IsImmediate()) { 352 return GetImmediate() == 0; 353 } else { 354 return GetRegister().IsZero(); 355 } 356 } 357 358 359 Operand Operand::ToExtendedRegister() const { 360 VIXL_ASSERT(IsShiftedRegister()); 361 VIXL_ASSERT((shift_ == LSL) && (shift_amount_ <= 4)); 362 return Operand(reg_, reg_.Is64Bits() ? UXTX : UXTW, shift_amount_); 363 } 364 365 366 // MemOperand 367 MemOperand::MemOperand() 368 : base_(NoReg), 369 regoffset_(NoReg), 370 offset_(0), 371 addrmode_(Offset), 372 shift_(NO_SHIFT), 373 extend_(NO_EXTEND) {} 374 375 376 MemOperand::MemOperand(Register base, int64_t offset, AddrMode addrmode) 377 : base_(base), 378 regoffset_(NoReg), 379 offset_(offset), 380 addrmode_(addrmode), 381 shift_(NO_SHIFT), 382 extend_(NO_EXTEND), 383 shift_amount_(0) { 384 VIXL_ASSERT(base.Is64Bits() && !base.IsZero()); 385 } 386 387 388 MemOperand::MemOperand(Register base, 389 Register regoffset, 390 Extend extend, 391 unsigned shift_amount) 392 : base_(base), 393 regoffset_(regoffset), 394 offset_(0), 395 addrmode_(Offset), 396 shift_(NO_SHIFT), 397 extend_(extend), 398 shift_amount_(shift_amount) { 399 VIXL_ASSERT(base.Is64Bits() && !base.IsZero()); 400 VIXL_ASSERT(!regoffset.IsSP()); 401 VIXL_ASSERT((extend == UXTW) || (extend == SXTW) || (extend == SXTX)); 402 403 // SXTX extend mode requires a 64-bit offset register. 404 VIXL_ASSERT(regoffset.Is64Bits() || (extend != SXTX)); 405 } 406 407 408 MemOperand::MemOperand(Register base, 409 Register regoffset, 410 Shift shift, 411 unsigned shift_amount) 412 : base_(base), 413 regoffset_(regoffset), 414 offset_(0), 415 addrmode_(Offset), 416 shift_(shift), 417 extend_(NO_EXTEND), 418 shift_amount_(shift_amount) { 419 VIXL_ASSERT(base.Is64Bits() && !base.IsZero()); 420 VIXL_ASSERT(regoffset.Is64Bits() && !regoffset.IsSP()); 421 VIXL_ASSERT(shift == LSL); 422 } 423 424 425 MemOperand::MemOperand(Register base, const Operand& offset, AddrMode addrmode) 426 : base_(base), 427 regoffset_(NoReg), 428 addrmode_(addrmode), 429 shift_(NO_SHIFT), 430 extend_(NO_EXTEND), 431 shift_amount_(0) { 432 VIXL_ASSERT(base.Is64Bits() && !base.IsZero()); 433 434 if (offset.IsImmediate()) { 435 offset_ = offset.GetImmediate(); 436 } else if (offset.IsShiftedRegister()) { 437 VIXL_ASSERT((addrmode == Offset) || (addrmode == PostIndex)); 438 439 regoffset_ = offset.GetRegister(); 440 shift_ = offset.GetShift(); 441 shift_amount_ = offset.GetShiftAmount(); 442 443 extend_ = NO_EXTEND; 444 offset_ = 0; 445 446 // These assertions match those in the shifted-register constructor. 447 VIXL_ASSERT(regoffset_.Is64Bits() && !regoffset_.IsSP()); 448 VIXL_ASSERT(shift_ == LSL); 449 } else { 450 VIXL_ASSERT(offset.IsExtendedRegister()); 451 VIXL_ASSERT(addrmode == Offset); 452 453 regoffset_ = offset.GetRegister(); 454 extend_ = offset.GetExtend(); 455 shift_amount_ = offset.GetShiftAmount(); 456 457 shift_ = NO_SHIFT; 458 offset_ = 0; 459 460 // These assertions match those in the extended-register constructor. 461 VIXL_ASSERT(!regoffset_.IsSP()); 462 VIXL_ASSERT((extend_ == UXTW) || (extend_ == SXTW) || (extend_ == SXTX)); 463 VIXL_ASSERT((regoffset_.Is64Bits() || (extend_ != SXTX))); 464 } 465 } 466 467 468 bool MemOperand::IsImmediateOffset() const { 469 return (addrmode_ == Offset) && regoffset_.Is(NoReg); 470 } 471 472 473 bool MemOperand::IsRegisterOffset() const { 474 return (addrmode_ == Offset) && !regoffset_.Is(NoReg); 475 } 476 477 478 bool MemOperand::IsPreIndex() const { return addrmode_ == PreIndex; } 479 480 481 bool MemOperand::IsPostIndex() const { return addrmode_ == PostIndex; } 482 483 484 void MemOperand::AddOffset(int64_t offset) { 485 VIXL_ASSERT(IsImmediateOffset()); 486 offset_ += offset; 487 } 488 489 490 GenericOperand::GenericOperand(const CPURegister& reg) 491 : cpu_register_(reg), mem_op_size_(0) { 492 if (reg.IsQ()) { 493 VIXL_ASSERT(reg.GetSizeInBits() > static_cast<int>(kXRegSize)); 494 // Support for Q registers is not implemented yet. 495 VIXL_UNIMPLEMENTED(); 496 } 497 } 498 499 500 GenericOperand::GenericOperand(const MemOperand& mem_op, size_t mem_op_size) 501 : cpu_register_(NoReg), mem_op_(mem_op), mem_op_size_(mem_op_size) { 502 if (mem_op_size_ > kXRegSizeInBytes) { 503 // We only support generic operands up to the size of X registers. 504 VIXL_UNIMPLEMENTED(); 505 } 506 } 507 508 bool GenericOperand::Equals(const GenericOperand& other) const { 509 if (!IsValid() || !other.IsValid()) { 510 // Two invalid generic operands are considered equal. 511 return !IsValid() && !other.IsValid(); 512 } 513 if (IsCPURegister() && other.IsCPURegister()) { 514 return GetCPURegister().Is(other.GetCPURegister()); 515 } else if (IsMemOperand() && other.IsMemOperand()) { 516 return GetMemOperand().Equals(other.GetMemOperand()) && 517 (GetMemOperandSizeInBytes() == other.GetMemOperandSizeInBytes()); 518 } 519 return false; 520 } 521 } 522 } // namespace vixl::aarch64 523