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
11namespace v8 {
12namespace 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.
69constexpr 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.
78const int kNumRegs = 32;
79
80const int kUndefIndex = -1;
81// Map with indexes on stack that corresponds to codes of saved registers.
82const 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
138enum RegisterCode {
139#define REGISTER_CODE(R) kRegCode_##R,
140  GENERAL_REGISTERS(REGISTER_CODE)
141#undef REGISTER_CODE
142      kRegAfterLast
143};
144
145class 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;
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);
167GENERAL_REGISTERS(DECLARE_REGISTER)
168#undef DECLARE_REGISTER
169
170constexpr Register no_reg = Register::no_reg();
171
172int ToNumber(Register reg);
173
174Register ToRegister(int num);
175
176constexpr bool kPadArguments = false;
177constexpr AliasingKind kFPAliasing = AliasingKind::kIndependent;
178constexpr bool kSimdMaskRegisters = false;
179
180enum DoubleRegisterCode {
181#define REGISTER_CODE(R) kDoubleCode_##R,
182  DOUBLE_REGISTERS(REGISTER_CODE)
183#undef REGISTER_CODE
184      kDoubleAfterLast
185};
186
187enum VRegisterCode {
188#define REGISTER_CODE(R) kVRCode_##R,
189  VECTOR_REGISTERS(REGISTER_CODE)
190#undef REGISTER_CODE
191      kVRAfterLast
192};
193class VRegister : public RegisterBase<VRegister, kVRAfterLast> {
194  friend class RegisterBase;
195
196 public:
197  explicit constexpr VRegister(int code) : RegisterBase(code) {}
198};
199
200// Coprocessor register.
201class 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
207  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  }
212  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.
221  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;
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.
238using FloatRegister = FPURegister;
239
240using DoubleRegister = FPURegister;
241
242using Simd128Register = VRegister;
243
244#define DECLARE_DOUBLE_REGISTER(R) \
245  constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R);
246DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
247#undef DECLARE_DOUBLE_REGISTER
248
249constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
250
251#define DECLARE_VECTOR_REGISTER(R) \
252  constexpr VRegister R = VRegister::from_code(kVRCode_##R);
253VECTOR_REGISTERS(DECLARE_VECTOR_REGISTER)
254#undef DECLARE_VECTOR_REGISTER
255
256const VRegister no_msareg = VRegister::no_reg();
257
258// Register aliases.
259// cp is assumed to be a callee saved register.
260constexpr Register kRootRegister = s6;
261constexpr Register cp = s7;
262constexpr Register kScratchReg = s3;
263constexpr Register kScratchReg2 = s4;
264
265constexpr DoubleRegister kScratchDoubleReg = ft0;
266
267constexpr DoubleRegister kDoubleRegZero = fs9;
268
269// Define {RegisterName} methods for the register types.
270DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
271DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
272DEFINE_REGISTER_NAMES(VRegister, VECTOR_REGISTERS)
273
274// Give alias names to registers for calling conventions.
275constexpr Register kReturnRegister0 = a0;
276constexpr Register kReturnRegister1 = a1;
277constexpr Register kReturnRegister2 = a2;
278constexpr Register kJSFunctionRegister = a1;
279constexpr Register kContextRegister = s7;
280constexpr Register kAllocateSizeRegister = a1;
281constexpr Register kInterpreterAccumulatorRegister = a0;
282constexpr Register kInterpreterBytecodeOffsetRegister = t0;
283constexpr Register kInterpreterBytecodeArrayRegister = t1;
284constexpr Register kInterpreterDispatchTableRegister = t2;
285
286constexpr Register kJavaScriptCallArgCountRegister = a0;
287constexpr Register kJavaScriptCallCodeStartRegister = a2;
288constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
289constexpr Register kJavaScriptCallNewTargetRegister = a3;
290constexpr Register kJavaScriptCallExtraArg1Register = a2;
291
292constexpr Register kOffHeapTrampolineRegister = t6;
293constexpr Register kRuntimeCallFunctionRegister = a1;
294constexpr Register kRuntimeCallArgCountRegister = a0;
295constexpr Register kRuntimeCallArgvRegister = a2;
296constexpr Register kWasmInstanceRegister = a0;
297constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
298
299constexpr DoubleRegister kFPReturnRegister0 = fa0;
300constexpr VRegister kSimd128ScratchReg = v24;
301constexpr VRegister kSimd128ScratchReg2 = v23;
302constexpr VRegister kSimd128ScratchReg3 = v8;
303constexpr VRegister kSimd128RegZero = v25;
304
305#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE
306constexpr Register kPtrComprCageBaseRegister = s11;  // callee save
307#else
308constexpr Register kPtrComprCageBaseRegister = kRootRegister;
309#endif
310
311}  // namespace internal
312}  // namespace v8
313
314#endif  // V8_CODEGEN_RISCV64_REGISTER_RISCV64_H_
315