• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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