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-base.h" 10 11namespace v8 { 12namespace internal { 13 14// clang-format off 15#define GENERAL_REGISTERS(V) \ 16 V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \ 17 V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(t7) \ 18 V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \ 19 V(k0) V(k1) V(gp) V(sp) V(fp) V(ra) 20 21#define ALLOCATABLE_GENERAL_REGISTERS(V) \ 22 V(a0) V(a1) V(a2) V(a3) \ 23 V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(s7) \ 24 V(v0) V(v1) 25 26#define DOUBLE_REGISTERS(V) \ 27 V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \ 28 V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \ 29 V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \ 30 V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31) 31 32// Currently, MIPS just use even float point register, except 33// for C function param registers. 34#define DOUBLE_USE_REGISTERS(V) \ 35 V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f13) \ 36 V(f14) V(f15) V(f16) V(f18) V(f20) V(f22) V(f24) V(f26) \ 37 V(f28) V(f30) 38 39#define FLOAT_REGISTERS DOUBLE_REGISTERS 40#define SIMD128_REGISTERS(V) \ 41 V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \ 42 V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \ 43 V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \ 44 V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31) 45 46#define ALLOCATABLE_DOUBLE_REGISTERS(V) \ 47 V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \ 48 V(f16) V(f18) V(f20) V(f22) V(f24) 49// clang-format on 50 51// Register lists. 52// Note that the bit values must match those used in actual instruction 53// encoding. 54const int kNumRegs = 32; 55 56// CPU Registers. 57// 58// 1) We would prefer to use an enum, but enum values are assignment- 59// compatible with int, which has caused code-generation bugs. 60// 61// 2) We would prefer to use a class instead of a struct but we don't like 62// the register initialization to depend on the particular initialization 63// order (which appears to be different on OS X, Linux, and Windows for the 64// installed versions of C++ we tried). Using a struct permits C-style 65// "initialization". Also, the Register objects cannot be const as this 66// forces initialization stubs in MSVC, making us dependent on initialization 67// order. 68// 69// 3) By not using an enum, we are possibly preventing the compiler from 70// doing certain constant folds, which may significantly reduce the 71// code generated for some assembly instructions (because they boil down 72// to a few constants). If this is a problem, we could change the code 73// such that we use an enum in optimized mode, and the struct in debug 74// mode. This way we get the compile-time error checking in debug mode 75// and best performance in optimized code. 76 77// ----------------------------------------------------------------------------- 78// Implementation of Register and FPURegister. 79 80enum RegisterCode { 81#define REGISTER_CODE(R) kRegCode_##R, 82 GENERAL_REGISTERS(REGISTER_CODE) 83#undef REGISTER_CODE 84 kRegAfterLast 85}; 86 87class Register : public RegisterBase<Register, kRegAfterLast> { 88 public: 89#if defined(V8_TARGET_LITTLE_ENDIAN) 90 static constexpr int kMantissaOffset = 0; 91 static constexpr int kExponentOffset = 4; 92#elif defined(V8_TARGET_BIG_ENDIAN) 93 static constexpr int kMantissaOffset = 4; 94 static constexpr int kExponentOffset = 0; 95#else 96#error Unknown endianness 97#endif 98 99 private: 100 friend class RegisterBase; 101 explicit constexpr Register(int code) : RegisterBase(code) {} 102}; 103 104// s7: context register 105// s3: scratch register 106// s4: scratch register 2 107#define DECLARE_REGISTER(R) \ 108 constexpr Register R = Register::from_code(kRegCode_##R); 109GENERAL_REGISTERS(DECLARE_REGISTER) 110#undef DECLARE_REGISTER 111constexpr Register no_reg = Register::no_reg(); 112 113int ToNumber(Register reg); 114 115Register ToRegister(int num); 116 117// Returns the number of padding slots needed for stack pointer alignment. 118constexpr int ArgumentPaddingSlots(int argument_count) { 119 // No argument padding required. 120 return 0; 121} 122 123constexpr AliasingKind kFPAliasing = AliasingKind::kOverlap; 124constexpr bool kSimdMaskRegisters = false; 125 126enum DoubleRegisterCode { 127#define REGISTER_CODE(R) kDoubleCode_##R, 128 DOUBLE_REGISTERS(REGISTER_CODE) 129#undef REGISTER_CODE 130 kDoubleAfterLast 131}; 132 133// Coprocessor register. 134class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> { 135 public: 136 FPURegister low() const { 137 // Find low reg of a Double-reg pair, which is the reg itself. 138 DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even. 139 return FPURegister::from_code(code()); 140 } 141 FPURegister high() const { 142 // Find high reg of a Doubel-reg pair, which is reg + 1. 143 DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even. 144 return FPURegister::from_code(code() + 1); 145 } 146 147 private: 148 friend class RegisterBase; 149 explicit constexpr FPURegister(int code) : RegisterBase(code) {} 150}; 151 152enum MSARegisterCode { 153#define REGISTER_CODE(R) kMsaCode_##R, 154 SIMD128_REGISTERS(REGISTER_CODE) 155#undef REGISTER_CODE 156 kMsaAfterLast 157}; 158 159// MIPS SIMD (MSA) register 160class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> { 161 friend class RegisterBase; 162 explicit constexpr MSARegister(int code) : RegisterBase(code) {} 163}; 164 165// A few double registers are reserved: one as a scratch register and one to 166// hold 0.0. 167// f28: 0.0 168// f30: scratch register. 169 170// V8 now supports the O32 ABI, and the FPU Registers are organized as 32 171// 32-bit registers, f0 through f31. When used as 'double' they are used 172// in pairs, starting with the even numbered register. So a double operation 173// on f0 really uses f0 and f1. 174// (Modern mips hardware also supports 32 64-bit registers, via setting 175// (priviledged) Status Register FR bit to 1. This is used by the N32 ABI, 176// but it is not in common use. Someday we will want to support this in v8.) 177 178// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers. 179using FloatRegister = FPURegister; 180 181using DoubleRegister = FPURegister; 182 183#define DECLARE_DOUBLE_REGISTER(R) \ 184 constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R); 185DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER) 186#undef DECLARE_DOUBLE_REGISTER 187 188constexpr DoubleRegister no_dreg = DoubleRegister::no_reg(); 189 190// SIMD registers. 191using Simd128Register = MSARegister; 192 193#define DECLARE_SIMD128_REGISTER(R) \ 194 constexpr Simd128Register R = Simd128Register::from_code(kMsaCode_##R); 195SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER) 196#undef DECLARE_SIMD128_REGISTER 197 198const Simd128Register no_msareg = Simd128Register::no_reg(); 199 200// Register aliases. 201// cp is assumed to be a callee saved register. 202constexpr Register kRootRegister = s6; 203constexpr Register cp = s7; 204constexpr Register kScratchReg = s3; 205constexpr Register kScratchReg2 = s4; 206constexpr DoubleRegister kScratchDoubleReg = f30; 207constexpr DoubleRegister kDoubleRegZero = f28; 208// Used on mips32r6 for compare operations. 209constexpr DoubleRegister kDoubleCompareReg = f26; 210// MSA zero and scratch regs must have the same numbers as FPU zero and scratch 211constexpr Simd128Register kSimd128RegZero = w28; 212constexpr Simd128Register kSimd128ScratchReg = w30; 213 214// FPU (coprocessor 1) control registers. 215// Currently only FCSR (#31) is implemented. 216struct FPUControlRegister { 217 bool is_valid() const { return reg_code == kFCSRRegister; } 218 bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; } 219 int code() const { 220 DCHECK(is_valid()); 221 return reg_code; 222 } 223 int bit() const { 224 DCHECK(is_valid()); 225 return 1 << reg_code; 226 } 227 void setcode(int f) { 228 reg_code = f; 229 DCHECK(is_valid()); 230 } 231 // Unfortunately we can't make this private in a struct. 232 int reg_code; 233}; 234 235constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister}; 236constexpr FPUControlRegister FCSR = {kFCSRRegister}; 237 238// MSA control registers 239struct MSAControlRegister { 240 bool is_valid() const { 241 return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister); 242 } 243 bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; } 244 int code() const { 245 DCHECK(is_valid()); 246 return reg_code; 247 } 248 int bit() const { 249 DCHECK(is_valid()); 250 return 1 << reg_code; 251 } 252 void setcode(int f) { 253 reg_code = f; 254 DCHECK(is_valid()); 255 } 256 // Unfortunately we can't make this private in a struct. 257 int reg_code; 258}; 259 260constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister}; 261constexpr MSAControlRegister MSAIR = {kMSAIRRegister}; 262constexpr MSAControlRegister MSACSR = {kMSACSRRegister}; 263 264// Define {RegisterName} methods for the register types. 265DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS) 266DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS) 267DEFINE_REGISTER_NAMES(MSARegister, SIMD128_REGISTERS) 268 269// Give alias names to registers for calling conventions. 270constexpr Register kReturnRegister0 = v0; 271constexpr Register kReturnRegister1 = v1; 272constexpr Register kReturnRegister2 = a0; 273constexpr Register kJSFunctionRegister = a1; 274constexpr Register kContextRegister = s7; 275constexpr Register kAllocateSizeRegister = a0; 276constexpr Register kInterpreterAccumulatorRegister = v0; 277constexpr Register kInterpreterBytecodeOffsetRegister = t4; 278constexpr Register kInterpreterBytecodeArrayRegister = t5; 279constexpr Register kInterpreterDispatchTableRegister = t6; 280 281constexpr Register kJavaScriptCallArgCountRegister = a0; 282constexpr Register kJavaScriptCallCodeStartRegister = a2; 283constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister; 284constexpr Register kJavaScriptCallNewTargetRegister = a3; 285constexpr Register kJavaScriptCallExtraArg1Register = a2; 286 287constexpr Register kOffHeapTrampolineRegister = at; 288constexpr Register kRuntimeCallFunctionRegister = a1; 289constexpr Register kRuntimeCallArgCountRegister = a0; 290constexpr Register kRuntimeCallArgvRegister = a2; 291constexpr Register kWasmInstanceRegister = a0; 292constexpr Register kWasmCompileLazyFuncIndexRegister = t0; 293 294constexpr DoubleRegister kFPReturnRegister0 = f0; 295 296} // namespace internal 297} // namespace v8 298 299#endif // V8_CODEGEN_MIPS_REGISTER_MIPS_H_ 300