1 // Copyright 2018 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_CODEGEN_ARM64_REGISTER_ARM64_H_ 6 #define V8_CODEGEN_ARM64_REGISTER_ARM64_H_ 7 8 #include "src/codegen/arm64/utils-arm64.h" 9 #include "src/codegen/register.h" 10 #include "src/codegen/reglist.h" 11 #include "src/common/globals.h" 12 13 namespace v8 { 14 namespace internal { 15 16 // ----------------------------------------------------------------------------- 17 // Registers. 18 // clang-format off 19 #define GENERAL_REGISTER_CODE_LIST(R) \ 20 R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ 21 R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ 22 R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ 23 R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) 24 25 #define GENERAL_REGISTERS(R) \ 26 R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \ 27 R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \ 28 R(x16) R(x17) R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) \ 29 R(x24) R(x25) R(x26) R(x27) R(x28) R(x29) R(x30) R(x31) 30 31 // x18 is the platform register and is reserved for the use of platform ABIs. 32 // It is known to be reserved by the OS at least on Windows and iOS. 33 #define ALLOCATABLE_GENERAL_REGISTERS(R) \ 34 R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \ 35 R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \ 36 R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x25) \ 37 R(x27) R(x28) 38 39 #define FLOAT_REGISTERS(V) \ 40 V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) \ 41 V(s8) V(s9) V(s10) V(s11) V(s12) V(s13) V(s14) V(s15) \ 42 V(s16) V(s17) V(s18) V(s19) V(s20) V(s21) V(s22) V(s23) \ 43 V(s24) V(s25) V(s26) V(s27) V(s28) V(s29) V(s30) V(s31) 44 45 #define DOUBLE_REGISTERS(R) \ 46 R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \ 47 R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d15) \ 48 R(d16) R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) \ 49 R(d24) R(d25) R(d26) R(d27) R(d28) R(d29) R(d30) R(d31) 50 51 #define SIMD128_REGISTERS(V) \ 52 V(q0) V(q1) V(q2) V(q3) V(q4) V(q5) V(q6) V(q7) \ 53 V(q8) V(q9) V(q10) V(q11) V(q12) V(q13) V(q14) V(q15) \ 54 V(q16) V(q17) V(q18) V(q19) V(q20) V(q21) V(q22) V(q23) \ 55 V(q24) V(q25) V(q26) V(q27) V(q28) V(q29) V(q30) V(q31) 56 57 #define VECTOR_REGISTERS(V) \ 58 V(v0) V(v1) V(v2) V(v3) V(v4) V(v5) V(v6) V(v7) \ 59 V(v8) V(v9) V(v10) V(v11) V(v12) V(v13) V(v14) V(v15) \ 60 V(v16) V(v17) V(v18) V(v19) V(v20) V(v21) V(v22) V(v23) \ 61 V(v24) V(v25) V(v26) V(v27) V(v28) V(v29) V(v30) V(v31) 62 63 // Register d29 could be allocated, but we keep an even length list here, in 64 // order to make stack alignment easier for save and restore. 65 #define ALLOCATABLE_DOUBLE_REGISTERS(R) \ 66 R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \ 67 R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d16) \ 68 R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) R(d24) \ 69 R(d25) R(d26) R(d27) R(d28) 70 // clang-format on 71 72 constexpr int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte; 73 74 // Some CPURegister methods can return Register and VRegister types, so we 75 // need to declare them in advance. 76 class Register; 77 class VRegister; 78 79 enum RegisterCode { 80 #define REGISTER_CODE(R) kRegCode_##R, 81 GENERAL_REGISTERS(REGISTER_CODE) 82 #undef REGISTER_CODE 83 kRegAfterLast 84 }; 85 86 class CPURegister : public RegisterBase<CPURegister, kRegAfterLast> { 87 public: 88 enum RegisterType { kRegister, kVRegister, kNoRegister }; 89 no_reg()90 static constexpr CPURegister no_reg() { 91 return CPURegister{kCode_no_reg, 0, kNoRegister}; 92 } 93 Create(int code,int size,RegisterType type)94 static constexpr CPURegister Create(int code, int size, RegisterType type) { 95 CONSTEXPR_DCHECK(IsValid(code, size, type)); 96 return CPURegister{code, size, type}; 97 } 98 type()99 RegisterType type() const { return reg_type_; } SizeInBits()100 int SizeInBits() const { 101 DCHECK(is_valid()); 102 return reg_size_; 103 } SizeInBytes()104 int SizeInBytes() const { 105 DCHECK(is_valid()); 106 DCHECK_EQ(SizeInBits() % 8, 0); 107 return reg_size_ / 8; 108 } Is8Bits()109 bool Is8Bits() const { 110 DCHECK(is_valid()); 111 return reg_size_ == 8; 112 } Is16Bits()113 bool Is16Bits() const { 114 DCHECK(is_valid()); 115 return reg_size_ == 16; 116 } Is32Bits()117 bool Is32Bits() const { 118 DCHECK(is_valid()); 119 return reg_size_ == 32; 120 } Is64Bits()121 bool Is64Bits() const { 122 DCHECK(is_valid()); 123 return reg_size_ == 64; 124 } Is128Bits()125 bool Is128Bits() const { 126 DCHECK(is_valid()); 127 return reg_size_ == 128; 128 } IsNone()129 bool IsNone() const { return reg_type_ == kNoRegister; } Aliases(const CPURegister & other)130 constexpr bool Aliases(const CPURegister& other) const { 131 return RegisterBase::operator==(other) && reg_type_ == other.reg_type_; 132 } 133 134 constexpr bool operator==(const CPURegister& other) const { 135 return RegisterBase::operator==(other) && reg_size_ == other.reg_size_ && 136 reg_type_ == other.reg_type_; 137 } 138 constexpr bool operator!=(const CPURegister& other) const { 139 return !operator==(other); 140 } 141 142 bool IsZero() const; 143 bool IsSP() const; 144 IsRegister()145 bool IsRegister() const { return reg_type_ == kRegister; } IsVRegister()146 bool IsVRegister() const { return reg_type_ == kVRegister; } 147 IsFPRegister()148 bool IsFPRegister() const { return IsS() || IsD(); } 149 IsW()150 bool IsW() const { return IsRegister() && Is32Bits(); } IsX()151 bool IsX() const { return IsRegister() && Is64Bits(); } 152 153 // These assertions ensure that the size and type of the register are as 154 // described. They do not consider the number of lanes that make up a vector. 155 // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD() 156 // does not imply Is1D() or Is8B(). 157 // Check the number of lanes, ie. the format of the vector, using methods such 158 // as Is8B(), Is1D(), etc. in the VRegister class. IsV()159 bool IsV() const { return IsVRegister(); } IsB()160 bool IsB() const { return IsV() && Is8Bits(); } IsH()161 bool IsH() const { return IsV() && Is16Bits(); } IsS()162 bool IsS() const { return IsV() && Is32Bits(); } IsD()163 bool IsD() const { return IsV() && Is64Bits(); } IsQ()164 bool IsQ() const { return IsV() && Is128Bits(); } 165 166 Register Reg() const; 167 VRegister VReg() const; 168 169 Register X() const; 170 Register W() const; 171 VRegister V() const; 172 VRegister B() const; 173 VRegister H() const; 174 VRegister D() const; 175 VRegister S() const; 176 VRegister Q() const; 177 178 bool IsSameSizeAndType(const CPURegister& other) const; 179 180 protected: 181 int reg_size_; 182 RegisterType reg_type_; 183 184 #if defined(V8_OS_WIN) && !defined(__clang__) 185 // MSVC has problem to parse template base class as friend class. 186 friend RegisterBase; 187 #else 188 friend class RegisterBase; 189 #endif 190 CPURegister(int code,int size,RegisterType type)191 constexpr CPURegister(int code, int size, RegisterType type) 192 : RegisterBase(code), reg_size_(size), reg_type_(type) {} 193 IsValidRegister(int code,int size)194 static constexpr bool IsValidRegister(int code, int size) { 195 return (size == kWRegSizeInBits || size == kXRegSizeInBits) && 196 (code < kNumberOfRegisters || code == kSPRegInternalCode); 197 } 198 IsValidVRegister(int code,int size)199 static constexpr bool IsValidVRegister(int code, int size) { 200 return (size == kBRegSizeInBits || size == kHRegSizeInBits || 201 size == kSRegSizeInBits || size == kDRegSizeInBits || 202 size == kQRegSizeInBits) && 203 code < kNumberOfVRegisters; 204 } 205 IsValid(int code,int size,RegisterType type)206 static constexpr bool IsValid(int code, int size, RegisterType type) { 207 return (type == kRegister && IsValidRegister(code, size)) || 208 (type == kVRegister && IsValidVRegister(code, size)); 209 } 210 IsNone(int code,int size,RegisterType type)211 static constexpr bool IsNone(int code, int size, RegisterType type) { 212 return type == kNoRegister && code == 0 && size == 0; 213 } 214 }; 215 216 ASSERT_TRIVIALLY_COPYABLE(CPURegister); 217 218 class Register : public CPURegister { 219 public: no_reg()220 static constexpr Register no_reg() { return Register(CPURegister::no_reg()); } 221 Create(int code,int size)222 static constexpr Register Create(int code, int size) { 223 return Register(CPURegister::Create(code, size, CPURegister::kRegister)); 224 } 225 226 static Register XRegFromCode(unsigned code); 227 static Register WRegFromCode(unsigned code); 228 from_code(int code)229 static constexpr Register from_code(int code) { 230 // Always return an X register. 231 return Register::Create(code, kXRegSizeInBits); 232 } 233 GetSpecialRegisterName(int code)234 static const char* GetSpecialRegisterName(int code) { 235 return (code == kSPRegInternalCode) ? "sp" : "UNKNOWN"; 236 } 237 238 private: Register(const CPURegister & r)239 constexpr explicit Register(const CPURegister& r) : CPURegister(r) {} 240 }; 241 242 ASSERT_TRIVIALLY_COPYABLE(Register); 243 244 constexpr bool kPadArguments = true; 245 constexpr bool kSimpleFPAliasing = true; 246 constexpr bool kSimdMaskRegisters = false; 247 248 enum DoubleRegisterCode { 249 #define REGISTER_CODE(R) kDoubleCode_##R, 250 DOUBLE_REGISTERS(REGISTER_CODE) 251 #undef REGISTER_CODE 252 kDoubleAfterLast 253 }; 254 255 // Functions for handling NEON vector format information. 256 enum VectorFormat { 257 kFormatUndefined = 0xffffffff, 258 kFormat8B = NEON_8B, 259 kFormat16B = NEON_16B, 260 kFormat4H = NEON_4H, 261 kFormat8H = NEON_8H, 262 kFormat2S = NEON_2S, 263 kFormat4S = NEON_4S, 264 kFormat1D = NEON_1D, 265 kFormat2D = NEON_2D, 266 267 // Scalar formats. We add the scalar bit to distinguish between scalar and 268 // vector enumerations; the bit is always set in the encoding of scalar ops 269 // and always clear for vector ops. Although kFormatD and kFormat1D appear 270 // to be the same, their meaning is subtly different. The first is a scalar 271 // operation, the second a vector operation that only affects one lane. 272 kFormatB = NEON_B | NEONScalar, 273 kFormatH = NEON_H | NEONScalar, 274 kFormatS = NEON_S | NEONScalar, 275 kFormatD = NEON_D | NEONScalar 276 }; 277 278 VectorFormat VectorFormatHalfWidth(VectorFormat vform); 279 VectorFormat VectorFormatDoubleWidth(VectorFormat vform); 280 VectorFormat VectorFormatDoubleLanes(VectorFormat vform); 281 VectorFormat VectorFormatHalfLanes(VectorFormat vform); 282 VectorFormat ScalarFormatFromLaneSize(int lanesize); 283 VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform); 284 VectorFormat VectorFormatFillQ(int laneSize); 285 VectorFormat VectorFormatFillQ(VectorFormat vform); 286 VectorFormat ScalarFormatFromFormat(VectorFormat vform); 287 V8_EXPORT_PRIVATE unsigned RegisterSizeInBitsFromFormat(VectorFormat vform); 288 unsigned RegisterSizeInBytesFromFormat(VectorFormat vform); 289 int LaneSizeInBytesFromFormat(VectorFormat vform); 290 unsigned LaneSizeInBitsFromFormat(VectorFormat vform); 291 int LaneSizeInBytesLog2FromFormat(VectorFormat vform); 292 V8_EXPORT_PRIVATE int LaneCountFromFormat(VectorFormat vform); 293 int MaxLaneCountFromFormat(VectorFormat vform); 294 V8_EXPORT_PRIVATE bool IsVectorFormat(VectorFormat vform); 295 int64_t MaxIntFromFormat(VectorFormat vform); 296 int64_t MinIntFromFormat(VectorFormat vform); 297 uint64_t MaxUintFromFormat(VectorFormat vform); 298 299 class VRegister : public CPURegister { 300 public: no_reg()301 static constexpr VRegister no_reg() { 302 return VRegister(CPURegister::no_reg(), 0); 303 } 304 305 static constexpr VRegister Create(int code, int size, int lane_count = 1) { 306 CONSTEXPR_DCHECK(IsValidLaneCount(lane_count)); 307 return VRegister(CPURegister::Create(code, size, CPURegister::kVRegister), 308 lane_count); 309 } 310 Create(int reg_code,VectorFormat format)311 static VRegister Create(int reg_code, VectorFormat format) { 312 int reg_size = RegisterSizeInBitsFromFormat(format); 313 int reg_count = IsVectorFormat(format) ? LaneCountFromFormat(format) : 1; 314 return VRegister::Create(reg_code, reg_size, reg_count); 315 } 316 317 static VRegister BRegFromCode(unsigned code); 318 static VRegister HRegFromCode(unsigned code); 319 static VRegister SRegFromCode(unsigned code); 320 static VRegister DRegFromCode(unsigned code); 321 static VRegister QRegFromCode(unsigned code); 322 static VRegister VRegFromCode(unsigned code); 323 V8B()324 VRegister V8B() const { 325 return VRegister::Create(code(), kDRegSizeInBits, 8); 326 } V16B()327 VRegister V16B() const { 328 return VRegister::Create(code(), kQRegSizeInBits, 16); 329 } V4H()330 VRegister V4H() const { 331 return VRegister::Create(code(), kDRegSizeInBits, 4); 332 } V8H()333 VRegister V8H() const { 334 return VRegister::Create(code(), kQRegSizeInBits, 8); 335 } V2S()336 VRegister V2S() const { 337 return VRegister::Create(code(), kDRegSizeInBits, 2); 338 } V4S()339 VRegister V4S() const { 340 return VRegister::Create(code(), kQRegSizeInBits, 4); 341 } V2D()342 VRegister V2D() const { 343 return VRegister::Create(code(), kQRegSizeInBits, 2); 344 } V1D()345 VRegister V1D() const { 346 return VRegister::Create(code(), kDRegSizeInBits, 1); 347 } 348 Format(VectorFormat f)349 VRegister Format(VectorFormat f) const { 350 return VRegister::Create(code(), f); 351 } 352 Is8B()353 bool Is8B() const { return (Is64Bits() && (lane_count_ == 8)); } Is16B()354 bool Is16B() const { return (Is128Bits() && (lane_count_ == 16)); } Is4H()355 bool Is4H() const { return (Is64Bits() && (lane_count_ == 4)); } Is8H()356 bool Is8H() const { return (Is128Bits() && (lane_count_ == 8)); } Is2S()357 bool Is2S() const { return (Is64Bits() && (lane_count_ == 2)); } Is4S()358 bool Is4S() const { return (Is128Bits() && (lane_count_ == 4)); } Is1D()359 bool Is1D() const { return (Is64Bits() && (lane_count_ == 1)); } Is2D()360 bool Is2D() const { return (Is128Bits() && (lane_count_ == 2)); } 361 362 // For consistency, we assert the number of lanes of these scalar registers, 363 // even though there are no vectors of equivalent total size with which they 364 // could alias. Is1B()365 bool Is1B() const { 366 DCHECK(!(Is8Bits() && IsVector())); 367 return Is8Bits(); 368 } Is1H()369 bool Is1H() const { 370 DCHECK(!(Is16Bits() && IsVector())); 371 return Is16Bits(); 372 } Is1S()373 bool Is1S() const { 374 DCHECK(!(Is32Bits() && IsVector())); 375 return Is32Bits(); 376 } 377 IsLaneSizeB()378 bool IsLaneSizeB() const { return LaneSizeInBits() == kBRegSizeInBits; } IsLaneSizeH()379 bool IsLaneSizeH() const { return LaneSizeInBits() == kHRegSizeInBits; } IsLaneSizeS()380 bool IsLaneSizeS() const { return LaneSizeInBits() == kSRegSizeInBits; } IsLaneSizeD()381 bool IsLaneSizeD() const { return LaneSizeInBits() == kDRegSizeInBits; } 382 IsScalar()383 bool IsScalar() const { return lane_count_ == 1; } IsVector()384 bool IsVector() const { return lane_count_ > 1; } 385 IsSameFormat(const VRegister & other)386 bool IsSameFormat(const VRegister& other) const { 387 return (reg_size_ == other.reg_size_) && (lane_count_ == other.lane_count_); 388 } 389 LaneCount()390 int LaneCount() const { return lane_count_; } 391 LaneSizeInBytes()392 unsigned LaneSizeInBytes() const { return SizeInBytes() / lane_count_; } 393 LaneSizeInBits()394 unsigned LaneSizeInBits() const { return LaneSizeInBytes() * 8; } 395 396 static constexpr int kMaxNumRegisters = kNumberOfVRegisters; 397 STATIC_ASSERT(kMaxNumRegisters == kDoubleAfterLast); 398 from_code(int code)399 static VRegister from_code(int code) { 400 // Always return a D register. 401 return VRegister::Create(code, kDRegSizeInBits); 402 } 403 404 private: 405 int lane_count_; 406 VRegister(const CPURegister & r,int lane_count)407 constexpr explicit VRegister(const CPURegister& r, int lane_count) 408 : CPURegister(r), lane_count_(lane_count) {} 409 IsValidLaneCount(int lane_count)410 static constexpr bool IsValidLaneCount(int lane_count) { 411 return base::bits::IsPowerOfTwo(lane_count) && lane_count <= 16; 412 } 413 }; 414 415 ASSERT_TRIVIALLY_COPYABLE(VRegister); 416 417 // No*Reg is used to indicate an unused argument, or an error case. Note that 418 // these all compare equal. The Register and VRegister variants are provided for 419 // convenience. 420 constexpr Register NoReg = Register::no_reg(); 421 constexpr VRegister NoVReg = VRegister::no_reg(); 422 constexpr CPURegister NoCPUReg = CPURegister::no_reg(); 423 constexpr Register no_reg = NoReg; 424 constexpr VRegister no_dreg = NoVReg; 425 426 #define DEFINE_REGISTER(register_class, name, ...) \ 427 constexpr register_class name = register_class::Create(__VA_ARGS__) 428 #define ALIAS_REGISTER(register_class, alias, name) \ 429 constexpr register_class alias = name 430 431 #define DEFINE_REGISTERS(N) \ 432 DEFINE_REGISTER(Register, w##N, N, kWRegSizeInBits); \ 433 DEFINE_REGISTER(Register, x##N, N, kXRegSizeInBits); 434 GENERAL_REGISTER_CODE_LIST(DEFINE_REGISTERS) 435 #undef DEFINE_REGISTERS 436 437 DEFINE_REGISTER(Register, wsp, kSPRegInternalCode, kWRegSizeInBits); 438 DEFINE_REGISTER(Register, sp, kSPRegInternalCode, kXRegSizeInBits); 439 440 #define DEFINE_VREGISTERS(N) \ 441 DEFINE_REGISTER(VRegister, b##N, N, kBRegSizeInBits); \ 442 DEFINE_REGISTER(VRegister, h##N, N, kHRegSizeInBits); \ 443 DEFINE_REGISTER(VRegister, s##N, N, kSRegSizeInBits); \ 444 DEFINE_REGISTER(VRegister, d##N, N, kDRegSizeInBits); \ 445 DEFINE_REGISTER(VRegister, q##N, N, kQRegSizeInBits); \ 446 DEFINE_REGISTER(VRegister, v##N, N, kQRegSizeInBits); 447 GENERAL_REGISTER_CODE_LIST(DEFINE_VREGISTERS) 448 #undef DEFINE_VREGISTERS 449 450 #undef DEFINE_REGISTER 451 452 // Registers aliases. 453 ALIAS_REGISTER(VRegister, v8_, v8); // Avoid conflicts with namespace v8. 454 ALIAS_REGISTER(Register, ip0, x16); 455 ALIAS_REGISTER(Register, ip1, x17); 456 ALIAS_REGISTER(Register, wip0, w16); 457 ALIAS_REGISTER(Register, wip1, w17); 458 // Root register. 459 ALIAS_REGISTER(Register, kRootRegister, x26); 460 ALIAS_REGISTER(Register, rr, x26); 461 // Context pointer register. 462 ALIAS_REGISTER(Register, cp, x27); 463 ALIAS_REGISTER(Register, fp, x29); 464 ALIAS_REGISTER(Register, lr, x30); 465 ALIAS_REGISTER(Register, xzr, x31); 466 ALIAS_REGISTER(Register, wzr, w31); 467 468 // Register used for padding stack slots. 469 ALIAS_REGISTER(Register, padreg, x31); 470 471 // Keeps the 0 double value. 472 ALIAS_REGISTER(VRegister, fp_zero, d15); 473 // MacroAssembler fixed V Registers. 474 // d29 is not part of ALLOCATABLE_DOUBLE_REGISTERS, so use 27 and 28. 475 ALIAS_REGISTER(VRegister, fp_fixed1, d27); 476 ALIAS_REGISTER(VRegister, fp_fixed2, d28); 477 478 // MacroAssembler scratch V registers. 479 ALIAS_REGISTER(VRegister, fp_scratch, d30); 480 ALIAS_REGISTER(VRegister, fp_scratch1, d30); 481 ALIAS_REGISTER(VRegister, fp_scratch2, d31); 482 483 #undef ALIAS_REGISTER 484 485 // AreAliased returns true if any of the named registers overlap. Arguments set 486 // to NoReg are ignored. The system stack pointer may be specified. 487 V8_EXPORT_PRIVATE bool AreAliased( 488 const CPURegister& reg1, const CPURegister& reg2, 489 const CPURegister& reg3 = NoReg, const CPURegister& reg4 = NoReg, 490 const CPURegister& reg5 = NoReg, const CPURegister& reg6 = NoReg, 491 const CPURegister& reg7 = NoReg, const CPURegister& reg8 = NoReg); 492 493 // AreSameSizeAndType returns true if all of the specified registers have the 494 // same size, and are of the same type. The system stack pointer may be 495 // specified. Arguments set to NoReg are ignored, as are any subsequent 496 // arguments. At least one argument (reg1) must be valid (not NoCPUReg). 497 V8_EXPORT_PRIVATE bool AreSameSizeAndType( 498 const CPURegister& reg1, const CPURegister& reg2 = NoCPUReg, 499 const CPURegister& reg3 = NoCPUReg, const CPURegister& reg4 = NoCPUReg, 500 const CPURegister& reg5 = NoCPUReg, const CPURegister& reg6 = NoCPUReg, 501 const CPURegister& reg7 = NoCPUReg, const CPURegister& reg8 = NoCPUReg); 502 503 // AreSameFormat returns true if all of the specified VRegisters have the same 504 // vector format. Arguments set to NoVReg are ignored, as are any subsequent 505 // arguments. At least one argument (reg1) must be valid (not NoVReg). 506 bool AreSameFormat(const VRegister& reg1, const VRegister& reg2, 507 const VRegister& reg3 = NoVReg, 508 const VRegister& reg4 = NoVReg); 509 510 // AreConsecutive returns true if all of the specified VRegisters are 511 // consecutive in the register file. Arguments may be set to NoVReg, and if so, 512 // subsequent arguments must also be NoVReg. At least one argument (reg1) must 513 // be valid (not NoVReg). 514 V8_EXPORT_PRIVATE bool AreConsecutive(const VRegister& reg1, 515 const VRegister& reg2, 516 const VRegister& reg3 = NoVReg, 517 const VRegister& reg4 = NoVReg); 518 519 using FloatRegister = VRegister; 520 using DoubleRegister = VRegister; 521 using Simd128Register = VRegister; 522 523 // ----------------------------------------------------------------------------- 524 // Lists of registers. 525 class V8_EXPORT_PRIVATE CPURegList { 526 public: 527 template <typename... CPURegisters> CPURegList(CPURegister reg0,CPURegisters...regs)528 explicit CPURegList(CPURegister reg0, CPURegisters... regs) 529 : list_(CPURegister::ListOf(reg0, regs...)), 530 size_(reg0.SizeInBits()), 531 type_(reg0.type()) { 532 DCHECK(AreSameSizeAndType(reg0, regs...)); 533 DCHECK(is_valid()); 534 } 535 CPURegList(CPURegister::RegisterType type,int size,RegList list)536 CPURegList(CPURegister::RegisterType type, int size, RegList list) 537 : list_(list), size_(size), type_(type) { 538 DCHECK(is_valid()); 539 } 540 CPURegList(CPURegister::RegisterType type,int size,int first_reg,int last_reg)541 CPURegList(CPURegister::RegisterType type, int size, int first_reg, 542 int last_reg) 543 : size_(size), type_(type) { 544 DCHECK( 545 ((type == CPURegister::kRegister) && (last_reg < kNumberOfRegisters)) || 546 ((type == CPURegister::kVRegister) && 547 (last_reg < kNumberOfVRegisters))); 548 DCHECK(last_reg >= first_reg); 549 list_ = (1ULL << (last_reg + 1)) - 1; 550 list_ &= ~((1ULL << first_reg) - 1); 551 DCHECK(is_valid()); 552 } 553 type()554 CPURegister::RegisterType type() const { 555 return type_; 556 } 557 list()558 RegList list() const { 559 return list_; 560 } 561 set_list(RegList new_list)562 inline void set_list(RegList new_list) { 563 list_ = new_list; 564 DCHECK(is_valid()); 565 } 566 567 // Combine another CPURegList into this one. Registers that already exist in 568 // this list are left unchanged. The type and size of the registers in the 569 // 'other' list must match those in this list. 570 void Combine(const CPURegList& other); 571 572 // Remove every register in the other CPURegList from this one. Registers that 573 // do not exist in this list are ignored. The type of the registers in the 574 // 'other' list must match those in this list. 575 void Remove(const CPURegList& other); 576 577 // Variants of Combine and Remove which take CPURegisters. 578 void Combine(const CPURegister& other); 579 void Remove(const CPURegister& other1, const CPURegister& other2 = NoCPUReg, 580 const CPURegister& other3 = NoCPUReg, 581 const CPURegister& other4 = NoCPUReg); 582 583 // Variants of Combine and Remove which take a single register by its code; 584 // the type and size of the register is inferred from this list. 585 void Combine(int code); 586 void Remove(int code); 587 588 // Align the list to 16 bytes. 589 void Align(); 590 591 CPURegister PopLowestIndex(); 592 CPURegister PopHighestIndex(); 593 594 // AAPCS64 callee-saved registers. 595 static CPURegList GetCalleeSaved(int size = kXRegSizeInBits); 596 static CPURegList GetCalleeSavedV(int size = kDRegSizeInBits); 597 598 // AAPCS64 caller-saved registers. Note that this includes lr. 599 // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top 600 // 64-bits being caller-saved. 601 static CPURegList GetCallerSaved(int size = kXRegSizeInBits); 602 static CPURegList GetCallerSavedV(int size = kDRegSizeInBits); 603 IsEmpty()604 bool IsEmpty() const { 605 return list_ == 0; 606 } 607 608 bool IncludesAliasOf(const CPURegister& other1, 609 const CPURegister& other2 = NoCPUReg, 610 const CPURegister& other3 = NoCPUReg, 611 const CPURegister& other4 = NoCPUReg) const { 612 RegList list = 0; 613 if (!other1.IsNone() && (other1.type() == type_)) list |= other1.bit(); 614 if (!other2.IsNone() && (other2.type() == type_)) list |= other2.bit(); 615 if (!other3.IsNone() && (other3.type() == type_)) list |= other3.bit(); 616 if (!other4.IsNone() && (other4.type() == type_)) list |= other4.bit(); 617 return (list_ & list) != 0; 618 } 619 Count()620 int Count() const { 621 return CountSetBits(list_, kRegListSizeInBits); 622 } 623 RegisterSizeInBits()624 int RegisterSizeInBits() const { 625 return size_; 626 } 627 RegisterSizeInBytes()628 int RegisterSizeInBytes() const { 629 int size_in_bits = RegisterSizeInBits(); 630 DCHECK_EQ(size_in_bits % kBitsPerByte, 0); 631 return size_in_bits / kBitsPerByte; 632 } 633 TotalSizeInBytes()634 int TotalSizeInBytes() const { 635 return RegisterSizeInBytes() * Count(); 636 } 637 638 private: 639 RegList list_; 640 int size_; 641 CPURegister::RegisterType type_; 642 is_valid()643 bool is_valid() const { 644 constexpr RegList kValidRegisters{0x8000000ffffffff}; 645 constexpr RegList kValidVRegisters{0x0000000ffffffff}; 646 switch (type_) { 647 case CPURegister::kRegister: 648 return (list_ & kValidRegisters) == list_; 649 case CPURegister::kVRegister: 650 return (list_ & kValidVRegisters) == list_; 651 case CPURegister::kNoRegister: 652 return list_ == 0; 653 default: 654 UNREACHABLE(); 655 } 656 } 657 }; 658 659 // AAPCS64 callee-saved registers. 660 #define kCalleeSaved CPURegList::GetCalleeSaved() 661 #define kCalleeSavedV CPURegList::GetCalleeSavedV() 662 663 // AAPCS64 caller-saved registers. Note that this includes lr. 664 #define kCallerSaved CPURegList::GetCallerSaved() 665 #define kCallerSavedV CPURegList::GetCallerSavedV() 666 667 // Define a {RegisterName} method for {Register} and {VRegister}. 668 DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS) 669 DEFINE_REGISTER_NAMES(VRegister, VECTOR_REGISTERS) 670 671 // Give alias names to registers for calling conventions. 672 constexpr Register kReturnRegister0 = x0; 673 constexpr Register kReturnRegister1 = x1; 674 constexpr Register kReturnRegister2 = x2; 675 constexpr Register kJSFunctionRegister = x1; 676 constexpr Register kContextRegister = cp; 677 constexpr Register kAllocateSizeRegister = x1; 678 679 constexpr Register kSpeculationPoisonRegister = x23; 680 681 constexpr Register kInterpreterAccumulatorRegister = x0; 682 constexpr Register kInterpreterBytecodeOffsetRegister = x19; 683 constexpr Register kInterpreterBytecodeArrayRegister = x20; 684 constexpr Register kInterpreterDispatchTableRegister = x21; 685 686 constexpr Register kJavaScriptCallArgCountRegister = x0; 687 constexpr Register kJavaScriptCallCodeStartRegister = x2; 688 constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister; 689 constexpr Register kJavaScriptCallNewTargetRegister = x3; 690 constexpr Register kJavaScriptCallExtraArg1Register = x2; 691 692 constexpr Register kOffHeapTrampolineRegister = ip0; 693 constexpr Register kRuntimeCallFunctionRegister = x1; 694 constexpr Register kRuntimeCallArgCountRegister = x0; 695 constexpr Register kRuntimeCallArgvRegister = x11; 696 constexpr Register kWasmInstanceRegister = x7; 697 constexpr Register kWasmCompileLazyFuncIndexRegister = x8; 698 699 constexpr DoubleRegister kFPReturnRegister0 = d0; 700 701 } // namespace internal 702 } // namespace v8 703 704 #endif // V8_CODEGEN_ARM64_REGISTER_ARM64_H_ 705