diff options
Diffstat (limited to 'deps/v8/src/arm64/register-arm64.h')
-rw-r--r-- | deps/v8/src/arm64/register-arm64.h | 752 |
1 files changed, 752 insertions, 0 deletions
diff --git a/deps/v8/src/arm64/register-arm64.h b/deps/v8/src/arm64/register-arm64.h new file mode 100644 index 0000000000..77310213f2 --- /dev/null +++ b/deps/v8/src/arm64/register-arm64.h @@ -0,0 +1,752 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_ARM64_REGISTER_ARM64_H_ +#define V8_ARM64_REGISTER_ARM64_H_ + +#include "src/arm64/utils-arm64.h" +#include "src/globals.h" +#include "src/register.h" +#include "src/reglist.h" + +namespace v8 { +namespace internal { + +// ----------------------------------------------------------------------------- +// Registers. +// clang-format off +#define GENERAL_REGISTER_CODE_LIST(R) \ + R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ + R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ + R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ + R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) + +#define GENERAL_REGISTERS(R) \ + R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \ + R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \ + R(x16) R(x17) R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) \ + R(x24) R(x25) R(x26) R(x27) R(x28) R(x29) R(x30) R(x31) + +#if defined(V8_OS_WIN) +// x18 is reserved as platform register on Windows ARM64. +#define ALLOCATABLE_GENERAL_REGISTERS(R) \ + R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \ + R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \ + R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x25) \ + R(x27) R(x28) +#else +#define ALLOCATABLE_GENERAL_REGISTERS(R) \ + R(x0) R(x1) R(x2) R(x3) R(x4) R(x5) R(x6) R(x7) \ + R(x8) R(x9) R(x10) R(x11) R(x12) R(x13) R(x14) R(x15) \ + R(x18) R(x19) R(x20) R(x21) R(x22) R(x23) R(x24) R(x25) \ + R(x27) R(x28) +#endif + +#define FLOAT_REGISTERS(V) \ + V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) \ + V(s8) V(s9) V(s10) V(s11) V(s12) V(s13) V(s14) V(s15) \ + V(s16) V(s17) V(s18) V(s19) V(s20) V(s21) V(s22) V(s23) \ + V(s24) V(s25) V(s26) V(s27) V(s28) V(s29) V(s30) V(s31) + +#define DOUBLE_REGISTERS(R) \ + R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \ + R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d15) \ + R(d16) R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) \ + R(d24) R(d25) R(d26) R(d27) R(d28) R(d29) R(d30) R(d31) + +#define SIMD128_REGISTERS(V) \ + V(q0) V(q1) V(q2) V(q3) V(q4) V(q5) V(q6) V(q7) \ + V(q8) V(q9) V(q10) V(q11) V(q12) V(q13) V(q14) V(q15) \ + V(q16) V(q17) V(q18) V(q19) V(q20) V(q21) V(q22) V(q23) \ + V(q24) V(q25) V(q26) V(q27) V(q28) V(q29) V(q30) V(q31) + +// Register d29 could be allocated, but we keep an even length list here, in +// order to make stack alignment easier for save and restore. +#define ALLOCATABLE_DOUBLE_REGISTERS(R) \ + R(d0) R(d1) R(d2) R(d3) R(d4) R(d5) R(d6) R(d7) \ + R(d8) R(d9) R(d10) R(d11) R(d12) R(d13) R(d14) R(d16) \ + R(d17) R(d18) R(d19) R(d20) R(d21) R(d22) R(d23) R(d24) \ + R(d25) R(d26) R(d27) R(d28) +// clang-format on + +constexpr int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte; + +const int kNumRegs = kNumberOfRegisters; +// Registers x0-x17 are caller-saved. +const int kNumJSCallerSaved = 18; +const RegList kJSCallerSaved = 0x3ffff; + +// Number of registers for which space is reserved in safepoints. Must be a +// multiple of eight. +// TODO(all): Refine this number. +const int kNumSafepointRegisters = 32; + +// Define the list of registers actually saved at safepoints. +// Note that the number of saved registers may be smaller than the reserved +// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters. +#define kSafepointSavedRegisters CPURegList::GetSafepointSavedRegisters().list() +#define kNumSafepointSavedRegisters \ + CPURegList::GetSafepointSavedRegisters().Count() + +// Some CPURegister methods can return Register and VRegister types, so we +// need to declare them in advance. +class Register; +class VRegister; + +enum RegisterCode { +#define REGISTER_CODE(R) kRegCode_##R, + GENERAL_REGISTERS(REGISTER_CODE) +#undef REGISTER_CODE + kRegAfterLast +}; + +class CPURegister : public RegisterBase<CPURegister, kRegAfterLast> { + public: + enum RegisterType { kRegister, kVRegister, kNoRegister }; + + static constexpr CPURegister no_reg() { + return CPURegister{0, 0, kNoRegister}; + } + + template <int code, int size, RegisterType type> + static constexpr CPURegister Create() { + static_assert(IsValid(code, size, type), "Cannot create invalid registers"); + return CPURegister{code, size, type}; + } + + static CPURegister Create(int code, int size, RegisterType type) { + DCHECK(IsValid(code, size, type)); + return CPURegister{code, size, type}; + } + + RegisterType type() const { return reg_type_; } + int SizeInBits() const { + DCHECK(IsValid()); + return reg_size_; + } + int SizeInBytes() const { + DCHECK(IsValid()); + DCHECK_EQ(SizeInBits() % 8, 0); + return reg_size_ / 8; + } + bool Is8Bits() const { + DCHECK(IsValid()); + return reg_size_ == 8; + } + bool Is16Bits() const { + DCHECK(IsValid()); + return reg_size_ == 16; + } + bool Is32Bits() const { + DCHECK(IsValid()); + return reg_size_ == 32; + } + bool Is64Bits() const { + DCHECK(IsValid()); + return reg_size_ == 64; + } + bool Is128Bits() const { + DCHECK(IsValid()); + return reg_size_ == 128; + } + bool IsValid() const { return reg_type_ != kNoRegister; } + bool IsNone() const { return reg_type_ == kNoRegister; } + bool Is(const CPURegister& other) const { + return Aliases(other) && (reg_size_ == other.reg_size_); + } + bool Aliases(const CPURegister& other) const { + return (reg_code_ == other.reg_code_) && (reg_type_ == other.reg_type_); + } + + bool IsZero() const; + bool IsSP() const; + + bool IsRegister() const { return reg_type_ == kRegister; } + bool IsVRegister() const { return reg_type_ == kVRegister; } + + bool IsFPRegister() const { return IsS() || IsD(); } + + bool IsW() const { return IsRegister() && Is32Bits(); } + bool IsX() const { return IsRegister() && Is64Bits(); } + + // These assertions ensure that the size and type of the register are as + // described. They do not consider the number of lanes that make up a vector. + // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD() + // does not imply Is1D() or Is8B(). + // Check the number of lanes, ie. the format of the vector, using methods such + // as Is8B(), Is1D(), etc. in the VRegister class. + bool IsV() const { return IsVRegister(); } + bool IsB() const { return IsV() && Is8Bits(); } + bool IsH() const { return IsV() && Is16Bits(); } + bool IsS() const { return IsV() && Is32Bits(); } + bool IsD() const { return IsV() && Is64Bits(); } + bool IsQ() const { return IsV() && Is128Bits(); } + + Register Reg() const; + VRegister VReg() const; + + Register X() const; + Register W() const; + VRegister V() const; + VRegister B() const; + VRegister H() const; + VRegister D() const; + VRegister S() const; + VRegister Q() const; + + bool IsSameSizeAndType(const CPURegister& other) const; + + bool is(const CPURegister& other) const { return Is(other); } + bool is_valid() const { return IsValid(); } + + protected: + int reg_size_; + RegisterType reg_type_; + +#if defined(V8_OS_WIN) && !defined(__clang__) + // MSVC has problem to parse template base class as friend class. + friend RegisterBase; +#else + friend class RegisterBase; +#endif + + constexpr CPURegister(int code, int size, RegisterType type) + : RegisterBase(code), reg_size_(size), reg_type_(type) {} + + static constexpr bool IsValidRegister(int code, int size) { + return (size == kWRegSizeInBits || size == kXRegSizeInBits) && + (code < kNumberOfRegisters || code == kSPRegInternalCode); + } + + static constexpr bool IsValidVRegister(int code, int size) { + return (size == kBRegSizeInBits || size == kHRegSizeInBits || + size == kSRegSizeInBits || size == kDRegSizeInBits || + size == kQRegSizeInBits) && + code < kNumberOfVRegisters; + } + + static constexpr bool IsValid(int code, int size, RegisterType type) { + return (type == kRegister && IsValidRegister(code, size)) || + (type == kVRegister && IsValidVRegister(code, size)); + } + + static constexpr bool IsNone(int code, int size, RegisterType type) { + return type == kNoRegister && code == 0 && size == 0; + } +}; + +ASSERT_TRIVIALLY_COPYABLE(CPURegister); + +class Register : public CPURegister { + public: + static constexpr Register no_reg() { return Register(CPURegister::no_reg()); } + + template <int code, int size> + static constexpr Register Create() { + return Register(CPURegister::Create<code, size, CPURegister::kRegister>()); + } + + static Register Create(int code, int size) { + return Register(CPURegister::Create(code, size, CPURegister::kRegister)); + } + + static Register XRegFromCode(unsigned code); + static Register WRegFromCode(unsigned code); + + static Register from_code(int code) { + // Always return an X register. + return Register::Create(code, kXRegSizeInBits); + } + + template <int code> + static Register from_code() { + // Always return an X register. + return Register::Create<code, kXRegSizeInBits>(); + } + + static const char* GetSpecialRegisterName(int code) { + return (code == kSPRegInternalCode) ? "sp" : "UNKNOWN"; + } + + private: + constexpr explicit Register(const CPURegister& r) : CPURegister(r) {} +}; + +ASSERT_TRIVIALLY_COPYABLE(Register); + +constexpr bool kPadArguments = true; +constexpr bool kSimpleFPAliasing = true; +constexpr bool kSimdMaskRegisters = false; + +enum DoubleRegisterCode { +#define REGISTER_CODE(R) kDoubleCode_##R, + DOUBLE_REGISTERS(REGISTER_CODE) +#undef REGISTER_CODE + kDoubleAfterLast +}; + +// Functions for handling NEON vector format information. +enum VectorFormat { + kFormatUndefined = 0xffffffff, + kFormat8B = NEON_8B, + kFormat16B = NEON_16B, + kFormat4H = NEON_4H, + kFormat8H = NEON_8H, + kFormat2S = NEON_2S, + kFormat4S = NEON_4S, + kFormat1D = NEON_1D, + kFormat2D = NEON_2D, + + // Scalar formats. We add the scalar bit to distinguish between scalar and + // vector enumerations; the bit is always set in the encoding of scalar ops + // and always clear for vector ops. Although kFormatD and kFormat1D appear + // to be the same, their meaning is subtly different. The first is a scalar + // operation, the second a vector operation that only affects one lane. + kFormatB = NEON_B | NEONScalar, + kFormatH = NEON_H | NEONScalar, + kFormatS = NEON_S | NEONScalar, + kFormatD = NEON_D | NEONScalar +}; + +VectorFormat VectorFormatHalfWidth(VectorFormat vform); +VectorFormat VectorFormatDoubleWidth(VectorFormat vform); +VectorFormat VectorFormatDoubleLanes(VectorFormat vform); +VectorFormat VectorFormatHalfLanes(VectorFormat vform); +VectorFormat ScalarFormatFromLaneSize(int lanesize); +VectorFormat VectorFormatHalfWidthDoubleLanes(VectorFormat vform); +VectorFormat VectorFormatFillQ(VectorFormat vform); +VectorFormat ScalarFormatFromFormat(VectorFormat vform); +unsigned RegisterSizeInBitsFromFormat(VectorFormat vform); +unsigned RegisterSizeInBytesFromFormat(VectorFormat vform); +int LaneSizeInBytesFromFormat(VectorFormat vform); +unsigned LaneSizeInBitsFromFormat(VectorFormat vform); +int LaneSizeInBytesLog2FromFormat(VectorFormat vform); +int LaneCountFromFormat(VectorFormat vform); +int MaxLaneCountFromFormat(VectorFormat vform); +bool IsVectorFormat(VectorFormat vform); +int64_t MaxIntFromFormat(VectorFormat vform); +int64_t MinIntFromFormat(VectorFormat vform); +uint64_t MaxUintFromFormat(VectorFormat vform); + +class VRegister : public CPURegister { + public: + static constexpr VRegister no_reg() { + return VRegister(CPURegister::no_reg(), 0); + } + + template <int code, int size, int lane_count = 1> + static constexpr VRegister Create() { + static_assert(IsValidLaneCount(lane_count), "Invalid lane count"); + return VRegister(CPURegister::Create<code, size, kVRegister>(), lane_count); + } + + static VRegister Create(int code, int size, int lane_count = 1) { + DCHECK(IsValidLaneCount(lane_count)); + return VRegister(CPURegister::Create(code, size, CPURegister::kVRegister), + lane_count); + } + + static VRegister Create(int reg_code, VectorFormat format) { + int reg_size = RegisterSizeInBitsFromFormat(format); + int reg_count = IsVectorFormat(format) ? LaneCountFromFormat(format) : 1; + return VRegister::Create(reg_code, reg_size, reg_count); + } + + static VRegister BRegFromCode(unsigned code); + static VRegister HRegFromCode(unsigned code); + static VRegister SRegFromCode(unsigned code); + static VRegister DRegFromCode(unsigned code); + static VRegister QRegFromCode(unsigned code); + static VRegister VRegFromCode(unsigned code); + + VRegister V8B() const { + return VRegister::Create(code(), kDRegSizeInBits, 8); + } + VRegister V16B() const { + return VRegister::Create(code(), kQRegSizeInBits, 16); + } + VRegister V4H() const { + return VRegister::Create(code(), kDRegSizeInBits, 4); + } + VRegister V8H() const { + return VRegister::Create(code(), kQRegSizeInBits, 8); + } + VRegister V2S() const { + return VRegister::Create(code(), kDRegSizeInBits, 2); + } + VRegister V4S() const { + return VRegister::Create(code(), kQRegSizeInBits, 4); + } + VRegister V2D() const { + return VRegister::Create(code(), kQRegSizeInBits, 2); + } + VRegister V1D() const { + return VRegister::Create(code(), kDRegSizeInBits, 1); + } + + bool Is8B() const { return (Is64Bits() && (lane_count_ == 8)); } + bool Is16B() const { return (Is128Bits() && (lane_count_ == 16)); } + bool Is4H() const { return (Is64Bits() && (lane_count_ == 4)); } + bool Is8H() const { return (Is128Bits() && (lane_count_ == 8)); } + bool Is2S() const { return (Is64Bits() && (lane_count_ == 2)); } + bool Is4S() const { return (Is128Bits() && (lane_count_ == 4)); } + bool Is1D() const { return (Is64Bits() && (lane_count_ == 1)); } + bool Is2D() const { return (Is128Bits() && (lane_count_ == 2)); } + + // For consistency, we assert the number of lanes of these scalar registers, + // even though there are no vectors of equivalent total size with which they + // could alias. + bool Is1B() const { + DCHECK(!(Is8Bits() && IsVector())); + return Is8Bits(); + } + bool Is1H() const { + DCHECK(!(Is16Bits() && IsVector())); + return Is16Bits(); + } + bool Is1S() const { + DCHECK(!(Is32Bits() && IsVector())); + return Is32Bits(); + } + + bool IsLaneSizeB() const { return LaneSizeInBits() == kBRegSizeInBits; } + bool IsLaneSizeH() const { return LaneSizeInBits() == kHRegSizeInBits; } + bool IsLaneSizeS() const { return LaneSizeInBits() == kSRegSizeInBits; } + bool IsLaneSizeD() const { return LaneSizeInBits() == kDRegSizeInBits; } + + bool IsScalar() const { return lane_count_ == 1; } + bool IsVector() const { return lane_count_ > 1; } + + bool IsSameFormat(const VRegister& other) const { + return (reg_size_ == other.reg_size_) && (lane_count_ == other.lane_count_); + } + + int LaneCount() const { return lane_count_; } + + unsigned LaneSizeInBytes() const { return SizeInBytes() / lane_count_; } + + unsigned LaneSizeInBits() const { return LaneSizeInBytes() * 8; } + + static constexpr int kMaxNumRegisters = kNumberOfVRegisters; + STATIC_ASSERT(kMaxNumRegisters == kDoubleAfterLast); + + static VRegister from_code(int code) { + // Always return a D register. + return VRegister::Create(code, kDRegSizeInBits); + } + + private: + int lane_count_; + + constexpr explicit VRegister(const CPURegister& r, int lane_count) + : CPURegister(r), lane_count_(lane_count) {} + + static constexpr bool IsValidLaneCount(int lane_count) { + return base::bits::IsPowerOfTwo(lane_count) && lane_count <= 16; + } +}; + +ASSERT_TRIVIALLY_COPYABLE(VRegister); + +// No*Reg is used to indicate an unused argument, or an error case. Note that +// these all compare equal (using the Is() method). The Register and VRegister +// variants are provided for convenience. +constexpr Register NoReg = Register::no_reg(); +constexpr VRegister NoVReg = VRegister::no_reg(); +constexpr CPURegister NoCPUReg = CPURegister::no_reg(); +constexpr Register no_reg = NoReg; +constexpr VRegister no_dreg = NoVReg; + +#define DEFINE_REGISTER(register_class, name, ...) \ + constexpr register_class name = register_class::Create<__VA_ARGS__>() +#define ALIAS_REGISTER(register_class, alias, name) \ + constexpr register_class alias = name + +#define DEFINE_REGISTERS(N) \ + DEFINE_REGISTER(Register, w##N, N, kWRegSizeInBits); \ + DEFINE_REGISTER(Register, x##N, N, kXRegSizeInBits); +GENERAL_REGISTER_CODE_LIST(DEFINE_REGISTERS) +#undef DEFINE_REGISTERS + +DEFINE_REGISTER(Register, wsp, kSPRegInternalCode, kWRegSizeInBits); +DEFINE_REGISTER(Register, sp, kSPRegInternalCode, kXRegSizeInBits); + +#define DEFINE_VREGISTERS(N) \ + DEFINE_REGISTER(VRegister, b##N, N, kBRegSizeInBits); \ + DEFINE_REGISTER(VRegister, h##N, N, kHRegSizeInBits); \ + DEFINE_REGISTER(VRegister, s##N, N, kSRegSizeInBits); \ + DEFINE_REGISTER(VRegister, d##N, N, kDRegSizeInBits); \ + DEFINE_REGISTER(VRegister, q##N, N, kQRegSizeInBits); \ + DEFINE_REGISTER(VRegister, v##N, N, kQRegSizeInBits); +GENERAL_REGISTER_CODE_LIST(DEFINE_VREGISTERS) +#undef DEFINE_VREGISTERS + +#undef DEFINE_REGISTER + +// Registers aliases. +ALIAS_REGISTER(VRegister, v8_, v8); // Avoid conflicts with namespace v8. +ALIAS_REGISTER(Register, ip0, x16); +ALIAS_REGISTER(Register, ip1, x17); +ALIAS_REGISTER(Register, wip0, w16); +ALIAS_REGISTER(Register, wip1, w17); +// Root register. +ALIAS_REGISTER(Register, kRootRegister, x26); +ALIAS_REGISTER(Register, rr, x26); +// Context pointer register. +ALIAS_REGISTER(Register, cp, x27); +ALIAS_REGISTER(Register, fp, x29); +ALIAS_REGISTER(Register, lr, x30); +ALIAS_REGISTER(Register, xzr, x31); +ALIAS_REGISTER(Register, wzr, w31); + +// Register used for padding stack slots. +ALIAS_REGISTER(Register, padreg, x31); + +// Keeps the 0 double value. +ALIAS_REGISTER(VRegister, fp_zero, d15); +// MacroAssembler fixed V Registers. +ALIAS_REGISTER(VRegister, fp_fixed1, d28); +ALIAS_REGISTER(VRegister, fp_fixed2, d29); + +// MacroAssembler scratch V registers. +ALIAS_REGISTER(VRegister, fp_scratch, d30); +ALIAS_REGISTER(VRegister, fp_scratch1, d30); +ALIAS_REGISTER(VRegister, fp_scratch2, d31); + +#undef ALIAS_REGISTER + +// AreAliased returns true if any of the named registers overlap. Arguments set +// to NoReg are ignored. The system stack pointer may be specified. +bool AreAliased(const CPURegister& reg1, const CPURegister& reg2, + const CPURegister& reg3 = NoReg, + const CPURegister& reg4 = NoReg, + const CPURegister& reg5 = NoReg, + const CPURegister& reg6 = NoReg, + const CPURegister& reg7 = NoReg, + const CPURegister& reg8 = NoReg); + +// AreSameSizeAndType returns true if all of the specified registers have the +// same size, and are of the same type. The system stack pointer may be +// specified. Arguments set to NoReg are ignored, as are any subsequent +// arguments. At least one argument (reg1) must be valid (not NoCPUReg). +bool AreSameSizeAndType( + const CPURegister& reg1, const CPURegister& reg2 = NoCPUReg, + const CPURegister& reg3 = NoCPUReg, const CPURegister& reg4 = NoCPUReg, + const CPURegister& reg5 = NoCPUReg, const CPURegister& reg6 = NoCPUReg, + const CPURegister& reg7 = NoCPUReg, const CPURegister& reg8 = NoCPUReg); + +// AreSameFormat returns true if all of the specified VRegisters have the same +// vector format. Arguments set to NoVReg are ignored, as are any subsequent +// arguments. At least one argument (reg1) must be valid (not NoVReg). +bool AreSameFormat(const VRegister& reg1, const VRegister& reg2, + const VRegister& reg3 = NoVReg, + const VRegister& reg4 = NoVReg); + +// AreConsecutive returns true if all of the specified VRegisters are +// consecutive in the register file. Arguments may be set to NoVReg, and if so, +// subsequent arguments must also be NoVReg. At least one argument (reg1) must +// be valid (not NoVReg). +bool AreConsecutive(const VRegister& reg1, const VRegister& reg2, + const VRegister& reg3 = NoVReg, + const VRegister& reg4 = NoVReg); + +typedef VRegister FloatRegister; +typedef VRegister DoubleRegister; +typedef VRegister Simd128Register; + +// ----------------------------------------------------------------------------- +// Lists of registers. +class CPURegList { + public: + template <typename... CPURegisters> + explicit CPURegList(CPURegister reg0, CPURegisters... regs) + : list_(CPURegister::ListOf(reg0, regs...)), + size_(reg0.SizeInBits()), + type_(reg0.type()) { + DCHECK(AreSameSizeAndType(reg0, regs...)); + DCHECK(IsValid()); + } + + CPURegList(CPURegister::RegisterType type, int size, RegList list) + : list_(list), size_(size), type_(type) { + DCHECK(IsValid()); + } + + CPURegList(CPURegister::RegisterType type, int size, int first_reg, + int last_reg) + : size_(size), type_(type) { + DCHECK( + ((type == CPURegister::kRegister) && (last_reg < kNumberOfRegisters)) || + ((type == CPURegister::kVRegister) && + (last_reg < kNumberOfVRegisters))); + DCHECK(last_reg >= first_reg); + list_ = (1ULL << (last_reg + 1)) - 1; + list_ &= ~((1ULL << first_reg) - 1); + DCHECK(IsValid()); + } + + CPURegister::RegisterType type() const { + DCHECK(IsValid()); + return type_; + } + + RegList list() const { + DCHECK(IsValid()); + return list_; + } + + inline void set_list(RegList new_list) { + DCHECK(IsValid()); + list_ = new_list; + } + + // Combine another CPURegList into this one. Registers that already exist in + // this list are left unchanged. The type and size of the registers in the + // 'other' list must match those in this list. + void Combine(const CPURegList& other); + + // Remove every register in the other CPURegList from this one. Registers that + // do not exist in this list are ignored. The type of the registers in the + // 'other' list must match those in this list. + void Remove(const CPURegList& other); + + // Variants of Combine and Remove which take CPURegisters. + void Combine(const CPURegister& other); + void Remove(const CPURegister& other1, const CPURegister& other2 = NoCPUReg, + const CPURegister& other3 = NoCPUReg, + const CPURegister& other4 = NoCPUReg); + + // Variants of Combine and Remove which take a single register by its code; + // the type and size of the register is inferred from this list. + void Combine(int code); + void Remove(int code); + + // Remove all callee-saved registers from the list. This can be useful when + // preparing registers for an AAPCS64 function call, for example. + void RemoveCalleeSaved(); + + CPURegister PopLowestIndex(); + CPURegister PopHighestIndex(); + + // AAPCS64 callee-saved registers. + static CPURegList GetCalleeSaved(int size = kXRegSizeInBits); + static CPURegList GetCalleeSavedV(int size = kDRegSizeInBits); + + // AAPCS64 caller-saved registers. Note that this includes lr. + // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top + // 64-bits being caller-saved. + static CPURegList GetCallerSaved(int size = kXRegSizeInBits); + static CPURegList GetCallerSavedV(int size = kDRegSizeInBits); + + // Registers saved as safepoints. + static CPURegList GetSafepointSavedRegisters(); + + bool IsEmpty() const { + DCHECK(IsValid()); + return list_ == 0; + } + + bool IncludesAliasOf(const CPURegister& other1, + const CPURegister& other2 = NoCPUReg, + const CPURegister& other3 = NoCPUReg, + const CPURegister& other4 = NoCPUReg) const { + DCHECK(IsValid()); + RegList list = 0; + if (!other1.IsNone() && (other1.type() == type_)) list |= other1.bit(); + if (!other2.IsNone() && (other2.type() == type_)) list |= other2.bit(); + if (!other3.IsNone() && (other3.type() == type_)) list |= other3.bit(); + if (!other4.IsNone() && (other4.type() == type_)) list |= other4.bit(); + return (list_ & list) != 0; + } + + int Count() const { + DCHECK(IsValid()); + return CountSetBits(list_, kRegListSizeInBits); + } + + int RegisterSizeInBits() const { + DCHECK(IsValid()); + return size_; + } + + int RegisterSizeInBytes() const { + int size_in_bits = RegisterSizeInBits(); + DCHECK_EQ(size_in_bits % kBitsPerByte, 0); + return size_in_bits / kBitsPerByte; + } + + int TotalSizeInBytes() const { + DCHECK(IsValid()); + return RegisterSizeInBytes() * Count(); + } + + private: + RegList list_; + int size_; + CPURegister::RegisterType type_; + + bool IsValid() const { + constexpr RegList kValidRegisters{0x8000000ffffffff}; + constexpr RegList kValidVRegisters{0x0000000ffffffff}; + switch (type_) { + case CPURegister::kRegister: + return (list_ & kValidRegisters) == list_; + case CPURegister::kVRegister: + return (list_ & kValidVRegisters) == list_; + case CPURegister::kNoRegister: + return list_ == 0; + default: + UNREACHABLE(); + } + } +}; + +// AAPCS64 callee-saved registers. +#define kCalleeSaved CPURegList::GetCalleeSaved() +#define kCalleeSavedV CPURegList::GetCalleeSavedV() + +// AAPCS64 caller-saved registers. Note that this includes lr. +#define kCallerSaved CPURegList::GetCallerSaved() +#define kCallerSavedV CPURegList::GetCallerSavedV() + +// Define a {RegisterName} method for {CPURegister}. +DEFINE_REGISTER_NAMES(CPURegister, GENERAL_REGISTERS); + +// Give alias names to registers for calling conventions. +constexpr Register kReturnRegister0 = x0; +constexpr Register kReturnRegister1 = x1; +constexpr Register kReturnRegister2 = x2; +constexpr Register kJSFunctionRegister = x1; +constexpr Register kContextRegister = cp; +constexpr Register kAllocateSizeRegister = x1; + +#if defined(V8_OS_WIN) +// x18 is reserved as platform register on Windows ARM64. +constexpr Register kSpeculationPoisonRegister = x23; +#else +constexpr Register kSpeculationPoisonRegister = x18; +#endif + +constexpr Register kInterpreterAccumulatorRegister = x0; +constexpr Register kInterpreterBytecodeOffsetRegister = x19; +constexpr Register kInterpreterBytecodeArrayRegister = x20; +constexpr Register kInterpreterDispatchTableRegister = x21; + +constexpr Register kJavaScriptCallArgCountRegister = x0; +constexpr Register kJavaScriptCallCodeStartRegister = x2; +constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister; +constexpr Register kJavaScriptCallNewTargetRegister = x3; +constexpr Register kJavaScriptCallExtraArg1Register = x2; + +constexpr Register kOffHeapTrampolineRegister = ip0; +constexpr Register kRuntimeCallFunctionRegister = x1; +constexpr Register kRuntimeCallArgCountRegister = x0; +constexpr Register kRuntimeCallArgvRegister = x11; +constexpr Register kWasmInstanceRegister = x7; +constexpr Register kWasmCompileLazyFuncIndexRegister = x8; + +} // namespace internal +} // namespace v8 + +#endif // V8_ARM64_REGISTER_ARM64_H_ |