// 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_X64_REGISTER_X64_H_ #define V8_CODEGEN_X64_REGISTER_X64_H_ #include "src/codegen/register-base.h" namespace v8 { namespace internal { #define GENERAL_REGISTERS(V) \ V(rax) \ V(rcx) \ V(rdx) \ V(rbx) \ V(rsp) \ V(rbp) \ V(rsi) \ V(rdi) \ V(r8) \ V(r9) \ V(r10) \ V(r11) \ V(r12) \ V(r13) \ V(r14) \ V(r15) #define ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \ V(rax) \ V(rbx) \ V(rdx) \ V(rcx) \ V(rsi) \ V(rdi) \ V(r8) \ V(r9) \ V(r11) \ V(r12) \ V(r15) #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE #define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V) #else #define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V) V(r14) #endif #define ALLOCATABLE_GENERAL_REGISTERS(V) \ ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \ MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V) enum RegisterCode { #define REGISTER_CODE(R) kRegCode_##R, GENERAL_REGISTERS(REGISTER_CODE) #undef REGISTER_CODE kRegAfterLast }; class Register : public RegisterBase { public: bool is_byte_register() const { return code() <= 3; } // Return the high bit of the register code as a 0 or 1. Used often // when constructing the REX prefix byte. int high_bit() const { return code() >> 3; } // Return the 3 low bits of the register code. Used when encoding registers // in modR/M, SIB, and opcode bytes. int low_bits() const { return code() & 0x7; } private: friend class RegisterBase; explicit constexpr Register(int code) : RegisterBase(code) {} }; ASSERT_TRIVIALLY_COPYABLE(Register); static_assert(sizeof(Register) <= sizeof(int), "Register can efficiently be passed by value"); #define DECLARE_REGISTER(R) \ constexpr Register R = Register::from_code(kRegCode_##R); GENERAL_REGISTERS(DECLARE_REGISTER) #undef DECLARE_REGISTER constexpr Register no_reg = Register::no_reg(); constexpr int kNumRegs = 16; #ifdef V8_TARGET_OS_WIN // Windows calling convention constexpr Register arg_reg_1 = rcx; constexpr Register arg_reg_2 = rdx; constexpr Register arg_reg_3 = r8; constexpr Register arg_reg_4 = r9; #else // AMD64 calling convention constexpr Register arg_reg_1 = rdi; constexpr Register arg_reg_2 = rsi; constexpr Register arg_reg_3 = rdx; constexpr Register arg_reg_4 = rcx; #endif // V8_TARGET_OS_WIN #define DOUBLE_REGISTERS(V) \ V(xmm0) \ V(xmm1) \ V(xmm2) \ V(xmm3) \ V(xmm4) \ V(xmm5) \ V(xmm6) \ V(xmm7) \ V(xmm8) \ V(xmm9) \ V(xmm10) \ V(xmm11) \ V(xmm12) \ V(xmm13) \ V(xmm14) \ V(xmm15) #define FLOAT_REGISTERS DOUBLE_REGISTERS #define SIMD128_REGISTERS DOUBLE_REGISTERS #define ALLOCATABLE_DOUBLE_REGISTERS(V) \ V(xmm0) \ V(xmm1) \ V(xmm2) \ V(xmm3) \ V(xmm4) \ V(xmm5) \ V(xmm6) \ V(xmm7) \ V(xmm8) \ V(xmm9) \ V(xmm10) \ V(xmm11) \ V(xmm12) \ V(xmm13) \ V(xmm14) #define YMM_REGISTERS(V) \ V(ymm0) \ V(ymm1) \ V(ymm2) \ V(ymm3) \ V(ymm4) \ V(ymm5) \ V(ymm6) \ V(ymm7) \ V(ymm8) \ V(ymm9) \ V(ymm10) \ V(ymm11) \ V(ymm12) \ V(ymm13) \ V(ymm14) \ V(ymm15) // Returns the number of padding slots needed for stack pointer alignment. constexpr int ArgumentPaddingSlots(int argument_count) { // No argument padding required. return 0; } 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 }; enum YMMRegisterCode { #define REGISTER_CODE(R) kYMMCode_##R, YMM_REGISTERS(REGISTER_CODE) #undef REGISTER_CODE kYMMAfterLast }; static_assert(static_cast(kDoubleAfterLast) == static_cast(kYMMAfterLast), "The number of XMM register codes must match the number of YMM " "register codes"); class XMMRegister : public RegisterBase { public: // Return the high bit of the register code as a 0 or 1. Used often // when constructing the REX prefix byte. int high_bit() const { return code() >> 3; } // Return the 3 low bits of the register code. Used when encoding registers // in modR/M, SIB, and opcode bytes. int low_bits() const { return code() & 0x7; } protected: friend class RegisterBase; explicit constexpr XMMRegister(int code) : RegisterBase(code) {} }; ASSERT_TRIVIALLY_COPYABLE(XMMRegister); static_assert(sizeof(XMMRegister) <= sizeof(int), "XMMRegister can efficiently be passed by value"); class YMMRegister : public XMMRegister { public: static constexpr YMMRegister from_code(int code) { DCHECK(base::IsInRange(code, 0, XMMRegister::kNumRegisters - 1)); return YMMRegister(code); } private: friend class XMMRegister; explicit constexpr YMMRegister(int code) : XMMRegister(code) {} }; ASSERT_TRIVIALLY_COPYABLE(YMMRegister); static_assert(sizeof(YMMRegister) <= sizeof(int), "YMMRegister can efficiently be passed by value"); using FloatRegister = XMMRegister; using DoubleRegister = XMMRegister; using Simd128Register = XMMRegister; #define DECLARE_REGISTER(R) \ constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R); DOUBLE_REGISTERS(DECLARE_REGISTER) #undef DECLARE_REGISTER constexpr DoubleRegister no_dreg = DoubleRegister::no_reg(); #define DECLARE_REGISTER(R) \ constexpr YMMRegister R = YMMRegister::from_code(kYMMCode_##R); YMM_REGISTERS(DECLARE_REGISTER) #undef DECLARE_REGISTER // Define {RegisterName} methods for the register types. DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS) DEFINE_REGISTER_NAMES(XMMRegister, DOUBLE_REGISTERS) DEFINE_REGISTER_NAMES(YMMRegister, YMM_REGISTERS) // Give alias names to registers for calling conventions. constexpr Register kReturnRegister0 = rax; constexpr Register kReturnRegister1 = rdx; constexpr Register kReturnRegister2 = r8; constexpr Register kJSFunctionRegister = rdi; constexpr Register kContextRegister = rsi; constexpr Register kAllocateSizeRegister = rdx; constexpr Register kInterpreterAccumulatorRegister = rax; constexpr Register kInterpreterBytecodeOffsetRegister = r9; constexpr Register kInterpreterBytecodeArrayRegister = r12; constexpr Register kInterpreterDispatchTableRegister = r15; constexpr Register kJavaScriptCallArgCountRegister = rax; constexpr Register kJavaScriptCallCodeStartRegister = rcx; constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister; constexpr Register kJavaScriptCallNewTargetRegister = rdx; constexpr Register kJavaScriptCallExtraArg1Register = rbx; constexpr Register kRuntimeCallFunctionRegister = rbx; constexpr Register kRuntimeCallArgCountRegister = rax; constexpr Register kRuntimeCallArgvRegister = r15; constexpr Register kWasmInstanceRegister = rsi; // Default scratch register used by MacroAssembler (and other code that needs // a spare register). The register isn't callee save, and not used by the // function calling convention. constexpr Register kScratchRegister = r10; constexpr XMMRegister kScratchDoubleReg = xmm15; constexpr Register kRootRegister = r13; // callee save #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE constexpr Register kPtrComprCageBaseRegister = r14; // callee save #else constexpr Register kPtrComprCageBaseRegister = kRootRegister; #endif constexpr Register kOffHeapTrampolineRegister = kScratchRegister; constexpr DoubleRegister kFPReturnRegister0 = xmm0; } // namespace internal } // namespace v8 #endif // V8_CODEGEN_X64_REGISTER_X64_H_