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