Line data Source code
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 :
121 : class LinkageAllocator {
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 32712 : : 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 5007728 : 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 520678 : 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 350046 : return std::max(1, ElementSizeInBytes(type) / kSystemPointerSize);
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 175023 : int NextStackSlot(MachineRepresentation type) {
215 : int num_stack_slots = NumStackSlots(type);
216 175023 : int offset = stack_offset_;
217 175023 : stack_offset_ += num_stack_slots;
218 175023 : 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 2521897 : 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_
|