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_MIPS64_REGISTER_MIPS64_H_
6 #define V8_CODEGEN_MIPS64_REGISTER_MIPS64_H_
7 
8 #include "src/codegen/mips64/constants-mips64.h"
9 #include "src/codegen/register.h"
10 #include "src/codegen/reglist.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 // clang-format off
16 #define GENERAL_REGISTERS(V)                              \
17   V(zero_reg)  V(at)  V(v0)  V(v1)  V(a0)  V(a1)  V(a2)  V(a3)  \
18   V(a4)  V(a5)  V(a6)  V(a7)  V(t0)  V(t1)  V(t2)  V(t3)  \
19   V(s0)  V(s1)  V(s2)  V(s3)  V(s4)  V(s5)  V(s6)  V(s7)  V(t8)  V(t9) \
20   V(k0)  V(k1)  V(gp)  V(sp)  V(fp)  V(ra)
21 
22 #define ALLOCATABLE_GENERAL_REGISTERS(V) \
23   V(a0)  V(a1)  V(a2)  V(a3) \
24   V(a4)  V(a5)  V(a6)  V(a7)  V(t0)  V(t1)  V(t2) V(s7) \
25   V(v0)  V(v1)
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(f2)  V(f4)  V(f6)  V(f8)  V(f10) V(f12) V(f14) \
42   V(f16) V(f18) V(f20) V(f22) V(f24) V(f26)
43 // clang-format on
44 
45 // Note that the bit values must match those used in actual instruction
46 // encoding.
47 const int kNumRegs = 32;
48 
49 const RegList kJSCallerSaved = 1 << 2 |   // v0
50                                1 << 3 |   // v1
51                                1 << 4 |   // a0
52                                1 << 5 |   // a1
53                                1 << 6 |   // a2
54                                1 << 7 |   // a3
55                                1 << 8 |   // a4
56                                1 << 9 |   // a5
57                                1 << 10 |  // a6
58                                1 << 11 |  // a7
59                                1 << 12 |  // t0
60                                1 << 13 |  // t1
61                                1 << 14 |  // t2
62                                1 << 15;   // t3
63 
64 const int kNumJSCallerSaved = 14;
65 
66 // Callee-saved registers preserved when switching from C to JavaScript.
67 const RegList kCalleeSaved = 1 << 16 |  // s0
68                              1 << 17 |  // s1
69                              1 << 18 |  // s2
70                              1 << 19 |  // s3
71                              1 << 20 |  // s4
72                              1 << 21 |  // s5
73                              1 << 22 |  // s6 (roots in Javascript code)
74                              1 << 23 |  // s7 (cp in Javascript code)
75                              1 << 30;   // fp/s8
76 
77 const int kNumCalleeSaved = 9;
78 
79 const RegList kCalleeSavedFPU = 1 << 20 |  // f20
80                                 1 << 22 |  // f22
81                                 1 << 24 |  // f24
82                                 1 << 26 |  // f26
83                                 1 << 28 |  // f28
84                                 1 << 30;   // f30
85 
86 const int kNumCalleeSavedFPU = 6;
87 
88 const RegList kCallerSavedFPU = 1 << 0 |   // f0
89                                 1 << 2 |   // f2
90                                 1 << 4 |   // f4
91                                 1 << 6 |   // f6
92                                 1 << 8 |   // f8
93                                 1 << 10 |  // f10
94                                 1 << 12 |  // f12
95                                 1 << 14 |  // f14
96                                 1 << 16 |  // f16
97                                 1 << 18;   // f18
98 
99 // Number of registers for which space is reserved in safepoints. Must be a
100 // multiple of 8.
101 const int kNumSafepointRegisters = 24;
102 
103 // Define the list of registers actually saved at safepoints.
104 // Note that the number of saved registers may be smaller than the reserved
105 // space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
106 const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
107 const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
108 
109 const int kUndefIndex = -1;
110 // Map with indexes on stack that corresponds to codes of saved registers.
111 const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex,  // zero_reg
112                                                        kUndefIndex,  // at
113                                                        0,            // v0
114                                                        1,            // v1
115                                                        2,            // a0
116                                                        3,            // a1
117                                                        4,            // a2
118                                                        5,            // a3
119                                                        6,            // a4
120                                                        7,            // a5
121                                                        8,            // a6
122                                                        9,            // a7
123                                                        10,           // t0
124                                                        11,           // t1
125                                                        12,           // t2
126                                                        13,           // t3
127                                                        14,           // s0
128                                                        15,           // s1
129                                                        16,           // s2
130                                                        17,           // s3
131                                                        18,           // s4
132                                                        19,           // s5
133                                                        20,           // s6
134                                                        21,           // s7
135                                                        kUndefIndex,  // t8
136                                                        kUndefIndex,  // t9
137                                                        kUndefIndex,  // k0
138                                                        kUndefIndex,  // k1
139                                                        kUndefIndex,  // gp
140                                                        kUndefIndex,  // sp
141                                                        22,           // fp
142                                                        kUndefIndex};
143 
144 // CPU Registers.
145 //
146 // 1) We would prefer to use an enum, but enum values are assignment-
147 // compatible with int, which has caused code-generation bugs.
148 //
149 // 2) We would prefer to use a class instead of a struct but we don't like
150 // the register initialization to depend on the particular initialization
151 // order (which appears to be different on OS X, Linux, and Windows for the
152 // installed versions of C++ we tried). Using a struct permits C-style
153 // "initialization". Also, the Register objects cannot be const as this
154 // forces initialization stubs in MSVC, making us dependent on initialization
155 // order.
156 //
157 // 3) By not using an enum, we are possibly preventing the compiler from
158 // doing certain constant folds, which may significantly reduce the
159 // code generated for some assembly instructions (because they boil down
160 // to a few constants). If this is a problem, we could change the code
161 // such that we use an enum in optimized mode, and the struct in debug
162 // mode. This way we get the compile-time error checking in debug mode
163 // and best performance in optimized code.
164 
165 // -----------------------------------------------------------------------------
166 // Implementation of Register and FPURegister.
167 
168 enum RegisterCode {
169 #define REGISTER_CODE(R) kRegCode_##R,
170   GENERAL_REGISTERS(REGISTER_CODE)
171 #undef REGISTER_CODE
172       kRegAfterLast
173 };
174 
175 class Register : public RegisterBase<Register, kRegAfterLast> {
176  public:
177 #if defined(V8_TARGET_LITTLE_ENDIAN)
178   static constexpr int kMantissaOffset = 0;
179   static constexpr int kExponentOffset = 4;
180 #elif defined(V8_TARGET_BIG_ENDIAN)
181   static constexpr int kMantissaOffset = 4;
182   static constexpr int kExponentOffset = 0;
183 #else
184 #error Unknown endianness
185 #endif
186 
187  private:
188   friend class RegisterBase;
Register(int code)189   explicit constexpr Register(int code) : RegisterBase(code) {}
190 };
191 
192 // s7: context register
193 // s3: scratch register
194 // s4: scratch register 2
195 #define DECLARE_REGISTER(R) \
196   constexpr Register R = Register::from_code(kRegCode_##R);
197 GENERAL_REGISTERS(DECLARE_REGISTER)
198 #undef DECLARE_REGISTER
199 
200 constexpr Register no_reg = Register::no_reg();
201 
202 int ToNumber(Register reg);
203 
204 Register ToRegister(int num);
205 
206 constexpr bool kPadArguments = false;
207 constexpr bool kSimpleFPAliasing = true;
208 constexpr bool kSimdMaskRegisters = false;
209 
210 enum MSARegisterCode {
211 #define REGISTER_CODE(R) kMsaCode_##R,
212   SIMD128_REGISTERS(REGISTER_CODE)
213 #undef REGISTER_CODE
214       kMsaAfterLast
215 };
216 
217 // MIPS SIMD (MSA) register
218 class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> {
219   friend class RegisterBase;
MSARegister(int code)220   explicit constexpr MSARegister(int code) : RegisterBase(code) {}
221 };
222 
223 enum DoubleRegisterCode {
224 #define REGISTER_CODE(R) kDoubleCode_##R,
225   DOUBLE_REGISTERS(REGISTER_CODE)
226 #undef REGISTER_CODE
227       kDoubleAfterLast
228 };
229 
230 // Coprocessor register.
231 class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
232  public:
233   // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
234   // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
235   // number of Double regs (64-bit regs, or FPU-reg-pairs).
236 
low()237   FPURegister low() const {
238     // TODO(plind): Create DCHECK for FR=0 mode. This usage suspect for FR=1.
239     // Find low reg of a Double-reg pair, which is the reg itself.
240     DCHECK_EQ(code() % 2, 0);  // Specified Double reg must be even.
241     return FPURegister::from_code(code());
242   }
high()243   FPURegister high() const {
244     // TODO(plind): Create DCHECK for FR=0 mode. This usage illegal in FR=1.
245     // Find high reg of a Doubel-reg pair, which is reg + 1.
246     DCHECK_EQ(code() % 2, 0);  // Specified Double reg must be even.
247     return FPURegister::from_code(code() + 1);
248   }
249 
toW()250   MSARegister toW() const { return MSARegister::from_code(code()); }
251 
252  private:
253   friend class RegisterBase;
FPURegister(int code)254   explicit constexpr FPURegister(int code) : RegisterBase(code) {}
255 };
256 
257 // A few double registers are reserved: one as a scratch register and one to
258 // hold 0.0.
259 //  f28: 0.0
260 //  f30: scratch register.
261 
262 // V8 now supports the O32 ABI, and the FPU Registers are organized as 32
263 // 32-bit registers, f0 through f31. When used as 'double' they are used
264 // in pairs, starting with the even numbered register. So a double operation
265 // on f0 really uses f0 and f1.
266 // (Modern mips hardware also supports 32 64-bit registers, via setting
267 // (privileged) Status Register FR bit to 1. This is used by the N32 ABI,
268 // but it is not in common use. Someday we will want to support this in v8.)
269 
270 // For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
271 using FloatRegister = FPURegister;
272 
273 using DoubleRegister = FPURegister;
274 
275 #define DECLARE_DOUBLE_REGISTER(R) \
276   constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R);
277 DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
278 #undef DECLARE_DOUBLE_REGISTER
279 
280 constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
281 
282 // SIMD registers.
283 using Simd128Register = MSARegister;
284 
285 #define DECLARE_SIMD128_REGISTER(R) \
286   constexpr Simd128Register R = Simd128Register::from_code(kMsaCode_##R);
287 SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
288 #undef DECLARE_SIMD128_REGISTER
289 
290 const Simd128Register no_msareg = Simd128Register::no_reg();
291 
292 // Register aliases.
293 // cp is assumed to be a callee saved register.
294 constexpr Register kRootRegister = s6;
295 constexpr Register cp = s7;
296 constexpr Register kScratchReg = s3;
297 constexpr Register kScratchReg2 = s4;
298 constexpr DoubleRegister kScratchDoubleReg = f30;
299 // FPU zero reg is often used to hold 0.0, but it's not hardwired to 0.0.
300 constexpr DoubleRegister kDoubleRegZero = f28;
301 // Used on mips64r6 for compare operations.
302 // We use the last non-callee saved odd register for N64 ABI
303 constexpr DoubleRegister kDoubleCompareReg = f23;
304 // MSA zero and scratch regs must have the same numbers as FPU zero and scratch
305 // MSA zero reg is often used to hold 0, but it's not hardwired to 0.
306 constexpr Simd128Register kSimd128RegZero = w28;
307 constexpr Simd128Register kSimd128ScratchReg = w30;
308 
309 // FPU (coprocessor 1) control registers.
310 // Currently only FCSR (#31) is implemented.
311 struct FPUControlRegister {
is_validFPUControlRegister312   bool is_valid() const { return reg_code == kFCSRRegister; }
isFPUControlRegister313   bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
codeFPUControlRegister314   int code() const {
315     DCHECK(is_valid());
316     return reg_code;
317   }
bitFPUControlRegister318   int bit() const {
319     DCHECK(is_valid());
320     return 1 << reg_code;
321   }
setcodeFPUControlRegister322   void setcode(int f) {
323     reg_code = f;
324     DCHECK(is_valid());
325   }
326   // Unfortunately we can't make this private in a struct.
327   int reg_code;
328 };
329 
330 constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
331 constexpr FPUControlRegister FCSR = {kFCSRRegister};
332 
333 // MSA control registers
334 struct MSAControlRegister {
is_validMSAControlRegister335   bool is_valid() const {
336     return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister);
337   }
isMSAControlRegister338   bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; }
codeMSAControlRegister339   int code() const {
340     DCHECK(is_valid());
341     return reg_code;
342   }
bitMSAControlRegister343   int bit() const {
344     DCHECK(is_valid());
345     return 1 << reg_code;
346   }
setcodeMSAControlRegister347   void setcode(int f) {
348     reg_code = f;
349     DCHECK(is_valid());
350   }
351   // Unfortunately we can't make this private in a struct.
352   int reg_code;
353 };
354 
355 constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister};
356 constexpr MSAControlRegister MSAIR = {kMSAIRRegister};
357 constexpr MSAControlRegister MSACSR = {kMSACSRRegister};
358 
359 // Define {RegisterName} methods for the register types.
360 DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
361 DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
362 DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS)
363 
364 // Give alias names to registers for calling conventions.
365 constexpr Register kReturnRegister0 = v0;
366 constexpr Register kReturnRegister1 = v1;
367 constexpr Register kReturnRegister2 = a0;
368 constexpr Register kJSFunctionRegister = a1;
369 constexpr Register kContextRegister = s7;
370 constexpr Register kAllocateSizeRegister = a0;
371 constexpr Register kSpeculationPoisonRegister = a7;
372 constexpr Register kInterpreterAccumulatorRegister = v0;
373 constexpr Register kInterpreterBytecodeOffsetRegister = t0;
374 constexpr Register kInterpreterBytecodeArrayRegister = t1;
375 constexpr Register kInterpreterDispatchTableRegister = t2;
376 
377 constexpr Register kJavaScriptCallArgCountRegister = a0;
378 constexpr Register kJavaScriptCallCodeStartRegister = a2;
379 constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
380 constexpr Register kJavaScriptCallNewTargetRegister = a3;
381 constexpr Register kJavaScriptCallExtraArg1Register = a2;
382 
383 constexpr Register kOffHeapTrampolineRegister = at;
384 constexpr Register kRuntimeCallFunctionRegister = a1;
385 constexpr Register kRuntimeCallArgCountRegister = a0;
386 constexpr Register kRuntimeCallArgvRegister = a2;
387 constexpr Register kWasmInstanceRegister = a0;
388 constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
389 
390 constexpr DoubleRegister kFPReturnRegister0 = f0;
391 
392 }  // namespace internal
393 }  // namespace v8
394 
395 #endif  // V8_CODEGEN_MIPS64_REGISTER_MIPS64_H_
396