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