1// Copyright 2021 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_LOONG64_REGISTER_LOONG64_H_ 6#define V8_CODEGEN_LOONG64_REGISTER_LOONG64_H_ 7 8#include "src/codegen/loong64/constants-loong64.h" 9#include "src/codegen/register-base.h" 10 11namespace v8 { 12namespace internal { 13 14// clang-format off 15#define GENERAL_REGISTERS(V) \ 16 V(zero_reg) V(ra) V(tp) V(sp) \ 17 V(a0) V(a1) V(a2) V(a3) V(a4) V(a5) V(a6) V(a7) \ 18 V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(t7) V(t8) \ 19 V(x_reg) V(fp) \ 20 V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(s8) \ 21 22#define ALLOCATABLE_GENERAL_REGISTERS(V) \ 23 V(a0) V(a1) V(a2) V(a3) V(a4) V(a5) V(a6) V(a7) \ 24 V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) \ 25 V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s7) V(s8) 26 27#define DOUBLE_REGISTERS(V) \ 28 V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \ 29 V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \ 30 V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \ 31 V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31) 32 33#define FLOAT_REGISTERS DOUBLE_REGISTERS 34#define SIMD128_REGISTERS(V) \ 35 V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \ 36 V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \ 37 V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \ 38 V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31) 39 40#define ALLOCATABLE_DOUBLE_REGISTERS(V) \ 41 V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \ 42 V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) V(f16) \ 43 V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) 44// clang-format on 45 46// Note that the bit values must match those used in actual instruction 47// encoding. 48const int kNumRegs = 32; 49 50// CPU Registers. 51// 52// 1) We would prefer to use an enum, but enum values are assignment- 53// compatible with int, which has caused code-generation bugs. 54// 55// 2) We would prefer to use a class instead of a struct but we don't like 56// the register initialization to depend on the particular initialization 57// order (which appears to be different on OS X, Linux, and Windows for the 58// installed versions of C++ we tried). Using a struct permits C-style 59// "initialization". Also, the Register objects cannot be const as this 60// forces initialization stubs in MSVC, making us dependent on initialization 61// order. 62// 63// 3) By not using an enum, we are possibly preventing the compiler from 64// doing certain constant folds, which may significantly reduce the 65// code generated for some assembly instructions (because they boil down 66// to a few constants). If this is a problem, we could change the code 67// such that we use an enum in optimized mode, and the struct in debug 68// mode. This way we get the compile-time error checking in debug mode 69// and best performance in optimized code. 70 71// ----------------------------------------------------------------------------- 72// Implementation of Register and FPURegister. 73 74enum RegisterCode { 75#define REGISTER_CODE(R) kRegCode_##R, 76 GENERAL_REGISTERS(REGISTER_CODE) 77#undef REGISTER_CODE 78 kRegAfterLast 79}; 80 81class Register : public RegisterBase<Register, kRegAfterLast> { 82 public: 83 static constexpr int kMantissaOffset = 0; 84 static constexpr int kExponentOffset = 4; 85 86 private: 87 friend class RegisterBase; 88 explicit constexpr Register(int code) : RegisterBase(code) {} 89}; 90 91// s7: context register 92// s3: scratch register 93// s4: scratch register 2 94#define DECLARE_REGISTER(R) \ 95 constexpr Register R = Register::from_code(kRegCode_##R); 96GENERAL_REGISTERS(DECLARE_REGISTER) 97#undef DECLARE_REGISTER 98 99constexpr Register no_reg = Register::no_reg(); 100 101int ToNumber(Register reg); 102 103Register ToRegister(int num); 104 105// Returns the number of padding slots needed for stack pointer alignment. 106constexpr int ArgumentPaddingSlots(int argument_count) { 107 // No argument padding required. 108 return 0; 109} 110 111constexpr AliasingKind kFPAliasing = AliasingKind::kOverlap; 112constexpr bool kSimdMaskRegisters = false; 113 114enum DoubleRegisterCode { 115#define REGISTER_CODE(R) kDoubleCode_##R, 116 DOUBLE_REGISTERS(REGISTER_CODE) 117#undef REGISTER_CODE 118 kDoubleAfterLast 119}; 120 121// FPURegister register. 122class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> { 123 public: 124 FPURegister low() const { return FPURegister::from_code(code()); } 125 126 private: 127 friend class RegisterBase; 128 explicit constexpr FPURegister(int code) : RegisterBase(code) {} 129}; 130 131// Condition Flag Register 132enum CFRegister { FCC0, FCC1, FCC2, FCC3, FCC4, FCC5, FCC6, FCC7 }; 133 134using FloatRegister = FPURegister; 135 136using DoubleRegister = FPURegister; 137 138using Simd128Register = FPURegister; 139 140#define DECLARE_DOUBLE_REGISTER(R) \ 141 constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R); 142DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER) 143#undef DECLARE_DOUBLE_REGISTER 144 145constexpr DoubleRegister no_dreg = DoubleRegister::no_reg(); 146 147// Register aliases. 148// cp is assumed to be a callee saved register. 149constexpr Register kRootRegister = s6; 150constexpr Register cp = s7; 151constexpr Register kScratchReg = s3; 152constexpr Register kScratchReg2 = s4; 153constexpr DoubleRegister kScratchDoubleReg = f30; 154constexpr DoubleRegister kScratchDoubleReg1 = f30; 155constexpr DoubleRegister kScratchDoubleReg2 = f31; 156// FPU zero reg is often used to hold 0.0, but it's not hardwired to 0.0. 157constexpr DoubleRegister kDoubleRegZero = f29; 158 159struct FPUControlRegister { 160 bool is_valid() const { return (reg_code >> 2) == 0; } 161 bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; } 162 int code() const { 163 DCHECK(is_valid()); 164 return reg_code; 165 } 166 int bit() const { 167 DCHECK(is_valid()); 168 return 1 << reg_code; 169 } 170 void setcode(int f) { 171 reg_code = f; 172 DCHECK(is_valid()); 173 } 174 // Unfortunately we can't make this private in a struct. 175 int reg_code; 176}; 177 178constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister}; 179constexpr FPUControlRegister FCSR = {kFCSRRegister}; 180constexpr FPUControlRegister FCSR0 = {kFCSRRegister}; 181constexpr FPUControlRegister FCSR1 = {kFCSRRegister + 1}; 182constexpr FPUControlRegister FCSR2 = {kFCSRRegister + 2}; 183constexpr FPUControlRegister FCSR3 = {kFCSRRegister + 3}; 184 185// Define {RegisterName} methods for the register types. 186DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS) 187DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS) 188 189// Give alias names to registers for calling conventions. 190constexpr Register kReturnRegister0 = a0; 191constexpr Register kReturnRegister1 = a1; 192constexpr Register kReturnRegister2 = a2; 193constexpr Register kJSFunctionRegister = a1; 194constexpr Register kContextRegister = s7; 195constexpr Register kAllocateSizeRegister = a0; 196constexpr Register kInterpreterAccumulatorRegister = a0; 197constexpr Register kInterpreterBytecodeOffsetRegister = t0; 198constexpr Register kInterpreterBytecodeArrayRegister = t1; 199constexpr Register kInterpreterDispatchTableRegister = t2; 200 201constexpr Register kJavaScriptCallArgCountRegister = a0; 202constexpr Register kJavaScriptCallCodeStartRegister = a2; 203constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister; 204constexpr Register kJavaScriptCallNewTargetRegister = a3; 205constexpr Register kJavaScriptCallExtraArg1Register = a2; 206 207constexpr Register kOffHeapTrampolineRegister = t7; 208constexpr Register kRuntimeCallFunctionRegister = a1; 209constexpr Register kRuntimeCallArgCountRegister = a0; 210constexpr Register kRuntimeCallArgvRegister = a2; 211constexpr Register kWasmInstanceRegister = a0; 212constexpr Register kWasmCompileLazyFuncIndexRegister = t0; 213 214constexpr DoubleRegister kFPReturnRegister0 = f0; 215 216} // namespace internal 217} // namespace v8 218 219#endif // V8_CODEGEN_LOONG64_REGISTER_LOONG64_H_ 220