1 // Copyright 2018 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_MIPS_REGISTER_MIPS_H_
6 #define V8_CODEGEN_MIPS_REGISTER_MIPS_H_
7
8 #include "src/codegen/mips/constants-mips.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(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
17 V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(t7) \
18 V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
19 V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
20
21 #define ALLOCATABLE_GENERAL_REGISTERS(V) \
22 V(a0) V(a1) V(a2) V(a3) \
23 V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(s7) \
24 V(v0) V(v1)
25
26 #define DOUBLE_REGISTERS(V) \
27 V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
28 V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
29 V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
30 V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
31
32 // Currently, MIPS just use even float point register, except
33 // for C function param registers.
34 #define DOUBLE_USE_REGISTERS(V) \
35 V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f13) \
36 V(f14) V(f15) V(f16) V(f18) V(f20) V(f22) V(f24) V(f26) \
37 V(f28) V(f30)
38
39 #define FLOAT_REGISTERS DOUBLE_REGISTERS
40 #define SIMD128_REGISTERS(V) \
41 V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \
42 V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \
43 V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \
44 V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31)
45
46 #define ALLOCATABLE_DOUBLE_REGISTERS(V) \
47 V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
48 V(f16) V(f18) V(f20) V(f22) V(f24)
49 // clang-format on
50
51 // Register lists.
52 // Note that the bit values must match those used in actual instruction
53 // encoding.
54 const int kNumRegs = 32;
55
56 // CPU Registers.
57 //
58 // 1) We would prefer to use an enum, but enum values are assignment-
59 // compatible with int, which has caused code-generation bugs.
60 //
61 // 2) We would prefer to use a class instead of a struct but we don't like
62 // the register initialization to depend on the particular initialization
63 // order (which appears to be different on OS X, Linux, and Windows for the
64 // installed versions of C++ we tried). Using a struct permits C-style
65 // "initialization". Also, the Register objects cannot be const as this
66 // forces initialization stubs in MSVC, making us dependent on initialization
67 // order.
68 //
69 // 3) By not using an enum, we are possibly preventing the compiler from
70 // doing certain constant folds, which may significantly reduce the
71 // code generated for some assembly instructions (because they boil down
72 // to a few constants). If this is a problem, we could change the code
73 // such that we use an enum in optimized mode, and the struct in debug
74 // mode. This way we get the compile-time error checking in debug mode
75 // and best performance in optimized code.
76
77 // -----------------------------------------------------------------------------
78 // Implementation of Register and FPURegister.
79
80 enum RegisterCode {
81 #define REGISTER_CODE(R) kRegCode_##R,
82 GENERAL_REGISTERS(REGISTER_CODE)
83 #undef REGISTER_CODE
84 kRegAfterLast
85 };
86
87 class Register : public RegisterBase<Register, kRegAfterLast> {
88 public:
89 #if defined(V8_TARGET_LITTLE_ENDIAN)
90 static constexpr int kMantissaOffset = 0;
91 static constexpr int kExponentOffset = 4;
92 #elif defined(V8_TARGET_BIG_ENDIAN)
93 static constexpr int kMantissaOffset = 4;
94 static constexpr int kExponentOffset = 0;
95 #else
96 #error Unknown endianness
97 #endif
98
99 private:
100 friend class RegisterBase;
Register(int code)101 explicit constexpr Register(int code) : RegisterBase(code) {}
102 };
103
104 // s7: context register
105 // s3: scratch register
106 // s4: scratch register 2
107 #define DECLARE_REGISTER(R) \
108 constexpr Register R = Register::from_code(kRegCode_##R);
109 GENERAL_REGISTERS(DECLARE_REGISTER)
110 #undef DECLARE_REGISTER
111 constexpr Register no_reg = Register::no_reg();
112
113 int ToNumber(Register reg);
114
115 Register ToRegister(int num);
116
117 // Returns the number of padding slots needed for stack pointer alignment.
ArgumentPaddingSlots(int argument_count)118 constexpr int ArgumentPaddingSlots(int argument_count) {
119 // No argument padding required.
120 return 0;
121 }
122
123 constexpr AliasingKind kFPAliasing = AliasingKind::kOverlap;
124 constexpr bool kSimdMaskRegisters = false;
125
126 enum DoubleRegisterCode {
127 #define REGISTER_CODE(R) kDoubleCode_##R,
128 DOUBLE_REGISTERS(REGISTER_CODE)
129 #undef REGISTER_CODE
130 kDoubleAfterLast
131 };
132
133 // Coprocessor register.
134 class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
135 public:
low()136 FPURegister low() const {
137 // Find low reg of a Double-reg pair, which is the reg itself.
138 DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
139 return FPURegister::from_code(code());
140 }
high()141 FPURegister high() const {
142 // Find high reg of a Doubel-reg pair, which is reg + 1.
143 DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
144 return FPURegister::from_code(code() + 1);
145 }
146
147 private:
148 friend class RegisterBase;
FPURegister(int code)149 explicit constexpr FPURegister(int code) : RegisterBase(code) {}
150 };
151
152 enum MSARegisterCode {
153 #define REGISTER_CODE(R) kMsaCode_##R,
154 SIMD128_REGISTERS(REGISTER_CODE)
155 #undef REGISTER_CODE
156 kMsaAfterLast
157 };
158
159 // MIPS SIMD (MSA) register
160 class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> {
161 friend class RegisterBase;
MSARegister(int code)162 explicit constexpr MSARegister(int code) : RegisterBase(code) {}
163 };
164
165 // A few double registers are reserved: one as a scratch register and one to
166 // hold 0.0.
167 // f28: 0.0
168 // f30: scratch register.
169
170 // V8 now supports the O32 ABI, and the FPU Registers are organized as 32
171 // 32-bit registers, f0 through f31. When used as 'double' they are used
172 // in pairs, starting with the even numbered register. So a double operation
173 // on f0 really uses f0 and f1.
174 // (Modern mips hardware also supports 32 64-bit registers, via setting
175 // (priviledged) Status Register FR bit to 1. This is used by the N32 ABI,
176 // but it is not in common use. Someday we will want to support this in v8.)
177
178 // For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
179 using FloatRegister = FPURegister;
180
181 using DoubleRegister = FPURegister;
182
183 #define DECLARE_DOUBLE_REGISTER(R) \
184 constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R);
185 DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
186 #undef DECLARE_DOUBLE_REGISTER
187
188 constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
189
190 // SIMD registers.
191 using Simd128Register = MSARegister;
192
193 #define DECLARE_SIMD128_REGISTER(R) \
194 constexpr Simd128Register R = Simd128Register::from_code(kMsaCode_##R);
195 SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
196 #undef DECLARE_SIMD128_REGISTER
197
198 const Simd128Register no_msareg = Simd128Register::no_reg();
199
200 // Register aliases.
201 // cp is assumed to be a callee saved register.
202 constexpr Register kRootRegister = s6;
203 constexpr Register cp = s7;
204 constexpr Register kScratchReg = s3;
205 constexpr Register kScratchReg2 = s4;
206 constexpr DoubleRegister kScratchDoubleReg = f30;
207 constexpr DoubleRegister kDoubleRegZero = f28;
208 // Used on mips32r6 for compare operations.
209 constexpr DoubleRegister kDoubleCompareReg = f26;
210 // MSA zero and scratch regs must have the same numbers as FPU zero and scratch
211 constexpr Simd128Register kSimd128RegZero = w28;
212 constexpr Simd128Register kSimd128ScratchReg = w30;
213
214 // FPU (coprocessor 1) control registers.
215 // Currently only FCSR (#31) is implemented.
216 struct FPUControlRegister {
is_validFPUControlRegister217 bool is_valid() const { return reg_code == kFCSRRegister; }
isFPUControlRegister218 bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
codeFPUControlRegister219 int code() const {
220 DCHECK(is_valid());
221 return reg_code;
222 }
bitFPUControlRegister223 int bit() const {
224 DCHECK(is_valid());
225 return 1 << reg_code;
226 }
setcodeFPUControlRegister227 void setcode(int f) {
228 reg_code = f;
229 DCHECK(is_valid());
230 }
231 // Unfortunately we can't make this private in a struct.
232 int reg_code;
233 };
234
235 constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
236 constexpr FPUControlRegister FCSR = {kFCSRRegister};
237
238 // MSA control registers
239 struct MSAControlRegister {
is_validMSAControlRegister240 bool is_valid() const {
241 return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister);
242 }
isMSAControlRegister243 bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; }
codeMSAControlRegister244 int code() const {
245 DCHECK(is_valid());
246 return reg_code;
247 }
bitMSAControlRegister248 int bit() const {
249 DCHECK(is_valid());
250 return 1 << reg_code;
251 }
setcodeMSAControlRegister252 void setcode(int f) {
253 reg_code = f;
254 DCHECK(is_valid());
255 }
256 // Unfortunately we can't make this private in a struct.
257 int reg_code;
258 };
259
260 constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister};
261 constexpr MSAControlRegister MSAIR = {kMSAIRRegister};
262 constexpr MSAControlRegister MSACSR = {kMSACSRRegister};
263
264 // Define {RegisterName} methods for the register types.
265 DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
266 DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
267 DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS)
268
269 // Give alias names to registers for calling conventions.
270 constexpr Register kReturnRegister0 = v0;
271 constexpr Register kReturnRegister1 = v1;
272 constexpr Register kReturnRegister2 = a0;
273 constexpr Register kJSFunctionRegister = a1;
274 constexpr Register kContextRegister = s7;
275 constexpr Register kAllocateSizeRegister = a0;
276 constexpr Register kInterpreterAccumulatorRegister = v0;
277 constexpr Register kInterpreterBytecodeOffsetRegister = t4;
278 constexpr Register kInterpreterBytecodeArrayRegister = t5;
279 constexpr Register kInterpreterDispatchTableRegister = t6;
280
281 constexpr Register kJavaScriptCallArgCountRegister = a0;
282 constexpr Register kJavaScriptCallCodeStartRegister = a2;
283 constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
284 constexpr Register kJavaScriptCallNewTargetRegister = a3;
285 constexpr Register kJavaScriptCallExtraArg1Register = a2;
286
287 constexpr Register kOffHeapTrampolineRegister = at;
288 constexpr Register kRuntimeCallFunctionRegister = a1;
289 constexpr Register kRuntimeCallArgCountRegister = a0;
290 constexpr Register kRuntimeCallArgvRegister = a2;
291 constexpr Register kWasmInstanceRegister = a0;
292 constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
293
294 constexpr DoubleRegister kFPReturnRegister0 = f0;
295
296 } // namespace internal
297 } // namespace v8
298
299 #endif // V8_CODEGEN_MIPS_REGISTER_MIPS_H_
300