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
11 namespace v8 {
12 namespace 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.
48 const 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
74 enum RegisterCode {
75 #define REGISTER_CODE(R) kRegCode_##R,
76 GENERAL_REGISTERS(REGISTER_CODE)
77 #undef REGISTER_CODE
78 kRegAfterLast
79 };
80
81 class 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;
Register(int code)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);
96 GENERAL_REGISTERS(DECLARE_REGISTER)
97 #undef DECLARE_REGISTER
98
99 constexpr Register no_reg = Register::no_reg();
100
101 int ToNumber(Register reg);
102
103 Register ToRegister(int num);
104
105 // Returns the number of padding slots needed for stack pointer alignment.
ArgumentPaddingSlots(int argument_count)106 constexpr int ArgumentPaddingSlots(int argument_count) {
107 // No argument padding required.
108 return 0;
109 }
110
111 constexpr AliasingKind kFPAliasing = AliasingKind::kOverlap;
112 constexpr bool kSimdMaskRegisters = false;
113
114 enum DoubleRegisterCode {
115 #define REGISTER_CODE(R) kDoubleCode_##R,
116 DOUBLE_REGISTERS(REGISTER_CODE)
117 #undef REGISTER_CODE
118 kDoubleAfterLast
119 };
120
121 // FPURegister register.
122 class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
123 public:
low() const124 FPURegister low() const { return FPURegister::from_code(code()); }
125
126 private:
127 friend class RegisterBase;
FPURegister(int code)128 explicit constexpr FPURegister(int code) : RegisterBase(code) {}
129 };
130
131 // Condition Flag Register
132 enum CFRegister { FCC0, FCC1, FCC2, FCC3, FCC4, FCC5, FCC6, FCC7 };
133
134 using FloatRegister = FPURegister;
135
136 using DoubleRegister = FPURegister;
137
138 using Simd128Register = FPURegister;
139
140 #define DECLARE_DOUBLE_REGISTER(R) \
141 constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R);
142 DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
143 #undef DECLARE_DOUBLE_REGISTER
144
145 constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
146
147 // Register aliases.
148 // cp is assumed to be a callee saved register.
149 constexpr Register kRootRegister = s6;
150 constexpr Register cp = s7;
151 constexpr Register kScratchReg = s3;
152 constexpr Register kScratchReg2 = s4;
153 constexpr DoubleRegister kScratchDoubleReg = f30;
154 constexpr DoubleRegister kScratchDoubleReg1 = f30;
155 constexpr DoubleRegister kScratchDoubleReg2 = f31;
156 // FPU zero reg is often used to hold 0.0, but it's not hardwired to 0.0.
157 constexpr DoubleRegister kDoubleRegZero = f29;
158
159 struct FPUControlRegister {
is_validv8::internal::FPUControlRegister160 bool is_valid() const { return (reg_code >> 2) == 0; }
isv8::internal::FPUControlRegister161 bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
codev8::internal::FPUControlRegister162 int code() const {
163 DCHECK(is_valid());
164 return reg_code;
165 }
bitv8::internal::FPUControlRegister166 int bit() const {
167 DCHECK(is_valid());
168 return 1 << reg_code;
169 }
setcodev8::internal::FPUControlRegister170 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
178 constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
179 constexpr FPUControlRegister FCSR = {kFCSRRegister};
180 constexpr FPUControlRegister FCSR0 = {kFCSRRegister};
181 constexpr FPUControlRegister FCSR1 = {kFCSRRegister + 1};
182 constexpr FPUControlRegister FCSR2 = {kFCSRRegister + 2};
183 constexpr FPUControlRegister FCSR3 = {kFCSRRegister + 3};
184
185 // Define {RegisterName} methods for the register types.
186 DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
187 DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
188
189 // Give alias names to registers for calling conventions.
190 constexpr Register kReturnRegister0 = a0;
191 constexpr Register kReturnRegister1 = a1;
192 constexpr Register kReturnRegister2 = a2;
193 constexpr Register kJSFunctionRegister = a1;
194 constexpr Register kContextRegister = s7;
195 constexpr Register kAllocateSizeRegister = a0;
196 constexpr Register kInterpreterAccumulatorRegister = a0;
197 constexpr Register kInterpreterBytecodeOffsetRegister = t0;
198 constexpr Register kInterpreterBytecodeArrayRegister = t1;
199 constexpr Register kInterpreterDispatchTableRegister = t2;
200
201 constexpr Register kJavaScriptCallArgCountRegister = a0;
202 constexpr Register kJavaScriptCallCodeStartRegister = a2;
203 constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
204 constexpr Register kJavaScriptCallNewTargetRegister = a3;
205 constexpr Register kJavaScriptCallExtraArg1Register = a2;
206
207 constexpr Register kOffHeapTrampolineRegister = t7;
208 constexpr Register kRuntimeCallFunctionRegister = a1;
209 constexpr Register kRuntimeCallArgCountRegister = a0;
210 constexpr Register kRuntimeCallArgvRegister = a2;
211 constexpr Register kWasmInstanceRegister = a0;
212 constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
213
214 constexpr DoubleRegister kFPReturnRegister0 = f0;
215
216 } // namespace internal
217 } // namespace v8
218
219 #endif // V8_CODEGEN_LOONG64_REGISTER_LOONG64_H_
220