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_RISCV64_REGISTER_RISCV64_H_
6 #define V8_CODEGEN_RISCV64_REGISTER_RISCV64_H_
7
8 #include "src/codegen/register-base.h"
9 #include "src/codegen/riscv64/constants-riscv64.h"
10
11 namespace v8 {
12 namespace internal {
13
14 // clang-format off
15
16 #define GENERAL_REGISTERS(V) \
17 V(zero_reg) V(ra) V(sp) V(gp) V(tp) V(t0) V(t1) V(t2) \
18 V(fp) V(s1) V(a0) V(a1) V(a2) V(a3) V(a4) V(a5) \
19 V(a6) V(a7) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(s8) V(s9) \
20 V(s10) V(s11) V(t3) V(t4) V(t5) V(t6)
21
22 // s3: scratch register s4: scratch register 2 used in code-generator-riscv64
23 // s6: roots in Javascript code s7: context register
24 // s11: PtrComprCageBaseRegister
25 // t3 t5 : scratch register used in scratch_register_list
26 // t6 : call reg.
27 // t0 t1 t2 t4:caller saved scratch register can be used in macroassembler and
28 // builtin-riscv64
29 #define ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \
30 V(a0) V(a1) V(a2) V(a3) \
31 V(a4) V(a5) V(a6) V(a7) V(t0) \
32 V(t1) V(t2) V(t4) V(s7) V(s8) V(s9) V(s10)
33
34 #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
35 #define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V)
36 #else
37 #define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V) V(s11)
38 #endif
39
40 #define ALLOCATABLE_GENERAL_REGISTERS(V) \
41 ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \
42 MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V)
43
44 #define DOUBLE_REGISTERS(V) \
45 V(ft0) V(ft1) V(ft2) V(ft3) V(ft4) V(ft5) V(ft6) V(ft7) \
46 V(fs0) V(fs1) V(fa0) V(fa1) V(fa2) V(fa3) V(fa4) V(fa5) \
47 V(fa6) V(fa7) V(fs2) V(fs3) V(fs4) V(fs5) V(fs6) V(fs7) \
48 V(fs8) V(fs9) V(fs10) V(fs11) V(ft8) V(ft9) V(ft10) V(ft11)
49
50 #define FLOAT_REGISTERS DOUBLE_REGISTERS
51 #define VECTOR_REGISTERS(V) \
52 V(v0) V(v1) V(v2) V(v3) V(v4) V(v5) V(v6) V(v7) \
53 V(v8) V(v9) V(v10) V(v11) V(v12) V(v13) V(v14) V(v15) \
54 V(v16) V(v17) V(v18) V(v19) V(v20) V(v21) V(v22) V(v23) \
55 V(v24) V(v25) V(v26) V(v27) V(v28) V(v29) V(v30) V(v31)
56
57 #define ALLOCATABLE_SIMD128_REGISTERS(V) \
58 V(v1) V(v2) V(v3) V(v4) V(v5) V(v6) V(v7) \
59 V(v10) V(v11) V(v12) V(v13) V(v14) V(v15) V(v16) \
60 V(v17) V(v18) V(v19) V(v20) V(v21) V(v22) V(v26) \
61 V(v27) V(v28) V(v29) V(v30) V(v31)
62
63 #define ALLOCATABLE_DOUBLE_REGISTERS(V) \
64 V(ft1) V(ft2) V(ft3) V(ft4) V(ft5) V(ft6) V(ft7) V(ft8) \
65 V(ft9) V(ft10) V(ft11) V(fa0) V(fa1) V(fa2) V(fa3) V(fa4) V(fa5) \
66 V(fa6) V(fa7)
67
68 // Returns the number of padding slots needed for stack pointer alignment.
ArgumentPaddingSlots(int argument_count)69 constexpr int ArgumentPaddingSlots(int argument_count) {
70 // No argument padding required.
71 return 0;
72 }
73
74 // clang-format on
75
76 // Note that the bit values must match those used in actual instruction
77 // encoding.
78 const int kNumRegs = 32;
79
80 const int kUndefIndex = -1;
81 // Map with indexes on stack that corresponds to codes of saved registers.
82 const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg
83 kUndefIndex, // ra
84 kUndefIndex, // sp
85 kUndefIndex, // gp
86 kUndefIndex, // tp
87 0, // t0
88 1, // t1
89 2, // t2
90 3, // s0/fp
91 4, // s1
92 5, // a0
93 6, // a1
94 7, // a2
95 8, // a3
96 9, // a4
97 10, // a5
98 11, // a6
99 12, // a7
100 13, // s2
101 14, // s3
102 15, // s4
103 16, // s5
104 17, // s6
105 18, // s7
106 19, // s8
107 10, // s9
108 21, // s10
109 22, // s11
110 kUndefIndex, // t3
111 23, // t4
112 kUndefIndex, // t5
113 kUndefIndex}; // t6
114 // CPU Registers.
115 //
116 // 1) We would prefer to use an enum, but enum values are assignment-
117 // compatible with int, which has caused code-generation bugs.
118 //
119 // 2) We would prefer to use a class instead of a struct but we don't like
120 // the register initialization to depend on the particular initialization
121 // order (which appears to be different on OS X, Linux, and Windows for the
122 // installed versions of C++ we tried). Using a struct permits C-style
123 // "initialization". Also, the Register objects cannot be const as this
124 // forces initialization stubs in MSVC, making us dependent on initialization
125 // order.
126 //
127 // 3) By not using an enum, we are possibly preventing the compiler from
128 // doing certain constant folds, which may significantly reduce the
129 // code generated for some assembly instructions (because they boil down
130 // to a few constants). If this is a problem, we could change the code
131 // such that we use an enum in optimized mode, and the struct in debug
132 // mode. This way we get the compile-time error checking in debug mode
133 // and best performance in optimized code.
134
135 // -----------------------------------------------------------------------------
136 // Implementation of Register and FPURegister.
137
138 enum RegisterCode {
139 #define REGISTER_CODE(R) kRegCode_##R,
140 GENERAL_REGISTERS(REGISTER_CODE)
141 #undef REGISTER_CODE
142 kRegAfterLast
143 };
144
145 class Register : public RegisterBase<Register, kRegAfterLast> {
146 public:
147 #if defined(V8_TARGET_LITTLE_ENDIAN)
148 static constexpr int kMantissaOffset = 0;
149 static constexpr int kExponentOffset = 4;
150 #elif defined(V8_TARGET_BIG_ENDIAN)
151 static constexpr int kMantissaOffset = 4;
152 static constexpr int kExponentOffset = 0;
153 #else
154 #error Unknown endianness
155 #endif
156
157 private:
158 friend class RegisterBase;
Register(int code)159 explicit constexpr Register(int code) : RegisterBase(code) {}
160 };
161
162 // s7: context register
163 // s3: scratch register
164 // s4: scratch register 2
165 #define DECLARE_REGISTER(R) \
166 constexpr Register R = Register::from_code(kRegCode_##R);
167 GENERAL_REGISTERS(DECLARE_REGISTER)
168 #undef DECLARE_REGISTER
169
170 constexpr Register no_reg = Register::no_reg();
171
172 int ToNumber(Register reg);
173
174 Register ToRegister(int num);
175
176 constexpr bool kPadArguments = false;
177 constexpr AliasingKind kFPAliasing = AliasingKind::kIndependent;
178 constexpr bool kSimdMaskRegisters = false;
179
180 enum DoubleRegisterCode {
181 #define REGISTER_CODE(R) kDoubleCode_##R,
182 DOUBLE_REGISTERS(REGISTER_CODE)
183 #undef REGISTER_CODE
184 kDoubleAfterLast
185 };
186
187 enum VRegisterCode {
188 #define REGISTER_CODE(R) kVRCode_##R,
189 VECTOR_REGISTERS(REGISTER_CODE)
190 #undef REGISTER_CODE
191 kVRAfterLast
192 };
193 class VRegister : public RegisterBase<VRegister, kVRAfterLast> {
194 friend class RegisterBase;
195
196 public:
VRegister(int code)197 explicit constexpr VRegister(int code) : RegisterBase(code) {}
198 };
199
200 // Coprocessor register.
201 class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
202 public:
203 // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
204 // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
205 // number of Double regs (64-bit regs, or FPU-reg-pairs).
206
low() const207 FPURegister low() const {
208 // TODO(plind): Create DCHECK for FR=0 mode. This usage suspect for FR=1.
209 // Find low reg of a Double-reg pair, which is the reg itself.
210 return FPURegister::from_code(code());
211 }
high() const212 FPURegister high() const {
213 // TODO(plind): Create DCHECK for FR=0 mode. This usage illegal in FR=1.
214 // Find high reg of a Doubel-reg pair, which is reg + 1.
215 return FPURegister::from_code(code() + 1);
216 }
217
218 // FIXME(riscv64): In Rvv, Vector regs is different from Float Regs. But in
219 // this cl, in order to facilitate modification, it is assumed that the vector
220 // register and floating point register are shared.
toV() const221 VRegister toV() const {
222 DCHECK(base::IsInRange(static_cast<int>(code()), 0, kVRAfterLast - 1));
223 return VRegister(code());
224 }
225
226 private:
227 friend class RegisterBase;
FPURegister(int code)228 explicit constexpr FPURegister(int code) : RegisterBase(code) {}
229 };
230
231
232 // A few double registers are reserved: one as a scratch register and one to
233 // hold 0.0.
234 // fs9: 0.0
235 // fs11: scratch register.
236
237 // For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
238 using FloatRegister = FPURegister;
239
240 using DoubleRegister = FPURegister;
241
242 using Simd128Register = VRegister;
243
244 #define DECLARE_DOUBLE_REGISTER(R) \
245 constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R);
246 DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
247 #undef DECLARE_DOUBLE_REGISTER
248
249 constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
250
251 #define DECLARE_VECTOR_REGISTER(R) \
252 constexpr VRegister R = VRegister::from_code(kVRCode_##R);
253 VECTOR_REGISTERS(DECLARE_VECTOR_REGISTER)
254 #undef DECLARE_VECTOR_REGISTER
255
256 const VRegister no_msareg = VRegister::no_reg();
257
258 // Register aliases.
259 // cp is assumed to be a callee saved register.
260 constexpr Register kRootRegister = s6;
261 constexpr Register cp = s7;
262 constexpr Register kScratchReg = s3;
263 constexpr Register kScratchReg2 = s4;
264
265 constexpr DoubleRegister kScratchDoubleReg = ft0;
266
267 constexpr DoubleRegister kDoubleRegZero = fs9;
268
269 // Define {RegisterName} methods for the register types.
270 DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
271 DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
272 DEFINE_REGISTER_NAMES(VRegister, VECTOR_REGISTERS)
273
274 // Give alias names to registers for calling conventions.
275 constexpr Register kReturnRegister0 = a0;
276 constexpr Register kReturnRegister1 = a1;
277 constexpr Register kReturnRegister2 = a2;
278 constexpr Register kJSFunctionRegister = a1;
279 constexpr Register kContextRegister = s7;
280 constexpr Register kAllocateSizeRegister = a1;
281 constexpr Register kInterpreterAccumulatorRegister = a0;
282 constexpr Register kInterpreterBytecodeOffsetRegister = t0;
283 constexpr Register kInterpreterBytecodeArrayRegister = t1;
284 constexpr Register kInterpreterDispatchTableRegister = t2;
285
286 constexpr Register kJavaScriptCallArgCountRegister = a0;
287 constexpr Register kJavaScriptCallCodeStartRegister = a2;
288 constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
289 constexpr Register kJavaScriptCallNewTargetRegister = a3;
290 constexpr Register kJavaScriptCallExtraArg1Register = a2;
291
292 constexpr Register kOffHeapTrampolineRegister = t6;
293 constexpr Register kRuntimeCallFunctionRegister = a1;
294 constexpr Register kRuntimeCallArgCountRegister = a0;
295 constexpr Register kRuntimeCallArgvRegister = a2;
296 constexpr Register kWasmInstanceRegister = a0;
297 constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
298
299 constexpr DoubleRegister kFPReturnRegister0 = fa0;
300 constexpr VRegister kSimd128ScratchReg = v24;
301 constexpr VRegister kSimd128ScratchReg2 = v23;
302 constexpr VRegister kSimd128ScratchReg3 = v8;
303 constexpr VRegister kSimd128RegZero = v25;
304
305 #ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
306 constexpr Register kPtrComprCageBaseRegister = s11; // callee save
307 #else
308 constexpr Register kPtrComprCageBaseRegister = kRootRegister;
309 #endif
310
311 } // namespace internal
312 } // namespace v8
313
314 #endif // V8_CODEGEN_RISCV64_REGISTER_RISCV64_H_
315