1// Copyright 2021 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_RISCV64_REGISTER_RISCV64_H_ 6#define V8_CODEGEN_RISCV64_REGISTER_RISCV64_H_ 7 8#include "src/codegen/register-base.h" 9#include "src/codegen/riscv64/constants-riscv64.h" 10 11namespace v8 { 12namespace internal { 13 14// clang-format off 15 16#define GENERAL_REGISTERS(V) \ 17 V(zero_reg) V(ra) V(sp) V(gp) V(tp) V(t0) V(t1) V(t2) \ 18 V(fp) V(s1) V(a0) V(a1) V(a2) V(a3) V(a4) V(a5) \ 19 V(a6) V(a7) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(s8) V(s9) \ 20 V(s10) V(s11) V(t3) V(t4) V(t5) V(t6) 21 22// s3: scratch register s4: scratch register 2 used in code-generator-riscv64 23// s6: roots in Javascript code s7: context register 24// s11: PtrComprCageBaseRegister 25// t3 t5 : scratch register used in scratch_register_list 26// t6 : call reg. 27// t0 t1 t2 t4:caller saved scratch register can be used in macroassembler and 28// builtin-riscv64 29#define ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \ 30 V(a0) V(a1) V(a2) V(a3) \ 31 V(a4) V(a5) V(a6) V(a7) V(t0) \ 32 V(t1) V(t2) V(t4) V(s7) V(s8) V(s9) V(s10) 33 34#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE 35#define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V) 36#else 37#define MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V) V(s11) 38#endif 39 40#define ALLOCATABLE_GENERAL_REGISTERS(V) \ 41 ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \ 42 MAYBE_ALLOCATABLE_GENERAL_REGISTERS(V) 43 44#define DOUBLE_REGISTERS(V) \ 45 V(ft0) V(ft1) V(ft2) V(ft3) V(ft4) V(ft5) V(ft6) V(ft7) \ 46 V(fs0) V(fs1) V(fa0) V(fa1) V(fa2) V(fa3) V(fa4) V(fa5) \ 47 V(fa6) V(fa7) V(fs2) V(fs3) V(fs4) V(fs5) V(fs6) V(fs7) \ 48 V(fs8) V(fs9) V(fs10) V(fs11) V(ft8) V(ft9) V(ft10) V(ft11) 49 50#define FLOAT_REGISTERS DOUBLE_REGISTERS 51#define VECTOR_REGISTERS(V) \ 52 V(v0) V(v1) V(v2) V(v3) V(v4) V(v5) V(v6) V(v7) \ 53 V(v8) V(v9) V(v10) V(v11) V(v12) V(v13) V(v14) V(v15) \ 54 V(v16) V(v17) V(v18) V(v19) V(v20) V(v21) V(v22) V(v23) \ 55 V(v24) V(v25) V(v26) V(v27) V(v28) V(v29) V(v30) V(v31) 56 57#define ALLOCATABLE_SIMD128_REGISTERS(V) \ 58 V(v1) V(v2) V(v3) V(v4) V(v5) V(v6) V(v7) \ 59 V(v10) V(v11) V(v12) V(v13) V(v14) V(v15) V(v16) \ 60 V(v17) V(v18) V(v19) V(v20) V(v21) V(v22) V(v26) \ 61 V(v27) V(v28) V(v29) V(v30) V(v31) 62 63#define ALLOCATABLE_DOUBLE_REGISTERS(V) \ 64 V(ft1) V(ft2) V(ft3) V(ft4) V(ft5) V(ft6) V(ft7) V(ft8) \ 65 V(ft9) V(ft10) V(ft11) V(fa0) V(fa1) V(fa2) V(fa3) V(fa4) V(fa5) \ 66 V(fa6) V(fa7) 67 68// Returns the number of padding slots needed for stack pointer alignment. 69constexpr int ArgumentPaddingSlots(int argument_count) { 70 // No argument padding required. 71 return 0; 72} 73 74// clang-format on 75 76// Note that the bit values must match those used in actual instruction 77// encoding. 78const int kNumRegs = 32; 79 80const int kUndefIndex = -1; 81// Map with indexes on stack that corresponds to codes of saved registers. 82const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg 83 kUndefIndex, // ra 84 kUndefIndex, // sp 85 kUndefIndex, // gp 86 kUndefIndex, // tp 87 0, // t0 88 1, // t1 89 2, // t2 90 3, // s0/fp 91 4, // s1 92 5, // a0 93 6, // a1 94 7, // a2 95 8, // a3 96 9, // a4 97 10, // a5 98 11, // a6 99 12, // a7 100 13, // s2 101 14, // s3 102 15, // s4 103 16, // s5 104 17, // s6 105 18, // s7 106 19, // s8 107 10, // s9 108 21, // s10 109 22, // s11 110 kUndefIndex, // t3 111 23, // t4 112 kUndefIndex, // t5 113 kUndefIndex}; // t6 114// CPU Registers. 115// 116// 1) We would prefer to use an enum, but enum values are assignment- 117// compatible with int, which has caused code-generation bugs. 118// 119// 2) We would prefer to use a class instead of a struct but we don't like 120// the register initialization to depend on the particular initialization 121// order (which appears to be different on OS X, Linux, and Windows for the 122// installed versions of C++ we tried). Using a struct permits C-style 123// "initialization". Also, the Register objects cannot be const as this 124// forces initialization stubs in MSVC, making us dependent on initialization 125// order. 126// 127// 3) By not using an enum, we are possibly preventing the compiler from 128// doing certain constant folds, which may significantly reduce the 129// code generated for some assembly instructions (because they boil down 130// to a few constants). If this is a problem, we could change the code 131// such that we use an enum in optimized mode, and the struct in debug 132// mode. This way we get the compile-time error checking in debug mode 133// and best performance in optimized code. 134 135// ----------------------------------------------------------------------------- 136// Implementation of Register and FPURegister. 137 138enum RegisterCode { 139#define REGISTER_CODE(R) kRegCode_##R, 140 GENERAL_REGISTERS(REGISTER_CODE) 141#undef REGISTER_CODE 142 kRegAfterLast 143}; 144 145class Register : public RegisterBase<Register, kRegAfterLast> { 146 public: 147#if defined(V8_TARGET_LITTLE_ENDIAN) 148 static constexpr int kMantissaOffset = 0; 149 static constexpr int kExponentOffset = 4; 150#elif defined(V8_TARGET_BIG_ENDIAN) 151 static constexpr int kMantissaOffset = 4; 152 static constexpr int kExponentOffset = 0; 153#else 154#error Unknown endianness 155#endif 156 157 private: 158 friend class RegisterBase; 159 explicit constexpr Register(int code) : RegisterBase(code) {} 160}; 161 162// s7: context register 163// s3: scratch register 164// s4: scratch register 2 165#define DECLARE_REGISTER(R) \ 166 constexpr Register R = Register::from_code(kRegCode_##R); 167GENERAL_REGISTERS(DECLARE_REGISTER) 168#undef DECLARE_REGISTER 169 170constexpr Register no_reg = Register::no_reg(); 171 172int ToNumber(Register reg); 173 174Register ToRegister(int num); 175 176constexpr bool kPadArguments = false; 177constexpr AliasingKind kFPAliasing = AliasingKind::kIndependent; 178constexpr bool kSimdMaskRegisters = false; 179 180enum DoubleRegisterCode { 181#define REGISTER_CODE(R) kDoubleCode_##R, 182 DOUBLE_REGISTERS(REGISTER_CODE) 183#undef REGISTER_CODE 184 kDoubleAfterLast 185}; 186 187enum VRegisterCode { 188#define REGISTER_CODE(R) kVRCode_##R, 189 VECTOR_REGISTERS(REGISTER_CODE) 190#undef REGISTER_CODE 191 kVRAfterLast 192}; 193class VRegister : public RegisterBase<VRegister, kVRAfterLast> { 194 friend class RegisterBase; 195 196 public: 197 explicit constexpr VRegister(int code) : RegisterBase(code) {} 198}; 199 200// Coprocessor register. 201class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> { 202 public: 203 // TODO(plind): Warning, inconsistent numbering here. kNumFPURegisters refers 204 // to number of 32-bit FPU regs, but kNumAllocatableRegisters refers to 205 // number of Double regs (64-bit regs, or FPU-reg-pairs). 206 207 FPURegister low() const { 208 // TODO(plind): Create DCHECK for FR=0 mode. This usage suspect for FR=1. 209 // Find low reg of a Double-reg pair, which is the reg itself. 210 return FPURegister::from_code(code()); 211 } 212 FPURegister high() const { 213 // TODO(plind): Create DCHECK for FR=0 mode. This usage illegal in FR=1. 214 // Find high reg of a Doubel-reg pair, which is reg + 1. 215 return FPURegister::from_code(code() + 1); 216 } 217 218 // FIXME(riscv64): In Rvv, Vector regs is different from Float Regs. But in 219 // this cl, in order to facilitate modification, it is assumed that the vector 220 // register and floating point register are shared. 221 VRegister toV() const { 222 DCHECK(base::IsInRange(static_cast<int>(code()), 0, kVRAfterLast - 1)); 223 return VRegister(code()); 224 } 225 226 private: 227 friend class RegisterBase; 228 explicit constexpr FPURegister(int code) : RegisterBase(code) {} 229}; 230 231 232// A few double registers are reserved: one as a scratch register and one to 233// hold 0.0. 234// fs9: 0.0 235// fs11: scratch register. 236 237// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers. 238using FloatRegister = FPURegister; 239 240using DoubleRegister = FPURegister; 241 242using Simd128Register = VRegister; 243 244#define DECLARE_DOUBLE_REGISTER(R) \ 245 constexpr DoubleRegister R = DoubleRegister::from_code(kDoubleCode_##R); 246DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER) 247#undef DECLARE_DOUBLE_REGISTER 248 249constexpr DoubleRegister no_dreg = DoubleRegister::no_reg(); 250 251#define DECLARE_VECTOR_REGISTER(R) \ 252 constexpr VRegister R = VRegister::from_code(kVRCode_##R); 253VECTOR_REGISTERS(DECLARE_VECTOR_REGISTER) 254#undef DECLARE_VECTOR_REGISTER 255 256const VRegister no_msareg = VRegister::no_reg(); 257 258// Register aliases. 259// cp is assumed to be a callee saved register. 260constexpr Register kRootRegister = s6; 261constexpr Register cp = s7; 262constexpr Register kScratchReg = s3; 263constexpr Register kScratchReg2 = s4; 264 265constexpr DoubleRegister kScratchDoubleReg = ft0; 266 267constexpr DoubleRegister kDoubleRegZero = fs9; 268 269// Define {RegisterName} methods for the register types. 270DEFINE_REGISTER_NAMES(Register, GENERAL_REGISTERS) 271DEFINE_REGISTER_NAMES(FPURegister, DOUBLE_REGISTERS) 272DEFINE_REGISTER_NAMES(VRegister, VECTOR_REGISTERS) 273 274// Give alias names to registers for calling conventions. 275constexpr Register kReturnRegister0 = a0; 276constexpr Register kReturnRegister1 = a1; 277constexpr Register kReturnRegister2 = a2; 278constexpr Register kJSFunctionRegister = a1; 279constexpr Register kContextRegister = s7; 280constexpr Register kAllocateSizeRegister = a1; 281constexpr Register kInterpreterAccumulatorRegister = a0; 282constexpr Register kInterpreterBytecodeOffsetRegister = t0; 283constexpr Register kInterpreterBytecodeArrayRegister = t1; 284constexpr Register kInterpreterDispatchTableRegister = t2; 285 286constexpr Register kJavaScriptCallArgCountRegister = a0; 287constexpr Register kJavaScriptCallCodeStartRegister = a2; 288constexpr Register kJavaScriptCallTargetRegister = kJSFunctionRegister; 289constexpr Register kJavaScriptCallNewTargetRegister = a3; 290constexpr Register kJavaScriptCallExtraArg1Register = a2; 291 292constexpr Register kOffHeapTrampolineRegister = t6; 293constexpr Register kRuntimeCallFunctionRegister = a1; 294constexpr Register kRuntimeCallArgCountRegister = a0; 295constexpr Register kRuntimeCallArgvRegister = a2; 296constexpr Register kWasmInstanceRegister = a0; 297constexpr Register kWasmCompileLazyFuncIndexRegister = t0; 298 299constexpr DoubleRegister kFPReturnRegister0 = fa0; 300constexpr VRegister kSimd128ScratchReg = v24; 301constexpr VRegister kSimd128ScratchReg2 = v23; 302constexpr VRegister kSimd128ScratchReg3 = v8; 303constexpr VRegister kSimd128RegZero = v25; 304 305#ifdef V8_COMPRESS_POINTERS_IN_SHARED_CAGE 306constexpr Register kPtrComprCageBaseRegister = s11; // callee save 307#else 308constexpr Register kPtrComprCageBaseRegister = kRootRegister; 309#endif 310 311} // namespace internal 312} // namespace v8 313 314#endif // V8_CODEGEN_RISCV64_REGISTER_RISCV64_H_ 315