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_MIPS64_REGISTER_MIPS64_H_ 6 #define V8_CODEGEN_MIPS64_REGISTER_MIPS64_H_ 7 8 #include "src/codegen/mips64/constants-mips64.h" 9 #include "src/codegen/register.h" 10 #include "src/codegen/reglist.h" 11 12 namespace v8 { 13 namespace internal { 14 15 // clang-format off 16 #define GENERAL_REGISTERS(V) \ 17 V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \ 18 V(a4) V(a5) V(a6) V(a7) V(t0) V(t1) V(t2) V(t3) \ 19 V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \ 20 V(k0) V(k1) V(gp) V(sp) V(fp) V(ra) 21 22 #define ALLOCATABLE_GENERAL_REGISTERS(V) \ 23 V(a0) V(a1) V(a2) V(a3) \ 24 V(a4) V(a5) V(a6) V(a7) V(t0) V(t1) V(t2) V(s7) \ 25 V(v0) V(v1) 26 27 #define DOUBLE_REGISTERS(V) \ 28 V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \ 29 V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \ 30 V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \ 31 V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31) 32 33 #define FLOAT_REGISTERS DOUBLE_REGISTERS 34 #define SIMD128_REGISTERS(V) \ 35 V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \ 36 V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \ 37 V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \ 38 V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31) 39 40 #define ALLOCATABLE_DOUBLE_REGISTERS(V) \ 41 V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \ 42 V(f16) V(f18) V(f20) V(f22) V(f24) V(f26) 43 // clang-format on 44 45 // Note that the bit values must match those used in actual instruction 46 // encoding. 47 const int kNumRegs = 32; 48 49 const RegList kJSCallerSaved = 1 << 2 | // v0 50 1 << 3 | // v1 51 1 << 4 | // a0 52 1 << 5 | // a1 53 1 << 6 | // a2 54 1 << 7 | // a3 55 1 << 8 | // a4 56 1 << 9 | // a5 57 1 << 10 | // a6 58 1 << 11 | // a7 59 1 << 12 | // t0 60 1 << 13 | // t1 61 1 << 14 | // t2 62 1 << 15; // t3 63 64 const int kNumJSCallerSaved = 14; 65 66 // Callee-saved registers preserved when switching from C to JavaScript. 67 const RegList kCalleeSaved = 1 << 16 | // s0 68 1 << 17 | // s1 69 1 << 18 | // s2 70 1 << 19 | // s3 71 1 << 20 | // s4 72 1 << 21 | // s5 73 1 << 22 | // s6 (roots in Javascript code) 74 1 << 23 | // s7 (cp in Javascript code) 75 1 << 30; // fp/s8 76 77 const int kNumCalleeSaved = 9; 78 79 const RegList kCalleeSavedFPU = 1 << 20 | // f20 80 1 << 22 | // f22 81 1 << 24 | // f24 82 1 << 26 | // f26 83 1 << 28 | // f28 84 1 << 30; // f30 85 86 const int kNumCalleeSavedFPU = 6; 87 88 const RegList kCallerSavedFPU = 1 << 0 | // f0 89 1 << 2 | // f2 90 1 << 4 | // f4 91 1 << 6 | // f6 92 1 << 8 | // f8 93 1 << 10 | // f10 94 1 << 12 | // f12 95 1 << 14 | // f14 96 1 << 16 | // f16 97 1 << 18; // f18 98 99 // Number of registers for which space is reserved in safepoints. Must be a 100 // multiple of 8. 101 const int kNumSafepointRegisters = 24; 102 103 // Define the list of registers actually saved at safepoints. 104 // Note that the number of saved registers may be smaller than the reserved 105 // space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters. 106 const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved; 107 const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved; 108 109 const int kUndefIndex = -1; 110 // Map with indexes on stack that corresponds to codes of saved registers. 111 const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg 112 kUndefIndex, // at 113 0, // v0 114 1, // v1 115 2, // a0 116 3, // a1 117 4, // a2 118 5, // a3 119 6, // a4 120 7, // a5 121 8, // a6 122 9, // a7 123 10, // t0 124 11, // t1 125 12, // t2 126 13, // t3 127 14, // s0 128 15, // s1 129 16, // s2 130 17, // s3 131 18, // s4 132 19, // s5 133 20, // s6 134 21, // s7 135 kUndefIndex, // t8 136 kUndefIndex, // t9 137 kUndefIndex, // k0 138 kUndefIndex, // k1 139 kUndefIndex, // gp 140 kUndefIndex, // sp 141 22, // fp 142 kUndefIndex}; 143 144 // CPU Registers. 145 // 146 // 1) We would prefer to use an enum, but enum values are assignment- 147 // compatible with int, which has caused code-generation bugs. 148 // 149 // 2) We would prefer to use a class instead of a struct but we don't like 150 // the register initialization to depend on the particular initialization 151 // order (which appears to be different on OS X, Linux, and Windows for the 152 // installed versions of C++ we tried). Using a struct permits C-style 153 // "initialization". Also, the Register objects cannot be const as this 154 // forces initialization stubs in MSVC, making us dependent on initialization 155 // order. 156 // 157 // 3) By not using an enum, we are possibly preventing the compiler from 158 // doing certain constant folds, which may significantly reduce the 159 // code generated for some assembly instructions (because they boil down 160 // to a few constants). If this is a problem, we could change the code 161 // such that we use an enum in optimized mode, and the struct in debug 162 // mode. This way we get the compile-time error checking in debug mode 163 // and best performance in optimized code. 164 165 // ----------------------------------------------------------------------------- 166 // Implementation of Register and FPURegister. 167 168 enum RegisterCode { 169 #define REGISTER_CODE(R) kRegCode_##R, 170 GENERAL_REGISTERS(REGISTER_CODE) 171 #undef REGISTER_CODE 172 kRegAfterLast 173 }; 174 175 class Register : public RegisterBase<Register, kRegAfterLast> { 176 public: 177 #if defined(V8_TARGET_LITTLE_ENDIAN) 178 static constexpr int kMantissaOffset = 0; 179 static constexpr int kExponentOffset = 4; 180 #elif defined(V8_TARGET_BIG_ENDIAN) 181 static constexpr int kMantissaOffset = 4; 182 static constexpr int kExponentOffset = 0; 183 #else 184 #error Unknown endianness 185 #endif 186 187 private: 188 friend class RegisterBase; Register(int code)189 explicit constexpr Register(int code) : RegisterBase(code) {} 190 }; 191 192 // s7: context register 193 // s3: scratch register 194 // s4: scratch register 2 195 #define DECLARE_REGISTER(R) \ 196 constexpr Register R = Register::from_code(kRegCode_##R); 197 GENERAL_REGISTERS(DECLARE_REGISTER) 198 #undef DECLARE_REGISTER 199 200 constexpr Register no_reg = Register::no_reg(); 201 202 int ToNumber(Register reg); 203 204 Register ToRegister(int num); 205 206 constexpr bool kPadArguments = false; 207 constexpr bool kSimpleFPAliasing = true; 208 constexpr bool kSimdMaskRegisters = false; 209 210 enum MSARegisterCode { 211 #define REGISTER_CODE(R) kMsaCode_##R, 212 SIMD128_REGISTERS(REGISTER_CODE) 213 #undef REGISTER_CODE 214 kMsaAfterLast 215 }; 216 217 // MIPS SIMD (MSA) register 218 class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> { 219 friend class RegisterBase; MSARegister(int code)220 explicit constexpr MSARegister(int code) : RegisterBase(code) {} 221 }; 222 223 enum DoubleRegisterCode { 224 #define REGISTER_CODE(R) kDoubleCode_##R, 225 DOUBLE_REGISTERS(REGISTER_CODE) 226 #undef REGISTER_CODE 227 kDoubleAfterLast 228 }; 229 230 // Coprocessor register. 231 class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> { 232 public: 233 // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers 234 // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to 235 // number of Double regs (64-bit regs, or FPU-reg-pairs). 236 low()237 FPURegister low() const { 238 // TODO(plind): Create DCHECK for FR=0 mode. This usage suspect for FR=1. 239 // Find low reg of a Double-reg pair, which is the reg itself. 240 DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even. 241 return FPURegister::from_code(code()); 242 } high()243 FPURegister high() const { 244 // TODO(plind): Create DCHECK for FR=0 mode. This usage illegal in FR=1. 245 // Find high reg of a Doubel-reg pair, which is reg + 1. 246 DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even. 247 return FPURegister::from_code(code() + 1); 248 } 249 toW()250 MSARegister toW() const { return MSARegister::from_code(code()); } 251 252 private: 253 friend class RegisterBase; FPURegister(int code)254 explicit constexpr FPURegister(int code) : RegisterBase(code) {} 255 }; 256 257 // A few double registers are reserved: one as a scratch register and one to 258 // hold 0.0. 259 // f28: 0.0 260 // f30: scratch register. 261 262 // V8 now supports the O32 ABI, and the FPU Registers are organized as 32 263 // 32-bit registers, f0 through f31. When used as 'double' they are used 264 // in pairs, starting with the even numbered register. So a double operation 265 // on f0 really uses f0 and f1. 266 // (Modern mips hardware also supports 32 64-bit registers, via setting 267 // (privileged) Status Register FR bit to 1. This is used by the N32 ABI, 268 // but it is not in common use. Someday we will want to support this in v8.) 269 270 // For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers. 271 using FloatRegister = FPURegister; 272 273 using DoubleRegister = FPURegister; 274 275 #define DECLARE_DOUBLE_REGISTER(R) \ 276 constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R); 277 DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER) 278 #undef DECLARE_DOUBLE_REGISTER 279 280 constexpr DoubleRegister no_dreg = DoubleRegister::no_reg(); 281 282 // SIMD registers. 283 using Simd128Register = MSARegister; 284 285 #define DECLARE_SIMD128_REGISTER(R) \ 286 constexpr Simd128Register R = Simd128Register::from_code(kMsaCode_##R); 287 SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER) 288 #undef DECLARE_SIMD128_REGISTER 289 290 const Simd128Register no_msareg = Simd128Register::no_reg(); 291 292 // Register aliases. 293 // cp is assumed to be a callee saved register. 294 constexpr Register kRootRegister = s6; 295 constexpr Register cp = s7; 296 constexpr Register kScratchReg = s3; 297 constexpr Register kScratchReg2 = s4; 298 constexpr DoubleRegister kScratchDoubleReg = f30; 299 // FPU zero reg is often used to hold 0.0, but it's not hardwired to 0.0. 300 constexpr DoubleRegister kDoubleRegZero = f28; 301 // Used on mips64r6 for compare operations. 302 // We use the last non-callee saved odd register for N64 ABI 303 constexpr DoubleRegister kDoubleCompareReg = f23; 304 // MSA zero and scratch regs must have the same numbers as FPU zero and scratch 305 // MSA zero reg is often used to hold 0, but it's not hardwired to 0. 306 constexpr Simd128Register kSimd128RegZero = w28; 307 constexpr Simd128Register kSimd128ScratchReg = w30; 308 309 // FPU (coprocessor 1) control registers. 310 // Currently only FCSR (#31) is implemented. 311 struct FPUControlRegister { is_validFPUControlRegister312 bool is_valid() const { return reg_code == kFCSRRegister; } isFPUControlRegister313 bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; } codeFPUControlRegister314 int code() const { 315 DCHECK(is_valid()); 316 return reg_code; 317 } bitFPUControlRegister318 int bit() const { 319 DCHECK(is_valid()); 320 return 1 << reg_code; 321 } setcodeFPUControlRegister322 void setcode(int f) { 323 reg_code = f; 324 DCHECK(is_valid()); 325 } 326 // Unfortunately we can't make this private in a struct. 327 int reg_code; 328 }; 329 330 constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister}; 331 constexpr FPUControlRegister FCSR = {kFCSRRegister}; 332 333 // MSA control registers 334 struct MSAControlRegister { is_validMSAControlRegister335 bool is_valid() const { 336 return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister); 337 } isMSAControlRegister338 bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; } codeMSAControlRegister339 int code() const { 340 DCHECK(is_valid()); 341 return reg_code; 342 } bitMSAControlRegister343 int bit() const { 344 DCHECK(is_valid()); 345 return 1 << reg_code; 346 } setcodeMSAControlRegister347 void setcode(int f) { 348 reg_code = f; 349 DCHECK(is_valid()); 350 } 351 // Unfortunately we can't make this private in a struct. 352 int reg_code; 353 }; 354 355 constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister}; 356 constexpr MSAControlRegister MSAIR = {kMSAIRRegister}; 357 constexpr MSAControlRegister MSACSR = {kMSACSRRegister}; 358 359 // Define {RegisterName} methods for the register types. 360 DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS) 361 DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS) 362 DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS) 363 364 // Give alias names to registers for calling conventions. 365 constexpr Register kReturnRegister0 = v0; 366 constexpr Register kReturnRegister1 = v1; 367 constexpr Register kReturnRegister2 = a0; 368 constexpr Register kJSFunctionRegister = a1; 369 constexpr Register kContextRegister = s7; 370 constexpr Register kAllocateSizeRegister = a0; 371 constexpr Register kSpeculationPoisonRegister = a7; 372 constexpr Register kInterpreterAccumulatorRegister = v0; 373 constexpr Register kInterpreterBytecodeOffsetRegister = t0; 374 constexpr Register kInterpreterBytecodeArrayRegister = t1; 375 constexpr Register kInterpreterDispatchTableRegister = t2; 376 377 constexpr Register kJavaScriptCallArgCountRegister = a0; 378 constexpr Register kJavaScriptCallCodeStartRegister = a2; 379 constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister; 380 constexpr Register kJavaScriptCallNewTargetRegister = a3; 381 constexpr Register kJavaScriptCallExtraArg1Register = a2; 382 383 constexpr Register kOffHeapTrampolineRegister = at; 384 constexpr Register kRuntimeCallFunctionRegister = a1; 385 constexpr Register kRuntimeCallArgCountRegister = a0; 386 constexpr Register kRuntimeCallArgvRegister = a2; 387 constexpr Register kWasmInstanceRegister = a0; 388 constexpr Register kWasmCompileLazyFuncIndexRegister = t0; 389 390 constexpr DoubleRegister kFPReturnRegister0 = f0; 391 392 } // namespace internal 393 } // namespace v8 394 395 #endif // V8_CODEGEN_MIPS64_REGISTER_MIPS64_H_ 396