• 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-base.h"
9 
10 namespace v8 {
11 namespace 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:
61 const int kR9Available = 1;  // 1 if available to us, 0 if reserved
62 
63 enum RegisterCode {
64 #define REGISTER_CODE(R) kRegCode_##R,
65   GENERAL_REGISTERS(REGISTER_CODE)
66 #undef REGISTER_CODE
67       kRegAfterLast
68 };
69 
70 class Register : public RegisterBase<Register, kRegAfterLast> {
71   friend class RegisterBase;
72 
Register(int code)73   explicit constexpr Register(int code) : RegisterBase(code) {}
74 };
75 
76 ASSERT_TRIVIALLY_COPYABLE(Register);
77 static_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);
83 GENERAL_REGISTERS(DECLARE_REGISTER)
84 #undef DECLARE_REGISTER
85 constexpr Register no_reg = Register::no_reg();
86 
87 // Returns the number of padding slots needed for stack pointer alignment.
ArgumentPaddingSlots(int argument_count)88 constexpr int ArgumentPaddingSlots(int argument_count) {
89   // No argument padding required.
90   return 0;
91 }
92 
93 constexpr AliasingKind kFPAliasing = AliasingKind::kCombine;
94 constexpr bool kSimdMaskRegisters = false;
95 
96 enum 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].
112 using VfpRegList = uint64_t;
113 
114 // Single word VFP register.
115 class SwVfpRegister : public RegisterBase<SwVfpRegister, kSwVfpAfterLast> {
116  public:
117   static constexpr int kSizeInBytes = 4;
118 
split_code(int reg_code,int * vm,int * m)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   }
split_code(int * vm,int * m)124   void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
ToVfpRegList()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;
SwVfpRegister(int code)133   explicit constexpr SwVfpRegister(int code) : RegisterBase(code) {}
134 };
135 
136 ASSERT_TRIVIALLY_COPYABLE(SwVfpRegister);
137 static_assert(sizeof(SwVfpRegister) <= sizeof(int),
138               "SwVfpRegister can efficiently be passed by value");
139 
140 using FloatRegister = SwVfpRegister;
141 
142 enum 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.
150 class 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 
split_code(int reg_code,int * vm,int * m)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   }
split_code(int * vm,int * m)164   void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
ToVfpRegList()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;
DwVfpRegister(int code)174   explicit constexpr DwVfpRegister(int code) : RegisterBase(code) {}
175 };
176 
177 ASSERT_TRIVIALLY_COPYABLE(DwVfpRegister);
178 static_assert(sizeof(DwVfpRegister) <= sizeof(int),
179               "DwVfpRegister can efficiently be passed by value");
180 
181 using DoubleRegister = DwVfpRegister;
182 
183 // Double word VFP register d0-15.
184 class LowDwVfpRegister
185     : public RegisterBase<LowDwVfpRegister, kDoubleCode_d16> {
186  public:
DwVfpRegister()187   constexpr operator DwVfpRegister() const { return DwVfpRegister(code()); }
188 
low()189   SwVfpRegister low() const { return SwVfpRegister::from_code(code() * 2); }
high()190   SwVfpRegister high() const {
191     return SwVfpRegister::from_code(code() * 2 + 1);
192   }
ToVfpRegList()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;
LowDwVfpRegister(int code)201   explicit constexpr LowDwVfpRegister(int code) : RegisterBase(code) {}
202 };
203 
204 enum 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.
212 class QwNeonRegister : public RegisterBase<QwNeonRegister, kSimd128AfterLast> {
213  public:
split_code(int reg_code,int * vm,int * m)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   }
split_code(int * vm,int * m)220   void split_code(int* vm, int* m) const { split_code(code(), vm, m); }
low()221   DwVfpRegister low() const { return DwVfpRegister::from_code(code() * 2); }
high()222   DwVfpRegister high() const {
223     return DwVfpRegister::from_code(code() * 2 + 1);
224   }
ToVfpRegList()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;
QwNeonRegister(int code)233   explicit constexpr QwNeonRegister(int code) : RegisterBase(code) {}
234 };
235 
236 using QuadRegister = QwNeonRegister;
237 
238 using Simd128Register = QwNeonRegister;
239 
240 enum CRegisterCode {
241 #define REGISTER_CODE(R) kCCode_##R,
242   C_REGISTERS(REGISTER_CODE)
243 #undef REGISTER_CODE
244       kCAfterLast
245 };
246 
247 // Coprocessor register
248 class CRegister : public RegisterBase<CRegister, kCAfterLast> {
249   friend class RegisterBase;
CRegister(int code)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);
257 FLOAT_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);
262 LOW_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);
267 NON_LOW_DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
268 #undef DECLARE_DOUBLE_REGISTER
269 
270 constexpr DwVfpRegister no_dreg = DwVfpRegister::no_reg();
271 
272 #define DECLARE_SIMD128_REGISTER(R) \
273   constexpr Simd128Register R = Simd128Register::from_code(kSimd128Code_##R);
274 SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
275 #undef DECLARE_SIMD128_REGISTER
276 
277 // Aliases for double registers.
278 constexpr LowDwVfpRegister kFirstCalleeSavedDoubleReg = d8;
279 constexpr LowDwVfpRegister kLastCalleeSavedDoubleReg = d15;
280 constexpr LowDwVfpRegister kDoubleRegZero = d13;
281 
282 constexpr CRegister no_creg = CRegister::no_reg();
283 
284 #define DECLARE_C_REGISTER(R) \
285   constexpr CRegister R = CRegister::from_code(kCCode_##R);
286 C_REGISTERS(DECLARE_C_REGISTER)
287 #undef DECLARE_C_REGISTER
288 
289 // Define {RegisterName} methods for the register types.
290 DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS)
291 DEFINE_REGISTER_NAMES(SwVfpRegister, FLOAT_REGISTERS)
292 DEFINE_REGISTER_NAMES(DwVfpRegister, DOUBLE_REGISTERS)
293 DEFINE_REGISTER_NAMES(LowDwVfpRegister, LOW_DOUBLE_REGISTERS)
294 DEFINE_REGISTER_NAMES(QwNeonRegister, SIMD128_REGISTERS)
295 DEFINE_REGISTER_NAMES(CRegister, C_REGISTERS)
296 
297 // Give alias names to registers for calling conventions.
298 constexpr Register kReturnRegister0 = r0;
299 constexpr Register kReturnRegister1 = r1;
300 constexpr Register kReturnRegister2 = r2;
301 constexpr Register kJSFunctionRegister = r1;
302 constexpr Register kContextRegister = r7;
303 constexpr Register kAllocateSizeRegister = r1;
304 constexpr Register kInterpreterAccumulatorRegister = r0;
305 constexpr Register kInterpreterBytecodeOffsetRegister = r5;
306 constexpr Register kInterpreterBytecodeArrayRegister = r6;
307 constexpr Register kInterpreterDispatchTableRegister = r8;
308 
309 constexpr Register kJavaScriptCallArgCountRegister = r0;
310 constexpr Register kJavaScriptCallCodeStartRegister = r2;
311 constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister;
312 constexpr Register kJavaScriptCallNewTargetRegister = r3;
313 constexpr Register kJavaScriptCallExtraArg1Register = r2;
314 
315 constexpr Register kOffHeapTrampolineRegister = ip;
316 constexpr Register kRuntimeCallFunctionRegister = r1;
317 constexpr Register kRuntimeCallArgCountRegister = r0;
318 constexpr Register kRuntimeCallArgvRegister = r2;
319 constexpr Register kWasmInstanceRegister = r3;
320 constexpr Register kWasmCompileLazyFuncIndexRegister = r4;
321 
322 // Give alias names to registers
323 constexpr Register cp = r7;              // JavaScript context pointer.
324 constexpr Register r11 = fp;
325 constexpr Register kRootRegister = r10;  // Roots array pointer.
326 
327 constexpr DoubleRegister kFPReturnRegister0 = d0;
328 
329 }  // namespace internal
330 }  // namespace v8
331 
332 #endif  // V8_CODEGEN_ARM_REGISTER_ARM_H_
333