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 29namespace vixl { 30namespace aarch64 { 31 32// CPURegList utilities. 33CPURegister 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 44CPURegister 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 57bool 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 76void 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 89CPURegList 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 96CPURegList 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 104CPURegList 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 111CPURegList 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 120CPURegList CPURegList::GetCalleeSaved(unsigned size) { 121 return CPURegList(CPURegister::kRegister, size, 19, 29); 122} 123 124 125CPURegList CPURegList::GetCalleeSavedV(unsigned size) { 126 return CPURegList(CPURegister::kVRegister, size, 8, 15); 127} 128 129 130CPURegList 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 139CPURegList 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 147const CPURegList kCalleeSaved = CPURegList::GetCalleeSaved(); 148const CPURegList kCalleeSavedV = CPURegList::GetCalleeSavedV(); 149const CPURegList kCallerSaved = CPURegList::GetCallerSaved(); 150const CPURegList kCallerSavedV = CPURegList::GetCallerSavedV(); 151 152 153// Registers. 154#define WREG(n) w##n, 155const Register Register::wregisters[] = {AARCH64_REGISTER_CODE_LIST(WREG)}; 156#undef WREG 157 158#define XREG(n) x##n, 159const Register Register::xregisters[] = {AARCH64_REGISTER_CODE_LIST(XREG)}; 160#undef XREG 161 162#define BREG(n) b##n, 163const VRegister VRegister::bregisters[] = {AARCH64_REGISTER_CODE_LIST(BREG)}; 164#undef BREG 165 166#define HREG(n) h##n, 167const VRegister VRegister::hregisters[] = {AARCH64_REGISTER_CODE_LIST(HREG)}; 168#undef HREG 169 170#define SREG(n) s##n, 171const VRegister VRegister::sregisters[] = {AARCH64_REGISTER_CODE_LIST(SREG)}; 172#undef SREG 173 174#define DREG(n) d##n, 175const VRegister VRegister::dregisters[] = {AARCH64_REGISTER_CODE_LIST(DREG)}; 176#undef DREG 177 178#define QREG(n) q##n, 179const VRegister VRegister::qregisters[] = {AARCH64_REGISTER_CODE_LIST(QREG)}; 180#undef QREG 181 182#define VREG(n) v##n, 183const VRegister VRegister::vregisters[] = {AARCH64_REGISTER_CODE_LIST(VREG)}; 184#undef VREG 185 186 187const 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 197const 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 207const VRegister& VRegister::GetBRegFromCode(unsigned code) { 208 VIXL_ASSERT(code < kNumberOfVRegisters); 209 return bregisters[code]; 210} 211 212 213const VRegister& VRegister::GetHRegFromCode(unsigned code) { 214 VIXL_ASSERT(code < kNumberOfVRegisters); 215 return hregisters[code]; 216} 217 218 219const VRegister& VRegister::GetSRegFromCode(unsigned code) { 220 VIXL_ASSERT(code < kNumberOfVRegisters); 221 return sregisters[code]; 222} 223 224 225const VRegister& VRegister::GetDRegFromCode(unsigned code) { 226 VIXL_ASSERT(code < kNumberOfVRegisters); 227 return dregisters[code]; 228} 229 230 231const VRegister& VRegister::GetQRegFromCode(unsigned code) { 232 VIXL_ASSERT(code < kNumberOfVRegisters); 233 return qregisters[code]; 234} 235 236 237const VRegister& VRegister::GetVRegFromCode(unsigned code) { 238 VIXL_ASSERT(code < kNumberOfVRegisters); 239 return vregisters[code]; 240} 241 242 243const Register& CPURegister::W() const { 244 VIXL_ASSERT(IsValidRegister()); 245 return Register::GetWRegFromCode(code_); 246} 247 248 249const Register& CPURegister::X() const { 250 VIXL_ASSERT(IsValidRegister()); 251 return Register::GetXRegFromCode(code_); 252} 253 254 255const VRegister& CPURegister::B() const { 256 VIXL_ASSERT(IsValidVRegister()); 257 return VRegister::GetBRegFromCode(code_); 258} 259 260 261const VRegister& CPURegister::H() const { 262 VIXL_ASSERT(IsValidVRegister()); 263 return VRegister::GetHRegFromCode(code_); 264} 265 266 267const VRegister& CPURegister::S() const { 268 VIXL_ASSERT(IsValidVRegister()); 269 return VRegister::GetSRegFromCode(code_); 270} 271 272 273const VRegister& CPURegister::D() const { 274 VIXL_ASSERT(IsValidVRegister()); 275 return VRegister::GetDRegFromCode(code_); 276} 277 278 279const VRegister& CPURegister::Q() const { 280 VIXL_ASSERT(IsValidVRegister()); 281 return VRegister::GetQRegFromCode(code_); 282} 283 284 285const VRegister& CPURegister::V() const { 286 VIXL_ASSERT(IsValidVRegister()); 287 return VRegister::GetVRegFromCode(code_); 288} 289 290 291// Operand. 292Operand::Operand(int64_t immediate) 293 : immediate_(immediate), 294 reg_(NoReg), 295 shift_(NO_SHIFT), 296 extend_(NO_EXTEND), 297 shift_amount_(0) {} 298 299 300Operand::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 312Operand::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 326bool Operand::IsImmediate() const { return reg_.Is(NoReg); } 327 328 329bool 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 // We can't include [US]XTW here without knowing more about the 336 // context; they are only no-ops for 32-bit operations. 337 // 338 // For example, this operand could be replaced with w1: 339 // __ Add(w0, w0, Operand(w1, UXTW)); 340 // However, no plain register can replace it in this context: 341 // __ Add(x0, x0, Operand(w1, UXTW)); 342 (((extend_ == UXTX) || (extend_ == SXTX)) && (shift_amount_ == 0))); 343} 344 345 346bool Operand::IsShiftedRegister() const { 347 return reg_.IsValid() && (shift_ != NO_SHIFT); 348} 349 350 351bool Operand::IsExtendedRegister() const { 352 return reg_.IsValid() && (extend_ != NO_EXTEND); 353} 354 355 356bool Operand::IsZero() const { 357 if (IsImmediate()) { 358 return GetImmediate() == 0; 359 } else { 360 return GetRegister().IsZero(); 361 } 362} 363 364 365Operand Operand::ToExtendedRegister() const { 366 VIXL_ASSERT(IsShiftedRegister()); 367 VIXL_ASSERT((shift_ == LSL) && (shift_amount_ <= 4)); 368 return Operand(reg_, reg_.Is64Bits() ? UXTX : UXTW, shift_amount_); 369} 370 371 372// MemOperand 373MemOperand::MemOperand() 374 : base_(NoReg), 375 regoffset_(NoReg), 376 offset_(0), 377 addrmode_(Offset), 378 shift_(NO_SHIFT), 379 extend_(NO_EXTEND) {} 380 381 382MemOperand::MemOperand(Register base, int64_t offset, AddrMode addrmode) 383 : base_(base), 384 regoffset_(NoReg), 385 offset_(offset), 386 addrmode_(addrmode), 387 shift_(NO_SHIFT), 388 extend_(NO_EXTEND), 389 shift_amount_(0) { 390 VIXL_ASSERT(base.Is64Bits() && !base.IsZero()); 391} 392 393 394MemOperand::MemOperand(Register base, 395 Register regoffset, 396 Extend extend, 397 unsigned shift_amount) 398 : base_(base), 399 regoffset_(regoffset), 400 offset_(0), 401 addrmode_(Offset), 402 shift_(NO_SHIFT), 403 extend_(extend), 404 shift_amount_(shift_amount) { 405 VIXL_ASSERT(base.Is64Bits() && !base.IsZero()); 406 VIXL_ASSERT(!regoffset.IsSP()); 407 VIXL_ASSERT((extend == UXTW) || (extend == SXTW) || (extend == SXTX)); 408 409 // SXTX extend mode requires a 64-bit offset register. 410 VIXL_ASSERT(regoffset.Is64Bits() || (extend != SXTX)); 411} 412 413 414MemOperand::MemOperand(Register base, 415 Register regoffset, 416 Shift shift, 417 unsigned shift_amount) 418 : base_(base), 419 regoffset_(regoffset), 420 offset_(0), 421 addrmode_(Offset), 422 shift_(shift), 423 extend_(NO_EXTEND), 424 shift_amount_(shift_amount) { 425 VIXL_ASSERT(base.Is64Bits() && !base.IsZero()); 426 VIXL_ASSERT(regoffset.Is64Bits() && !regoffset.IsSP()); 427 VIXL_ASSERT(shift == LSL); 428} 429 430 431MemOperand::MemOperand(Register base, const Operand& offset, AddrMode addrmode) 432 : base_(base), 433 regoffset_(NoReg), 434 addrmode_(addrmode), 435 shift_(NO_SHIFT), 436 extend_(NO_EXTEND), 437 shift_amount_(0) { 438 VIXL_ASSERT(base.Is64Bits() && !base.IsZero()); 439 440 if (offset.IsImmediate()) { 441 offset_ = offset.GetImmediate(); 442 } else if (offset.IsShiftedRegister()) { 443 VIXL_ASSERT((addrmode == Offset) || (addrmode == PostIndex)); 444 445 regoffset_ = offset.GetRegister(); 446 shift_ = offset.GetShift(); 447 shift_amount_ = offset.GetShiftAmount(); 448 449 extend_ = NO_EXTEND; 450 offset_ = 0; 451 452 // These assertions match those in the shifted-register constructor. 453 VIXL_ASSERT(regoffset_.Is64Bits() && !regoffset_.IsSP()); 454 VIXL_ASSERT(shift_ == LSL); 455 } else { 456 VIXL_ASSERT(offset.IsExtendedRegister()); 457 VIXL_ASSERT(addrmode == Offset); 458 459 regoffset_ = offset.GetRegister(); 460 extend_ = offset.GetExtend(); 461 shift_amount_ = offset.GetShiftAmount(); 462 463 shift_ = NO_SHIFT; 464 offset_ = 0; 465 466 // These assertions match those in the extended-register constructor. 467 VIXL_ASSERT(!regoffset_.IsSP()); 468 VIXL_ASSERT((extend_ == UXTW) || (extend_ == SXTW) || (extend_ == SXTX)); 469 VIXL_ASSERT((regoffset_.Is64Bits() || (extend_ != SXTX))); 470 } 471} 472 473 474bool MemOperand::IsImmediateOffset() const { 475 return (addrmode_ == Offset) && regoffset_.Is(NoReg); 476} 477 478 479bool MemOperand::IsRegisterOffset() const { 480 return (addrmode_ == Offset) && !regoffset_.Is(NoReg); 481} 482 483 484bool MemOperand::IsPreIndex() const { return addrmode_ == PreIndex; } 485 486 487bool MemOperand::IsPostIndex() const { return addrmode_ == PostIndex; } 488 489 490void MemOperand::AddOffset(int64_t offset) { 491 VIXL_ASSERT(IsImmediateOffset()); 492 offset_ += offset; 493} 494 495 496GenericOperand::GenericOperand(const CPURegister& reg) 497 : cpu_register_(reg), mem_op_size_(0) { 498 if (reg.IsQ()) { 499 VIXL_ASSERT(reg.GetSizeInBits() > static_cast<int>(kXRegSize)); 500 // Support for Q registers is not implemented yet. 501 VIXL_UNIMPLEMENTED(); 502 } 503} 504 505 506GenericOperand::GenericOperand(const MemOperand& mem_op, size_t mem_op_size) 507 : cpu_register_(NoReg), mem_op_(mem_op), mem_op_size_(mem_op_size) { 508 if (mem_op_size_ > kXRegSizeInBytes) { 509 // We only support generic operands up to the size of X registers. 510 VIXL_UNIMPLEMENTED(); 511 } 512} 513 514bool GenericOperand::Equals(const GenericOperand& other) const { 515 if (!IsValid() || !other.IsValid()) { 516 // Two invalid generic operands are considered equal. 517 return !IsValid() && !other.IsValid(); 518 } 519 if (IsCPURegister() && other.IsCPURegister()) { 520 return GetCPURegister().Is(other.GetCPURegister()); 521 } else if (IsMemOperand() && other.IsMemOperand()) { 522 return GetMemOperand().Equals(other.GetMemOperand()) && 523 (GetMemOperandSizeInBytes() == other.GetMemOperandSizeInBytes()); 524 } 525 return false; 526} 527} 528} // namespace vixl::aarch64 529