| // 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_CODEGEN_ARM64_REGISTER_ARM64_H_ |
| #define V8_CODEGEN_ARM64_REGISTER_ARM64_H_ |
| |
| #include "src/codegen/arm64/utils-arm64.h" |
| #include "src/codegen/register-base.h" |
| #include "src/common/globals.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) |
| |
| // x18 is the platform register and is reserved for the use of platform ABIs. |
| // It is known to be reserved by the OS at least on Windows and iOS. |
| #define ALWAYS_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) |
| |
| #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE |
| #define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(R) |
| #else |
| #define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(R) R(x28) |
| #endif |
| |
| #define ALLOCATABLE_GENERAL_REGISTERS(V) \ |
| ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \ |
| MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V) |
| |
| #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) |
| |
| #define VECTOR_REGISTERS(V) \ |
| V(v0) V(v1) V(v2) V(v3) V(v4) V(v5) V(v6) V(v7) \ |
| V(v8) V(v9) V(v10) V(v11) V(v12) V(v13) V(v14) V(v15) \ |
| V(v16) V(v17) V(v18) V(v19) V(v20) V(v21) V(v22) V(v23) \ |
| V(v24) V(v25) V(v26) V(v27) V(v28) V(v29) V(v30) V(v31) |
| |
| // 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 |
| |
| // 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 : int8_t { kRegister, kVRegister, kNoRegister }; |
| |
| static constexpr CPURegister no_reg() { |
| return CPURegister{kCode_no_reg, 0, kNoRegister}; |
| } |
| |
| static constexpr 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(is_valid()); |
| return reg_size_; |
| } |
| int SizeInBytes() const { |
| DCHECK(is_valid()); |
| DCHECK_EQ(SizeInBits() % 8, 0); |
| return reg_size_ / 8; |
| } |
| bool Is8Bits() const { |
| DCHECK(is_valid()); |
| return reg_size_ == 8; |
| } |
| bool Is16Bits() const { |
| DCHECK(is_valid()); |
| return reg_size_ == 16; |
| } |
| bool Is32Bits() const { |
| DCHECK(is_valid()); |
| return reg_size_ == 32; |
| } |
| bool Is64Bits() const { |
| DCHECK(is_valid()); |
| return reg_size_ == 64; |
| } |
| bool Is128Bits() const { |
| DCHECK(is_valid()); |
| return reg_size_ == 128; |
| } |
| bool IsNone() const { return reg_type_ == kNoRegister; } |
| constexpr bool Aliases(const CPURegister& other) const { |
| return RegisterBase::operator==(other) && reg_type_ == other.reg_type_; |
| } |
| |
| constexpr bool operator==(const CPURegister& other) const { |
| return RegisterBase::operator==(other) && reg_size_ == other.reg_size_ && |
| reg_type_ == other.reg_type_; |
| } |
| constexpr bool operator!=(const CPURegister& other) const { |
| return !operator==(other); |
| } |
| |
| 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; |
| |
| protected: |
| uint8_t 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); |
| static_assert(sizeof(CPURegister) <= sizeof(int), |
| "CPURegister can efficiently be passed by value"); |
| |
| class Register : public CPURegister { |
| public: |
| static constexpr Register no_reg() { return Register(CPURegister::no_reg()); } |
| |
| static constexpr 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 constexpr Register from_code(int 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); |
| static_assert(sizeof(Register) <= sizeof(int), |
| "Register can efficiently be passed by value"); |
| |
| // Stack frame alignment and padding. |
| constexpr int ArgumentPaddingSlots(int argument_count) { |
| // Stack frames are aligned to 16 bytes. |
| constexpr int kStackFrameAlignment = 16; |
| constexpr int alignment_mask = kStackFrameAlignment / kSystemPointerSize - 1; |
| return argument_count & alignment_mask; |
| } |
| |
| constexpr AliasingKind kFPAliasing = AliasingKind::kOverlap; |
| 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(int laneSize); |
| VectorFormat VectorFormatFillQ(VectorFormat vform); |
| VectorFormat ScalarFormatFromFormat(VectorFormat vform); |
| V8_EXPORT_PRIVATE unsigned RegisterSizeInBitsFromFormat(VectorFormat vform); |
| unsigned RegisterSizeInBytesFromFormat(VectorFormat vform); |
| int LaneSizeInBytesFromFormat(VectorFormat vform); |
| unsigned LaneSizeInBitsFromFormat(VectorFormat vform); |
| int LaneSizeInBytesLog2FromFormat(VectorFormat vform); |
| V8_EXPORT_PRIVATE int LaneCountFromFormat(VectorFormat vform); |
| int MaxLaneCountFromFormat(VectorFormat vform); |
| V8_EXPORT_PRIVATE 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); |
| } |
| |
| static constexpr 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); |
| } |
| |
| VRegister Format(VectorFormat f) const { |
| return VRegister::Create(code(), f); |
| } |
| |
| 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 constexpr VRegister from_code(int code) { |
| // Always return a D register. |
| return VRegister::Create(code, kDRegSizeInBits); |
| } |
| |
| private: |
| int8_t 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); |
| static_assert(sizeof(VRegister) <= sizeof(int), |
| "VRegister can efficiently be passed by value"); |
| |
| // No*Reg is used to indicate an unused argument, or an error case. Note that |
| // these all compare equal. 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); |
| // Pointer cage base register. |
| #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE |
| ALIAS_REGISTER(Register, kPtrComprCageBaseRegister, x28); |
| #else |
| ALIAS_REGISTER(Register, kPtrComprCageBaseRegister, kRootRegister); |
| #endif |
| // 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. |
| // d29 is not part of ALLOCATABLE_DOUBLE_REGISTERS, so use 27 and 28. |
| ALIAS_REGISTER(VRegister, fp_fixed1, d27); |
| ALIAS_REGISTER(VRegister, fp_fixed2, d28); |
| |
| // 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. |
| V8_EXPORT_PRIVATE 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). |
| V8_EXPORT_PRIVATE 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). |
| V8_EXPORT_PRIVATE bool AreConsecutive(const VRegister& reg1, |
| const VRegister& reg2, |
| const VRegister& reg3 = NoVReg, |
| const VRegister& reg4 = NoVReg); |
| |
| using FloatRegister = VRegister; |
| using DoubleRegister = VRegister; |
| using Simd128Register = VRegister; |
| |
| // Define a {RegisterName} method for {Register} and {VRegister}. |
| DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS) |
| DEFINE_REGISTER_NAMES(VRegister, VECTOR_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; |
| |
| 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; |
| |
| constexpr DoubleRegister kFPReturnRegister0 = d0; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_CODEGEN_ARM64_REGISTER_ARM64_H_ |