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
11namespace v8 {
12namespace 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.
53const 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
79enum RegisterCode {
80#define REGISTER_CODE(R) kRegCode_##R,
81  GENERAL_REGISTERS(REGISTER_CODE)
82#undef REGISTER_CODE
83      kRegAfterLast
84};
85
86class 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;
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);
108GENERAL_REGISTERS(DECLARE_REGISTER)
109#undef DECLARE_REGISTER
110
111constexpr Register no_reg = Register::no_reg();
112
113int ToNumber(Register reg);
114
115Register ToRegister(int num);
116
117// Returns the number of padding slots needed for stack pointer alignment.
118constexpr int ArgumentPaddingSlots(int argument_count) {
119  // No argument padding required.
120  return 0;
121}
122
123constexpr AliasingKind kFPAliasing = AliasingKind::kOverlap;
124constexpr bool kSimdMaskRegisters = false;
125
126enum 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
134class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> {
135  friend class RegisterBase;
136  explicit constexpr MSARegister(int code) : RegisterBase(code) {}
137};
138
139enum DoubleRegisterCode {
140#define REGISTER_CODE(R) kDoubleCode_##R,
141  DOUBLE_REGISTERS(REGISTER_CODE)
142#undef REGISTER_CODE
143      kDoubleAfterLast
144};
145
146// Coprocessor register.
147class 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
153  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  }
159  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
166  MSARegister toW() const { return MSARegister::from_code(code()); }
167
168 private:
169  friend class RegisterBase;
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.
187using FloatRegister = FPURegister;
188
189using DoubleRegister = FPURegister;
190
191#define DECLARE_DOUBLE_REGISTER(R) \
192  constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R);
193DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
194#undef DECLARE_DOUBLE_REGISTER
195
196constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
197
198// SIMD registers.
199using Simd128Register = MSARegister;
200
201#define DECLARE_SIMD128_REGISTER(R) \
202  constexpr Simd128Register R = Simd128Register::from_code(kMsaCode_##R);
203SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
204#undef DECLARE_SIMD128_REGISTER
205
206const Simd128Register no_msareg = Simd128Register::no_reg();
207
208// Register aliases.
209// cp is assumed to be a callee saved register.
210constexpr Register kRootRegister = s6;
211constexpr Register cp = s7;
212constexpr Register kScratchReg = s3;
213constexpr Register kScratchReg2 = s4;
214constexpr DoubleRegister kScratchDoubleReg = f30;
215// FPU zero reg is often used to hold 0.0, but it's not hardwired to 0.0.
216constexpr DoubleRegister kDoubleRegZero = f28;
217// Used on mips64r6 for compare operations.
218// We use the last non-callee saved odd register for N64 ABI
219constexpr 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.
222constexpr Simd128Register kSimd128RegZero = w28;
223constexpr Simd128Register kSimd128ScratchReg = w30;
224
225// FPU (coprocessor 1) control registers.
226// Currently only FCSR (#31) is implemented.
227struct FPUControlRegister {
228  bool is_valid() const { return reg_code == kFCSRRegister; }
229  bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
230  int code() const {
231    DCHECK(is_valid());
232    return reg_code;
233  }
234  int bit() const {
235    DCHECK(is_valid());
236    return 1 << reg_code;
237  }
238  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
246constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
247constexpr FPUControlRegister FCSR = {kFCSRRegister};
248
249// MSA control registers
250struct MSAControlRegister {
251  bool is_valid() const {
252    return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister);
253  }
254  bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; }
255  int code() const {
256    DCHECK(is_valid());
257    return reg_code;
258  }
259  int bit() const {
260    DCHECK(is_valid());
261    return 1 << reg_code;
262  }
263  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
271constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister};
272constexpr MSAControlRegister MSAIR = {kMSAIRRegister};
273constexpr MSAControlRegister MSACSR = {kMSACSRRegister};
274
275// Define {RegisterName} methods for the register types.
276DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
277DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS)
278DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS)
279
280// Give alias names to registers for calling conventions.
281constexpr Register kReturnRegister0 = v0;
282constexpr Register kReturnRegister1 = v1;
283constexpr Register kReturnRegister2 = a0;
284constexpr Register kJSFunctionRegister = a1;
285constexpr Register kContextRegister = s7;
286constexpr Register kAllocateSizeRegister = a0;
287constexpr Register kInterpreterAccumulatorRegister = v0;
288constexpr Register kInterpreterBytecodeOffsetRegister = t0;
289constexpr Register kInterpreterBytecodeArrayRegister = t1;
290constexpr Register kInterpreterDispatchTableRegister = t2;
291
292constexpr Register kJavaScriptCallArgCountRegister = a0;
293constexpr Register kJavaScriptCallCodeStartRegister = a2;
294constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
295constexpr Register kJavaScriptCallNewTargetRegister = a3;
296constexpr Register kJavaScriptCallExtraArg1Register = a2;
297
298constexpr Register kOffHeapTrampolineRegister = at;
299constexpr Register kRuntimeCallFunctionRegister = a1;
300constexpr Register kRuntimeCallArgCountRegister = a0;
301constexpr Register kRuntimeCallArgvRegister = a2;
302constexpr Register kWasmInstanceRegister = a0;
303constexpr Register kWasmCompileLazyFuncIndexRegister = t0;
304
305constexpr DoubleRegister kFPReturnRegister0 = f0;
306
307}  // namespace internal
308}  // namespace v8
309
310#endif  // V8_CODEGEN_MIPS64_REGISTER_MIPS64_H_
311