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 #if !V8_ENABLE_WEBASSEMBLY 6 #error This header should only be included if WebAssembly is enabled. 7 #endif // !V8_ENABLE_WEBASSEMBLY 8 9 #ifndef V8_WASM_WASM_LINKAGE_H_ 10 #define V8_WASM_WASM_LINKAGE_H_ 11 12 #include "src/codegen/aligned-slot-allocator.h" 13 #include "src/codegen/assembler-arch.h" 14 #include "src/codegen/machine-type.h" 15 #include "src/codegen/signature.h" 16 #include "src/wasm/value-type.h" 17 18 namespace v8 { 19 namespace internal { 20 namespace wasm { 21 22 // TODO(wasm): optimize calling conventions to be both closer to C++ (to 23 // reduce adapter costs for fast Wasm <-> C++ calls) and to be more efficient 24 // in general. 25 26 #if V8_TARGET_ARCH_IA32 27 // =========================================================================== 28 // == ia32 =================================================================== 29 // =========================================================================== 30 constexpr Register kGpParamRegisters[] = {esi, eax, edx, ecx}; 31 constexpr Register kGpReturnRegisters[] = {eax, edx}; 32 constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3, 33 xmm4, xmm5, xmm6}; 34 constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2}; 35 36 #elif V8_TARGET_ARCH_X64 37 // =========================================================================== 38 // == x64 ==================================================================== 39 // =========================================================================== 40 constexpr Register kGpParamRegisters[] = {rsi, rax, rdx, rcx, rbx, r9}; 41 constexpr Register kGpReturnRegisters[] = {rax, rdx}; 42 constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3, 43 xmm4, xmm5, xmm6}; 44 constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2}; 45 46 #elif V8_TARGET_ARCH_ARM 47 // =========================================================================== 48 // == arm ==================================================================== 49 // =========================================================================== 50 constexpr Register kGpParamRegisters[] = {r3, r0, r2, r6}; 51 constexpr Register kGpReturnRegisters[] = {r0, r1}; 52 // ARM d-registers must be in even/odd D-register pairs for correct allocation. 53 constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7}; 54 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1}; 55 56 #elif V8_TARGET_ARCH_ARM64 57 // =========================================================================== 58 // == arm64 ==================================================================== 59 // =========================================================================== 60 constexpr Register kGpParamRegisters[] = {x7, x0, x2, x3, x4, x5, x6}; 61 constexpr Register kGpReturnRegisters[] = {x0, x1}; 62 constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7}; 63 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1}; 64 65 #elif V8_TARGET_ARCH_MIPS 66 // =========================================================================== 67 // == mips =================================================================== 68 // =========================================================================== 69 constexpr Register kGpParamRegisters[] = {a0, a2, a3}; 70 constexpr Register kGpReturnRegisters[] = {v0, v1}; 71 constexpr DoubleRegister kFpParamRegisters[] = {f2, f4, f6, f8, f10, f12, f14}; 72 constexpr DoubleRegister kFpReturnRegisters[] = {f2, f4}; 73 74 #elif V8_TARGET_ARCH_MIPS64 75 // =========================================================================== 76 // == mips64 ================================================================= 77 // =========================================================================== 78 constexpr Register kGpParamRegisters[] = {a0, a2, a3, a4, a5, a6, a7}; 79 constexpr Register kGpReturnRegisters[] = {v0, v1}; 80 constexpr DoubleRegister kFpParamRegisters[] = {f2, f4, f6, f8, f10, f12, f14}; 81 constexpr DoubleRegister kFpReturnRegisters[] = {f2, f4}; 82 83 #elif V8_TARGET_ARCH_LOONG64 84 // =========================================================================== 85 // == LOONG64 ================================================================ 86 // =========================================================================== 87 constexpr Register kGpParamRegisters[] = {a0, a2, a3, a4, a5, a6, a7}; 88 constexpr Register kGpReturnRegisters[] = {a0, a1}; 89 constexpr DoubleRegister kFpParamRegisters[] = {f0, f1, f2, f3, f4, f5, f6, f7}; 90 constexpr DoubleRegister kFpReturnRegisters[] = {f0, f1}; 91 92 #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 93 // =========================================================================== 94 // == ppc & ppc64 ============================================================ 95 // =========================================================================== 96 constexpr Register kGpParamRegisters[] = {r10, r3, r5, r6, r7, r8, r9}; 97 constexpr Register kGpReturnRegisters[] = {r3, r4}; 98 constexpr DoubleRegister kFpParamRegisters[] = {d1, d2, d3, d4, d5, d6, d7, d8}; 99 constexpr DoubleRegister kFpReturnRegisters[] = {d1, d2}; 100 101 #elif V8_TARGET_ARCH_S390X 102 // =========================================================================== 103 // == s390x ================================================================== 104 // =========================================================================== 105 constexpr Register kGpParamRegisters[] = {r6, r2, r4, r5}; 106 constexpr Register kGpReturnRegisters[] = {r2, r3}; 107 constexpr DoubleRegister kFpParamRegisters[] = {d0, d2, d4, d6}; 108 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2, d4, d6}; 109 110 #elif V8_TARGET_ARCH_S390 111 // =========================================================================== 112 // == s390 =================================================================== 113 // =========================================================================== 114 constexpr Register kGpParamRegisters[] = {r6, r2, r4, r5}; 115 constexpr Register kGpReturnRegisters[] = {r2, r3}; 116 constexpr DoubleRegister kFpParamRegisters[] = {d0, d2}; 117 constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2}; 118 119 #elif V8_TARGET_ARCH_RISCV64 120 // =========================================================================== 121 // == riscv64 ================================================================= 122 // =========================================================================== 123 // Note that kGpParamRegisters and kFpParamRegisters are used in 124 // Builtins::Generate_WasmCompileLazy (builtins-riscv64.cc) 125 constexpr Register kGpParamRegisters[] = {a0, a2, a3, a4, a5, a6, a7}; 126 constexpr Register kGpReturnRegisters[] = {a0, a1}; 127 constexpr DoubleRegister kFpParamRegisters[] = {fa0, fa1, fa2, fa3, 128 fa4, fa5, fa6}; 129 constexpr DoubleRegister kFpReturnRegisters[] = {fa0, fa1}; 130 131 #else 132 // =========================================================================== 133 // == unknown ================================================================ 134 // =========================================================================== 135 // Do not use any registers, we will just always use the stack. 136 constexpr Register kGpParamRegisters[] = {}; 137 constexpr Register kGpReturnRegisters[] = {}; 138 constexpr DoubleRegister kFpParamRegisters[] = {}; 139 constexpr DoubleRegister kFpReturnRegisters[] = {}; 140 141 #endif 142 143 // The parameter index where the instance parameter should be placed in wasm 144 // call descriptors. This is used by the Int64Lowering::LowerNode method. 145 constexpr int kWasmInstanceParameterIndex = 0; 146 static_assert(kWasmInstanceRegister == 147 kGpParamRegisters[kWasmInstanceParameterIndex]); 148 149 class LinkageAllocator { 150 public: 151 template <size_t kNumGpRegs, size_t kNumFpRegs> LinkageAllocator(const Register (& gp)[kNumGpRegs],const DoubleRegister (& fp)[kNumFpRegs])152 constexpr LinkageAllocator(const Register (&gp)[kNumGpRegs], 153 const DoubleRegister (&fp)[kNumFpRegs]) 154 : LinkageAllocator(gp, kNumGpRegs, fp, kNumFpRegs) {} 155 LinkageAllocator(const Register * gp,int gpc,const DoubleRegister * fp,int fpc)156 constexpr LinkageAllocator(const Register* gp, int gpc, 157 const DoubleRegister* fp, int fpc) 158 : gp_count_(gpc), gp_regs_(gp), fp_count_(fpc), fp_regs_(fp) {} 159 CanAllocateGP()160 bool CanAllocateGP() const { return gp_offset_ < gp_count_; } CanAllocateFP(MachineRepresentation rep)161 bool CanAllocateFP(MachineRepresentation rep) const { 162 #if V8_TARGET_ARCH_ARM 163 switch (rep) { 164 case MachineRepresentation::kFloat32: { 165 // Get the next D-register (Liftoff only uses the even S-registers). 166 int next = fp_allocator_.NextSlot(2) / 2; 167 // Only the lower 16 D-registers alias S-registers. 168 return next < fp_count_ && fp_regs_[next].code() < 16; 169 } 170 case MachineRepresentation::kFloat64: { 171 int next = fp_allocator_.NextSlot(2) / 2; 172 return next < fp_count_; 173 } 174 case MachineRepresentation::kSimd128: { 175 int next = fp_allocator_.NextSlot(4) / 2; 176 return next < fp_count_ - 1; // 2 D-registers are required. 177 } 178 default: 179 UNREACHABLE(); 180 return false; 181 } 182 #else 183 return fp_offset_ < fp_count_; 184 #endif 185 } 186 NextGpReg()187 int NextGpReg() { 188 DCHECK_LT(gp_offset_, gp_count_); 189 return gp_regs_[gp_offset_++].code(); 190 } 191 NextFpReg(MachineRepresentation rep)192 int NextFpReg(MachineRepresentation rep) { 193 DCHECK(CanAllocateFP(rep)); 194 #if V8_TARGET_ARCH_ARM 195 switch (rep) { 196 case MachineRepresentation::kFloat32: { 197 // Liftoff uses only even-numbered S-registers, and encodes them using 198 // the code of the corresponding D-register. This limits the calling 199 // interface to only using the even-numbered S-registers. 200 int d_reg_code = NextFpReg(MachineRepresentation::kFloat64); 201 DCHECK_GT(16, d_reg_code); // D16 - D31 don't alias S-registers. 202 return d_reg_code * 2; 203 } 204 case MachineRepresentation::kFloat64: { 205 int next = fp_allocator_.Allocate(2) / 2; 206 return fp_regs_[next].code(); 207 } 208 case MachineRepresentation::kSimd128: { 209 int next = fp_allocator_.Allocate(4) / 2; 210 int d_reg_code = fp_regs_[next].code(); 211 // Check that result and the next D-register pair. 212 DCHECK_EQ(0, d_reg_code % 2); 213 DCHECK_EQ(d_reg_code + 1, fp_regs_[next + 1].code()); 214 return d_reg_code / 2; 215 } 216 default: 217 UNREACHABLE(); 218 } 219 #else 220 return fp_regs_[fp_offset_++].code(); 221 #endif 222 } 223 224 // Stackslots are counted upwards starting from 0 (or the offset set by 225 // {SetStackOffset}. If {type} needs more than one stack slot, the lowest 226 // used stack slot is returned. NextStackSlot(MachineRepresentation type)227 int NextStackSlot(MachineRepresentation type) { 228 int num_slots = 229 AlignedSlotAllocator::NumSlotsForWidth(ElementSizeInBytes(type)); 230 int slot = slot_allocator_.Allocate(num_slots); 231 return slot; 232 } 233 234 // Set an offset for the stack slots returned by {NextStackSlot} and 235 // {NumStackSlots}. Can only be called before any call to {NextStackSlot}. SetStackOffset(int offset)236 void SetStackOffset(int offset) { 237 DCHECK_LE(0, offset); 238 DCHECK_EQ(0, slot_allocator_.Size()); 239 slot_allocator_.AllocateUnaligned(offset); 240 } 241 NumStackSlots()242 int NumStackSlots() const { return slot_allocator_.Size(); } 243 EndSlotArea()244 void EndSlotArea() { slot_allocator_.AllocateUnaligned(0); } 245 246 private: 247 const int gp_count_; 248 int gp_offset_ = 0; 249 const Register* const gp_regs_; 250 251 const int fp_count_; 252 #if V8_TARGET_ARCH_ARM 253 // Use an aligned slot allocator to model ARM FP register aliasing. The slots 254 // are 32 bits, so 2 slots are required for a D-register, 4 for a Q-register. 255 AlignedSlotAllocator fp_allocator_; 256 #else 257 int fp_offset_ = 0; 258 #endif 259 const DoubleRegister* const fp_regs_; 260 261 AlignedSlotAllocator slot_allocator_; 262 }; 263 264 } // namespace wasm 265 } // namespace internal 266 } // namespace v8 267 268 #endif // V8_WASM_WASM_LINKAGE_H_ 269