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