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