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