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