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