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-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(a4)  V(a5)  V(a6)  V(a7)  V(t0)  V(t1)  V(t2)  V(t3)  \
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(a4)  V(a5)  V(a6)  V(a7)  V(t0)  V(t1)  V(t2)  V(t3)  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, MIPS64 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(f17) V(f18) V(f19) V(f20) V(f22) \
37   V(f24) V(f26) 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) V(f26)
49 // clang-format on
50 
51 // Note that the bit values must match those used in actual instruction
52 // encoding.
53 const int kNumRegs = 32;
54 
55 // CPU Registers.
56 //
57 // 1) We would prefer to use an enum, but enum values are assignment-
58 // compatible with int, which has caused code-generation bugs.
59 //
60 // 2) We would prefer to use a class instead of a struct but we don't like
61 // the register initialization to depend on the particular initialization
62 // order (which appears to be different on OS X, Linux, and Windows for the
63 // installed versions of C++ we tried). Using a struct permits C-style
64 // "initialization". Also, the Register objects cannot be const as this
65 // forces initialization stubs in MSVC, making us dependent on initialization
66 // order.
67 //
68 // 3) By not using an enum, we are possibly preventing the compiler from
69 // doing certain constant folds, which may significantly reduce the
70 // code generated for some assembly instructions (because they boil down
71 // to a few constants). If this is a problem, we could change the code
72 // such that we use an enum in optimized mode, and the struct in debug
73 // mode. This way we get the compile-time error checking in debug mode
74 // and best performance in optimized code.
75 
76 // -----------------------------------------------------------------------------
77 // Implementation of Register and FPURegister.
78 
79 enum RegisterCode {
80 #define REGISTER_CODE(R) kRegCode_##R,
81   GENERAL_REGISTERS(REGISTER_CODE)
82 #undef REGISTER_CODE
83       kRegAfterLast
84 };
85 
86 class Register : public RegisterBase<Register, kRegAfterLast> {
87  public:
88 #if defined(V8_TARGET_LITTLE_ENDIAN)
89   static constexpr int kMantissaOffset = 0;
90   static constexpr int kExponentOffset = 4;
91 #elif defined(V8_TARGET_BIG_ENDIAN)
92   static constexpr int kMantissaOffset = 4;
93   static constexpr int kExponentOffset = 0;
94 #else
95 #error Unknown endianness
96 #endif
97 
98  private:
99   friend class RegisterBase;
Register(int code)100   explicit constexpr Register(int code) : RegisterBase(code) {}
101 };
102 
103 // s7: context register
104 // s3: scratch register
105 // s4: scratch register 2
106 #define DECLARE_REGISTER(R) \
107   constexpr Register R = Register::from_code(kRegCode_##R);
108 GENERAL_REGISTERS(DECLARE_REGISTER)
109 #undef DECLARE_REGISTER
110 
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 MSARegisterCode {
127 #define REGISTER_CODE(R) kMsaCode_##R,
128   SIMD128_REGISTERS(REGISTER_CODE)
129 #undef REGISTER_CODE
130       kMsaAfterLast
131 };
132 
133 // MIPS SIMD (MSA) register
134 class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> {
135   friend class RegisterBase;
MSARegister(int code)136   explicit constexpr MSARegister(int code) : RegisterBase(code) {}
137 };
138 
139 enum DoubleRegisterCode {
140 #define REGISTER_CODE(R) kDoubleCode_##R,
141   DOUBLE_REGISTERS(REGISTER_CODE)
142 #undef REGISTER_CODE
143       kDoubleAfterLast
144 };
145 
146 // Coprocessor register.
147 class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
148  public:
149   // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers
150   // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to
151   // number of Double regs (64-bit regs, or FPU-reg-pairs).
152 
low() const153   FPURegister low() const {
154     // TODO(plind): Create DCHECK for FR=0 mode. This usage suspect for FR=1.
155     // Find low reg of a Double-reg pair, which is the reg itself.
156     DCHECK_EQ(code() % 2, 0);  // Specified Double reg must be even.
157     return FPURegister::from_code(code());
158   }
high() const159   FPURegister high() const {
160     // TODO(plind): Create DCHECK for FR=0 mode. This usage illegal in FR=1.
161     // Find high reg of a Doubel-reg pair, which is reg + 1.
162     DCHECK_EQ(code() % 2, 0);  // Specified Double reg must be even.
163     return FPURegister::from_code(code() + 1);
164   }
165 
toW() const166   MSARegister toW() const { return MSARegister::from_code(code()); }
167 
168  private:
169   friend class RegisterBase;
FPURegister(int code)170   explicit constexpr FPURegister(int code) : RegisterBase(code) {}
171 };
172 
173 // A few double registers are reserved: one as a scratch register and one to
174 // hold 0.0.
175 //  f28: 0.0
176 //  f30: scratch register.
177 
178 // V8 now supports the O32 ABI, and the FPU Registers are organized as 32
179 // 32-bit registers, f0 through f31. When used as 'double' they are used
180 // in pairs, starting with the even numbered register. So a double operation
181 // on f0 really uses f0 and f1.
182 // (Modern mips hardware also supports 32 64-bit registers, via setting
183 // (privileged) Status Register FR bit to 1. This is used by the N32 ABI,
184 // but it is not in common use. Someday we will want to support this in v8.)
185 
186 // For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
187 using FloatRegister = FPURegister;
188 
189 using DoubleRegister = FPURegister;
190 
191 #define DECLARE_DOUBLE_REGISTER(R) \
192   constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R);
193 DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
194 #undef DECLARE_DOUBLE_REGISTER
195 
196 constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
197 
198 // SIMD registers.
199 using Simd128Register = MSARegister;
200 
201 #define DECLARE_SIMD128_REGISTER(R) \
202   constexpr Simd128Register R = Simd128Register::from_code(kMsaCode_##R);
203 SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
204 #undef DECLARE_SIMD128_REGISTER
205 
206 const Simd128Register no_msareg = Simd128Register::no_reg();
207 
208 // Register aliases.
209 // cp is assumed to be a callee saved register.
210 constexpr Register kRootRegister = s6;
211 constexpr Register cp = s7;
212 constexpr Register kScratchReg = s3;
213 constexpr Register kScratchReg2 = s4;
214 constexpr DoubleRegister kScratchDoubleReg = f30;
215 // FPU zero reg is often used to hold 0.0, but it's not hardwired to 0.0.
216 constexpr DoubleRegister kDoubleRegZero = f28;
217 // Used on mips64r6 for compare operations.
218 // We use the last non-callee saved odd register for N64 ABI
219 constexpr DoubleRegister kDoubleCompareReg = f23;
220 // MSA zero and scratch regs must have the same numbers as FPU zero and scratch
221 // MSA zero reg is often used to hold 0, but it's not hardwired to 0.
222 constexpr Simd128Register kSimd128RegZero = w28;
223 constexpr Simd128Register kSimd128ScratchReg = w30;
224 
225 // FPU (coprocessor 1) control registers.
226 // Currently only FCSR (#31) is implemented.
227 struct FPUControlRegister {
is_validv8::internal::FPUControlRegister228   bool is_valid() const { return reg_code == kFCSRRegister; }
isv8::internal::FPUControlRegister229   bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
codev8::internal::FPUControlRegister230   int code() const {
231     DCHECK(is_valid());
232     return reg_code;
233   }
bitv8::internal::FPUControlRegister234   int bit() const {
235     DCHECK(is_valid());
236     return 1 << reg_code;
237   }
setcodev8::internal::FPUControlRegister238   void setcode(int f) {
239     reg_code = f;
240     DCHECK(is_valid());
241   }
242   // Unfortunately we can't make this private in a struct.
243   int reg_code;
244 };
245 
246 constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
247 constexpr FPUControlRegister FCSR = {kFCSRRegister};
248 
249 // MSA control registers
250 struct MSAControlRegister {
is_validv8::internal::MSAControlRegister251   bool is_valid() const {
252     return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister);
253   }
isv8::internal::MSAControlRegister254   bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; }
codev8::internal::MSAControlRegister255   int code() const {
256     DCHECK(is_valid());
257     return reg_code;
258   }
bitv8::internal::MSAControlRegister259   int bit() const {
260     DCHECK(is_valid());
261     return 1 << reg_code;
262   }
setcodev8::internal::MSAControlRegister263   void setcode(int f) {
264     reg_code = f;
265     DCHECK(is_valid());
266   }
267   // Unfortunately we can't make this private in a struct.
268   int reg_code;
269 };
270 
271 constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister};
272 constexpr MSAControlRegister MSAIR = {kMSAIRRegister};
273 constexpr MSAControlRegister MSACSR = {kMSACSRRegister};
274 
275 // Define {RegisterName} methods for the register types.
276 DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
277 DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
278 DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS)
279 
280 // Give alias names to registers for calling conventions.
281 constexpr Register kReturnRegister0 = v0;
282 constexpr Register kReturnRegister1 = v1;
283 constexpr Register kReturnRegister2 = a0;
284 constexpr Register kJSFunctionRegister = a1;
285 constexpr Register kContextRegister = s7;
286 constexpr Register kAllocateSizeRegister = a0;
287 constexpr Register kInterpreterAccumulatorRegister = v0;
288 constexpr Register kInterpreterBytecodeOffsetRegister = t0;
289 constexpr Register kInterpreterBytecodeArrayRegister = t1;
290 constexpr Register kInterpreterDispatchTableRegister = t2;
291 
292 constexpr Register kJavaScriptCallArgCountRegister = a0;
293 constexpr Register kJavaScriptCallCodeStartRegister = a2;
294 constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
295 constexpr Register kJavaScriptCallNewTargetRegister = a3;
296 constexpr Register kJavaScriptCallExtraArg1Register = a2;
297 
298 constexpr Register kOffHeapTrampolineRegister = at;
299 constexpr Register kRuntimeCallFunctionRegister = a1;
300 constexpr Register kRuntimeCallArgCountRegister = a0;
301 constexpr Register kRuntimeCallArgvRegister = a2;
302 constexpr Register kWasmInstanceRegister = a0;
303 constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
304 
305 constexpr DoubleRegister kFPReturnRegister0 = f0;
306 
307 }  // namespace internal
308 }  // namespace v8
309 
310 #endif  // V8_CODEGEN_MIPS64_REGISTER_MIPS64_H_
311