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_WASM_WASM_LINKAGE_H_ 6 #define V8_WASM_WASM_LINKAGE_H_ 7 8 #include "src/assembler-arch.h" 9 #include "src/machine-type.h" 10 #include "src/signature.h" 11 #include "src/wasm/value-type.h" 12 13 namespace v8 { 14 namespace internal { 15 namespace wasm { 16 17 #if V8_TARGET_ARCH_IA32 18 // =========================================================================== 19 // == ia32 =================================================================== 20 // =========================================================================== 21 constexpr Register kGpParamRegisters[] = {esi, eax, edx, ecx, ebx}; 22 constexpr Register kGpReturnRegisters[] = {eax, edx}; 23 constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3, 24 xmm4, xmm5, xmm6}; 25 constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2}; 26 27 #elif V8_TARGET_ARCH_X64 28 // =========================================================================== 29 // == x64 ==================================================================== 30 // =========================================================================== 31 constexpr Register kGpParamRegisters[] = {rsi, rax, rdx, rcx, rbx, rdi}; 32 constexpr Register kGpReturnRegisters[] = {rax, rdx}; 33 constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3, 34 xmm4, xmm5, xmm6}; 35 constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2}; 36 37 #elif V8_TARGET_ARCH_ARM 38 // =========================================================================== 39 // == arm ==================================================================== 40 // =========================================================================== 41 constexpr Register kGpParamRegisters[] = {r3, r0, r1, r2}; 42 constexpr Register kGpReturnRegisters[] = {r0, r1}; 43 constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7}; 44 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1}; 45 46 #elif V8_TARGET_ARCH_ARM64 47 // =========================================================================== 48 // == arm64 ==================================================================== 49 // =========================================================================== 50 constexpr Register kGpParamRegisters[] = {x7, x0, x1, x2, x3, x4, x5, x6}; 51 constexpr Register kGpReturnRegisters[] = {x0, x1}; 52 constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7}; 53 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1}; 54 55 #elif V8_TARGET_ARCH_MIPS 56 // =========================================================================== 57 // == mips =================================================================== 58 // =========================================================================== 59 constexpr Register kGpParamRegisters[] = {a0, a1, a2, a3}; 60 constexpr Register kGpReturnRegisters[] = {v0, v1}; 61 constexpr DoubleRegister kFpParamRegisters[] = {f2, f4, f6, f8, f10, f12, f14}; 62 constexpr DoubleRegister kFpReturnRegisters[] = {f2, f4}; 63 64 #elif V8_TARGET_ARCH_MIPS64 65 // =========================================================================== 66 // == mips64 ================================================================= 67 // =========================================================================== 68 constexpr Register kGpParamRegisters[] = {a0, a1, a2, a3, a4, a5, a6, a7}; 69 constexpr Register kGpReturnRegisters[] = {v0, v1}; 70 constexpr DoubleRegister kFpParamRegisters[] = {f2, f4, f6, f8, f10, f12, f14}; 71 constexpr DoubleRegister kFpReturnRegisters[] = {f2, f4}; 72 73 #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 74 // =========================================================================== 75 // == ppc & ppc64 ============================================================ 76 // =========================================================================== 77 constexpr Register kGpParamRegisters[] = {r10, r3, r4, r5, r6, r7, r8, r9}; 78 constexpr Register kGpReturnRegisters[] = {r3, r4}; 79 constexpr DoubleRegister kFpParamRegisters[] = {d1, d2, d3, d4, d5, d6, d7, d8}; 80 constexpr DoubleRegister kFpReturnRegisters[] = {d1, d2}; 81 82 #elif V8_TARGET_ARCH_S390X 83 // =========================================================================== 84 // == s390x ================================================================== 85 // =========================================================================== 86 constexpr Register kGpParamRegisters[] = {r6, r2, r3, r4, r5}; 87 constexpr Register kGpReturnRegisters[] = {r2, r3}; 88 constexpr DoubleRegister kFpParamRegisters[] = {d0, d2, d4, d6}; 89 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2, d4, d6}; 90 91 #elif V8_TARGET_ARCH_S390 92 // =========================================================================== 93 // == s390 =================================================================== 94 // =========================================================================== 95 constexpr Register kGpParamRegisters[] = {r6, r2, r3, r4, r5}; 96 constexpr Register kGpReturnRegisters[] = {r2, r3}; 97 constexpr DoubleRegister kFpParamRegisters[] = {d0, d2}; 98 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2}; 99 100 #else 101 // =========================================================================== 102 // == unknown ================================================================ 103 // =========================================================================== 104 // Do not use any registers, we will just always use the stack. 105 constexpr Register kGpParamRegisters[] = {}; 106 constexpr Register kGpReturnRegisters[] = {}; 107 constexpr DoubleRegister kFpParamRegisters[] = {}; 108 constexpr DoubleRegister kFpReturnRegisters[] = {}; 109 110 #endif 111 112 // The parameter index where the instance parameter should be placed in wasm 113 // call descriptors. This is used by the Int64Lowering::LowerNode method. 114 constexpr int kWasmInstanceParameterIndex = 0; 115 116 class LinkageAllocator { 117 public: 118 template <size_t kNumGpRegs, size_t kNumFpRegs> LinkageAllocator(const Register (& gp)[kNumGpRegs],const DoubleRegister (& fp)[kNumFpRegs])119 constexpr LinkageAllocator(const Register (&gp)[kNumGpRegs], 120 const DoubleRegister (&fp)[kNumFpRegs]) 121 : LinkageAllocator(gp, kNumGpRegs, fp, kNumFpRegs) {} 122 LinkageAllocator(const Register * gp,int gpc,const DoubleRegister * fp,int fpc)123 constexpr LinkageAllocator(const Register* gp, int gpc, 124 const DoubleRegister* fp, int fpc) 125 : gp_count_(gpc), gp_regs_(gp), fp_count_(fpc), fp_regs_(fp) {} 126 CanAllocateGP()127 bool CanAllocateGP() const { return gp_offset_ < gp_count_; } CanAllocateFP(MachineRepresentation rep)128 bool CanAllocateFP(MachineRepresentation rep) const { 129 #if V8_TARGET_ARCH_ARM 130 switch (rep) { 131 case MachineRepresentation::kFloat32: 132 return extra_float_reg >= 0 || fp_offset_ < fp_count_; 133 case MachineRepresentation::kFloat64: 134 return extra_double_reg >= 0 || fp_offset_ < fp_count_; 135 case MachineRepresentation::kSimd128: 136 return ((fp_offset_ + 1) & ~1) + 1 < fp_count_; 137 default: 138 UNREACHABLE(); 139 return false; 140 } 141 #endif 142 return fp_offset_ < fp_count_; 143 } 144 NextGpReg()145 int NextGpReg() { 146 DCHECK_LT(gp_offset_, gp_count_); 147 return gp_regs_[gp_offset_++].code(); 148 } 149 NextFpReg(MachineRepresentation rep)150 int NextFpReg(MachineRepresentation rep) { 151 #if V8_TARGET_ARCH_ARM 152 switch (rep) { 153 case MachineRepresentation::kFloat32: { 154 // Use the extra S-register if we can. 155 if (extra_float_reg >= 0) { 156 int reg_code = extra_float_reg; 157 extra_float_reg = -1; 158 return reg_code; 159 } 160 // Allocate a D-register and split into 2 float registers. 161 int d_reg_code = NextFpReg(MachineRepresentation::kFloat64); 162 DCHECK_GT(16, d_reg_code); // D-registers 16 - 31 can't split. 163 int reg_code = d_reg_code * 2; 164 // Save the extra S-register. 165 DCHECK_EQ(-1, extra_float_reg); 166 extra_float_reg = reg_code + 1; 167 return reg_code; 168 } 169 case MachineRepresentation::kFloat64: { 170 // Use an extra D-register if we can. 171 if (extra_double_reg >= 0) { 172 int reg_code = extra_double_reg; 173 extra_double_reg = -1; 174 return reg_code; 175 } 176 DCHECK_LT(fp_offset_, fp_count_); 177 return fp_regs_[fp_offset_++].code(); 178 } 179 case MachineRepresentation::kSimd128: { 180 // Q-register must be an even-odd pair, so we must try to allocate at 181 // the end, not using extra_double_reg. If we are at an odd D-register, 182 // skip past it (saving it to extra_double_reg). 183 DCHECK_LT(((fp_offset_ + 1) & ~1) + 1, fp_count_); 184 int d_reg1_code = fp_regs_[fp_offset_++].code(); 185 if (d_reg1_code % 2 != 0) { 186 // If we're misaligned then extra_double_reg must have been consumed. 187 DCHECK_EQ(-1, extra_double_reg); 188 int odd_double_reg = d_reg1_code; 189 d_reg1_code = fp_regs_[fp_offset_++].code(); 190 extra_double_reg = odd_double_reg; 191 } 192 // Combine the current D-register with the next to form a Q-register. 193 int d_reg2_code = fp_regs_[fp_offset_++].code(); 194 DCHECK_EQ(0, d_reg1_code % 2); 195 DCHECK_EQ(d_reg1_code + 1, d_reg2_code); 196 USE(d_reg2_code); 197 return d_reg1_code / 2; 198 } 199 default: 200 UNREACHABLE(); 201 } 202 #else 203 DCHECK_LT(fp_offset_, fp_count_); 204 return fp_regs_[fp_offset_++].code(); 205 #endif 206 } 207 208 // Stackslots are counted upwards starting from 0 (or the offset set by 209 // {SetStackOffset}. NumStackSlots(MachineRepresentation type)210 int NumStackSlots(MachineRepresentation type) { 211 return std::max(1, ElementSizeInBytes(type) / kPointerSize); 212 } 213 214 // Stackslots are counted upwards starting from 0 (or the offset set by 215 // {SetStackOffset}. If {type} needs more than 216 // one stack slot, the lowest used stack slot is returned. NextStackSlot(MachineRepresentation type)217 int NextStackSlot(MachineRepresentation type) { 218 int num_stack_slots = NumStackSlots(type); 219 int offset = stack_offset_; 220 stack_offset_ += num_stack_slots; 221 return offset; 222 } 223 224 // Set an offset for the stack slots returned by {NextStackSlot} and 225 // {NumStackSlots}. Can only be called before any call to {NextStackSlot}. SetStackOffset(int num)226 void SetStackOffset(int num) { 227 DCHECK_LE(0, num); 228 DCHECK_EQ(0, stack_offset_); 229 stack_offset_ = num; 230 } 231 NumStackSlots()232 int NumStackSlots() const { return stack_offset_; } 233 234 private: 235 const int gp_count_; 236 int gp_offset_ = 0; 237 const Register* const gp_regs_; 238 239 const int fp_count_; 240 int fp_offset_ = 0; 241 const DoubleRegister* const fp_regs_; 242 243 #if V8_TARGET_ARCH_ARM 244 // ARM FP register aliasing may require splitting or merging double registers. 245 // Track fragments of registers below fp_offset_ here. There can only be one 246 // extra float and double register. 247 int extra_float_reg = -1; 248 int extra_double_reg = -1; 249 #endif 250 251 int stack_offset_ = 0; 252 }; 253 254 } // namespace wasm 255 } // namespace internal 256 } // namespace v8 257 258 #endif // V8_WASM_WASM_LINKAGE_H_ 259