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_ARM_REGISTER_ARM_H_
6#define V8_CODEGEN_ARM_REGISTER_ARM_H_
7
8#include "src/codegen/register-base.h"
9
10namespace v8 {
11namespace internal {
12
13// clang-format off
14#define GENERAL_REGISTERS(V)                              \
15  V(r0)  V(r1)  V(r2)  V(r3)  V(r4)  V(r5)  V(r6)  V(r7)  \
16  V(r8)  V(r9)  V(r10) V(fp)  V(ip)  V(sp)  V(lr)  V(pc)
17
18#define ALLOCATABLE_GENERAL_REGISTERS(V)                  \
19  V(r0)  V(r1)  V(r2)  V(r3)  V(r4)  V(r5)  V(r6)  V(r7)  \
20  V(r8)  V(r9)
21
22#define FLOAT_REGISTERS(V)                                \
23  V(s0)  V(s1)  V(s2)  V(s3)  V(s4)  V(s5)  V(s6)  V(s7)  \
24  V(s8)  V(s9)  V(s10) V(s11) V(s12) V(s13) V(s14) V(s15) \
25  V(s16) V(s17) V(s18) V(s19) V(s20) V(s21) V(s22) V(s23) \
26  V(s24) V(s25) V(s26) V(s27) V(s28) V(s29) V(s30) V(s31)
27
28#define LOW_DOUBLE_REGISTERS(V)                           \
29  V(d0)  V(d1)  V(d2)  V(d3)  V(d4)  V(d5)  V(d6)  V(d7)  \
30  V(d8)  V(d9)  V(d10) V(d11) V(d12) V(d13) V(d14) V(d15)
31
32#define NON_LOW_DOUBLE_REGISTERS(V)                       \
33  V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
34  V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
35
36#define DOUBLE_REGISTERS(V) \
37  LOW_DOUBLE_REGISTERS(V) NON_LOW_DOUBLE_REGISTERS(V)
38
39#define SIMD128_REGISTERS(V)                              \
40  V(q0)  V(q1)  V(q2)  V(q3)  V(q4)  V(q5)  V(q6)  V(q7)  \
41  V(q8)  V(q9)  V(q10) V(q11) V(q12) V(q13) V(q14) V(q15)
42
43#define ALLOCATABLE_DOUBLE_REGISTERS(V)                   \
44  V(d0)  V(d1)  V(d2)  V(d3)  V(d4)  V(d5)  V(d6)  V(d7)  \
45  V(d8)  V(d9)  V(d10) V(d11) V(d12)                      \
46  V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
47  V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
48
49#define ALLOCATABLE_NO_VFP32_DOUBLE_REGISTERS(V)          \
50  V(d0)  V(d1)  V(d2)  V(d3)  V(d4)  V(d5)  V(d6)  V(d7)  \
51  V(d8)  V(d9)  V(d10) V(d11) V(d12) V(d15)
52
53#define C_REGISTERS(V)                                            \
54  V(cr0)  V(cr1)  V(cr2)  V(cr3)  V(cr4)  V(cr5)  V(cr6)  V(cr7)  \
55  V(cr8)  V(cr9)  V(cr10) V(cr11) V(cr12) V(cr15)
56// clang-format on
57
58// The ARM ABI does not specify the usage of register r9, which may be reserved
59// as the static base or thread register on some platforms, in which case we
60// leave it alone. Adjust the value of kR9Available accordingly:
61const int kR9Available = 1;  // 1 if available to us, 0 if reserved
62
63enum RegisterCode {
64#define REGISTER_CODE(R) kRegCode_##R,
65  GENERAL_REGISTERS(REGISTER_CODE)
66#undef REGISTER_CODE
67      kRegAfterLast
68};
69
70class Register : public RegisterBase<Register, kRegAfterLast> {
71  friend class RegisterBase;
72
73  explicit constexpr Register(int code) : RegisterBase(code) {}
74};
75
76ASSERT_TRIVIALLY_COPYABLE(Register);
77static_assert(sizeof(Register) <= sizeof(int),
78              "Register can efficiently be passed by value");
79
80// r7: context register
81#define DECLARE_REGISTER(R) \
82  constexpr Register R = Register::from_code(kRegCode_##R);
83GENERAL_REGISTERS(DECLARE_REGISTER)
84#undef DECLARE_REGISTER
85constexpr Register no_reg = Register::no_reg();
86
87// Returns the number of padding slots needed for stack pointer alignment.
88constexpr int ArgumentPaddingSlots(int argument_count) {
89  // No argument padding required.
90  return 0;
91}
92
93constexpr AliasingKind kFPAliasing = AliasingKind::kCombine;
94constexpr bool kSimdMaskRegisters = false;
95
96enum SwVfpRegisterCode {
97#define REGISTER_CODE(R) kSwVfpCode_##R,
98  FLOAT_REGISTERS(REGISTER_CODE)
99#undef REGISTER_CODE
100      kSwVfpAfterLast
101};
102
103// Representation of a list of non-overlapping VFP registers. This list
104// represents the data layout of VFP registers as a bitfield:
105//   S registers cover 1 bit
106//   D registers cover 2 bits
107//   Q registers cover 4 bits
108//
109// This way, we make sure no registers in the list ever overlap. However, a list
110// may represent multiple different sets of registers,
111// e.g. [d0 s2 s3] <=> [s0 s1 d1].
112using VfpRegList = uint64_t;
113
114// Single word VFP register.
115class SwVfpRegister : public RegisterBase<SwVfpRegister, kSwVfpAfterLast> {
116 public:
117  static constexpr int kSizeInBytes = 4;
118
119  static void split_code(int reg_code, int* vm, int* m) {
120    DCHECK(from_code(reg_code).is_valid());
121    *m = reg_code & 0x1;
122    *vm = reg_code >> 1;
123  }
124  void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
125  VfpRegList ToVfpRegList() const {
126    DCHECK(is_valid());
127    // Each bit in the list corresponds to a S register.
128    return uint64_t{0x1} << code();
129  }
130
131 private:
132  friend class RegisterBase;
133  explicit constexpr SwVfpRegister(int code) : RegisterBase(code) {}
134};
135
136ASSERT_TRIVIALLY_COPYABLE(SwVfpRegister);
137static_assert(sizeof(SwVfpRegister) <= sizeof(int),
138              "SwVfpRegister can efficiently be passed by value");
139
140using FloatRegister = SwVfpRegister;
141
142enum DoubleRegisterCode {
143#define REGISTER_CODE(R) kDoubleCode_##R,
144  DOUBLE_REGISTERS(REGISTER_CODE)
145#undef REGISTER_CODE
146      kDoubleAfterLast
147};
148
149// Double word VFP register.
150class DwVfpRegister : public RegisterBase<DwVfpRegister, kDoubleAfterLast> {
151 public:
152  static constexpr int kSizeInBytes = 8;
153
154  // This function differs from kNumRegisters by returning the number of double
155  // registers supported by the current CPU, while kNumRegisters always returns
156  // 32.
157  inline static int SupportedRegisterCount();
158
159  static void split_code(int reg_code, int* vm, int* m) {
160    DCHECK(from_code(reg_code).is_valid());
161    *m = (reg_code & 0x10) >> 4;
162    *vm = reg_code & 0x0F;
163  }
164  void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
165  VfpRegList ToVfpRegList() const {
166    DCHECK(is_valid());
167    // A D register overlaps two S registers.
168    return uint64_t{0x3} << (code() * 2);
169  }
170
171 private:
172  friend class RegisterBase;
173  friend class LowDwVfpRegister;
174  explicit constexpr DwVfpRegister(int code) : RegisterBase(code) {}
175};
176
177ASSERT_TRIVIALLY_COPYABLE(DwVfpRegister);
178static_assert(sizeof(DwVfpRegister) <= sizeof(int),
179              "DwVfpRegister can efficiently be passed by value");
180
181using DoubleRegister = DwVfpRegister;
182
183// Double word VFP register d0-15.
184class LowDwVfpRegister
185    : public RegisterBase<LowDwVfpRegister, kDoubleCode_d16> {
186 public:
187  constexpr operator DwVfpRegister() const { return DwVfpRegister(code()); }
188
189  SwVfpRegister low() const { return SwVfpRegister::from_code(code() * 2); }
190  SwVfpRegister high() const {
191    return SwVfpRegister::from_code(code() * 2 + 1);
192  }
193  VfpRegList ToVfpRegList() const {
194    DCHECK(is_valid());
195    // A D register overlaps two S registers.
196    return uint64_t{0x3} << (code() * 2);
197  }
198
199 private:
200  friend class RegisterBase;
201  explicit constexpr LowDwVfpRegister(int code) : RegisterBase(code) {}
202};
203
204enum Simd128RegisterCode {
205#define REGISTER_CODE(R) kSimd128Code_##R,
206  SIMD128_REGISTERS(REGISTER_CODE)
207#undef REGISTER_CODE
208      kSimd128AfterLast
209};
210
211// Quad word NEON register.
212class QwNeonRegister : public RegisterBase<QwNeonRegister, kSimd128AfterLast> {
213 public:
214  static void split_code(int reg_code, int* vm, int* m) {
215    DCHECK(from_code(reg_code).is_valid());
216    int encoded_code = reg_code << 1;
217    *m = (encoded_code & 0x10) >> 4;
218    *vm = encoded_code & 0x0F;
219  }
220  void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
221  DwVfpRegister low() const { return DwVfpRegister::from_code(code() * 2); }
222  DwVfpRegister high() const {
223    return DwVfpRegister::from_code(code() * 2 + 1);
224  }
225  VfpRegList ToVfpRegList() const {
226    DCHECK(is_valid());
227    // A Q register overlaps four S registers.
228    return uint64_t{0xf} << (code() * 4);
229  }
230
231 private:
232  friend class RegisterBase;
233  explicit constexpr QwNeonRegister(int code) : RegisterBase(code) {}
234};
235
236using QuadRegister = QwNeonRegister;
237
238using Simd128Register = QwNeonRegister;
239
240enum CRegisterCode {
241#define REGISTER_CODE(R) kCCode_##R,
242  C_REGISTERS(REGISTER_CODE)
243#undef REGISTER_CODE
244      kCAfterLast
245};
246
247// Coprocessor register
248class CRegister : public RegisterBase<CRegister, kCAfterLast> {
249  friend class RegisterBase;
250  explicit constexpr CRegister(int code) : RegisterBase(code) {}
251};
252
253// Support for the VFP registers s0 to s31 (d0 to d15).
254// Note that "s(N):s(N+1)" is the same as "d(N/2)".
255#define DECLARE_FLOAT_REGISTER(R) \
256  constexpr SwVfpRegister R = SwVfpRegister::from_code(kSwVfpCode_##R);
257FLOAT_REGISTERS(DECLARE_FLOAT_REGISTER)
258#undef DECLARE_FLOAT_REGISTER
259
260#define DECLARE_LOW_DOUBLE_REGISTER(R) \
261  constexpr LowDwVfpRegister R = LowDwVfpRegister::from_code(kDoubleCode_##R);
262LOW_DOUBLE_REGISTERS(DECLARE_LOW_DOUBLE_REGISTER)
263#undef DECLARE_LOW_DOUBLE_REGISTER
264
265#define DECLARE_DOUBLE_REGISTER(R) \
266  constexpr DwVfpRegister R = DwVfpRegister::from_code(kDoubleCode_##R);
267NON_LOW_DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
268#undef DECLARE_DOUBLE_REGISTER
269
270constexpr DwVfpRegister no_dreg = DwVfpRegister::no_reg();
271
272#define DECLARE_SIMD128_REGISTER(R) \
273  constexpr Simd128Register R = Simd128Register::from_code(kSimd128Code_##R);
274SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
275#undef DECLARE_SIMD128_REGISTER
276
277// Aliases for double registers.
278constexpr LowDwVfpRegister kFirstCalleeSavedDoubleReg = d8;
279constexpr LowDwVfpRegister kLastCalleeSavedDoubleReg = d15;
280constexpr LowDwVfpRegister kDoubleRegZero = d13;
281
282constexpr CRegister no_creg = CRegister::no_reg();
283
284#define DECLARE_C_REGISTER(R) \
285  constexpr CRegister R = CRegister::from_code(kCCode_##R);
286C_REGISTERS(DECLARE_C_REGISTER)
287#undef DECLARE_C_REGISTER
288
289// Define {RegisterName} methods for the register types.
290DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
291DEFINE_REGISTER_NAMES(SwVfpRegister, FLOAT_REGISTERS)
292DEFINE_REGISTER_NAMES(DwVfpRegister, DOUBLE_REGISTERS)
293DEFINE_REGISTER_NAMES(LowDwVfpRegister, LOW_DOUBLE_REGISTERS)
294DEFINE_REGISTER_NAMES(QwNeonRegister, SIMD128_REGISTERS)
295DEFINE_REGISTER_NAMES(CRegister, C_REGISTERS)
296
297// Give alias names to registers for calling conventions.
298constexpr Register kReturnRegister0 = r0;
299constexpr Register kReturnRegister1 = r1;
300constexpr Register kReturnRegister2 = r2;
301constexpr Register kJSFunctionRegister = r1;
302constexpr Register kContextRegister = r7;
303constexpr Register kAllocateSizeRegister = r1;
304constexpr Register kInterpreterAccumulatorRegister = r0;
305constexpr Register kInterpreterBytecodeOffsetRegister = r5;
306constexpr Register kInterpreterBytecodeArrayRegister = r6;
307constexpr Register kInterpreterDispatchTableRegister = r8;
308
309constexpr Register kJavaScriptCallArgCountRegister = r0;
310constexpr Register kJavaScriptCallCodeStartRegister = r2;
311constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
312constexpr Register kJavaScriptCallNewTargetRegister = r3;
313constexpr Register kJavaScriptCallExtraArg1Register = r2;
314
315constexpr Register kOffHeapTrampolineRegister = ip;
316constexpr Register kRuntimeCallFunctionRegister = r1;
317constexpr Register kRuntimeCallArgCountRegister = r0;
318constexpr Register kRuntimeCallArgvRegister = r2;
319constexpr Register kWasmInstanceRegister = r3;
320constexpr Register kWasmCompileLazyFuncIndexRegister = r4;
321
322// Give alias names to registers
323constexpr Register cp = r7;              // JavaScript context pointer.
324constexpr Register r11 = fp;
325constexpr Register kRootRegister = r10;  // Roots array pointer.
326
327constexpr DoubleRegister kFPReturnRegister0 = d0;
328
329}  // namespace internal
330}  // namespace v8
331
332#endif  // V8_CODEGEN_ARM_REGISTER_ARM_H_
333