Line data Source code
1 : // Copyright 2015 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 : #include "src/assembler-inl.h"
6 : #include "src/base/lazy-instance.h"
7 : #include "src/macro-assembler.h"
8 : #include "src/register-configuration.h"
9 :
10 : #include "src/compiler/linkage.h"
11 : #include "src/compiler/wasm-compiler.h"
12 :
13 : #include "src/zone/zone.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 : namespace compiler {
18 :
19 : using wasm::ValueType;
20 :
21 : namespace {
22 :
23 2651596 : MachineType MachineTypeFor(ValueType type) {
24 2651596 : switch (type) {
25 : case wasm::kWasmI32:
26 : return MachineType::Int32();
27 : case wasm::kWasmI64:
28 : return MachineType::Int64();
29 : case wasm::kWasmF64:
30 : return MachineType::Float64();
31 : case wasm::kWasmF32:
32 : return MachineType::Float32();
33 : case wasm::kWasmS128:
34 : return MachineType::Simd128();
35 : default:
36 0 : UNREACHABLE();
37 : }
38 : }
39 :
40 : LinkageLocation stackloc(int i, MachineType type) {
41 : return LinkageLocation::ForCallerFrameSlot(i, type);
42 : }
43 :
44 :
45 : #if V8_TARGET_ARCH_IA32
46 : // ===========================================================================
47 : // == ia32 ===================================================================
48 : // ===========================================================================
49 : #define GP_PARAM_REGISTERS esi, eax, edx, ecx, ebx
50 : #define GP_RETURN_REGISTERS eax, edx
51 : #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
52 : #define FP_RETURN_REGISTERS xmm1, xmm2
53 :
54 : #elif V8_TARGET_ARCH_X64
55 : // ===========================================================================
56 : // == x64 ====================================================================
57 : // ===========================================================================
58 : #define GP_PARAM_REGISTERS rsi, rax, rdx, rcx, rbx, rdi
59 : #define GP_RETURN_REGISTERS rax, rdx
60 : #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
61 : #define FP_RETURN_REGISTERS xmm1, xmm2
62 :
63 : #elif V8_TARGET_ARCH_ARM
64 : // ===========================================================================
65 : // == arm ====================================================================
66 : // ===========================================================================
67 : #define GP_PARAM_REGISTERS r3, r0, r1, r2
68 : #define GP_RETURN_REGISTERS r0, r1
69 : #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
70 : #define FP_RETURN_REGISTERS d0, d1
71 :
72 : #elif V8_TARGET_ARCH_ARM64
73 : // ===========================================================================
74 : // == arm64 ====================================================================
75 : // ===========================================================================
76 : #define GP_PARAM_REGISTERS x7, x0, x1, x2, x3, x4, x5, x6
77 : #define GP_RETURN_REGISTERS x0, x1
78 : #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
79 : #define FP_RETURN_REGISTERS d0, d1
80 :
81 : #elif V8_TARGET_ARCH_MIPS
82 : // ===========================================================================
83 : // == mips ===================================================================
84 : // ===========================================================================
85 : #define GP_PARAM_REGISTERS a0, a1, a2, a3
86 : #define GP_RETURN_REGISTERS v0, v1
87 : #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
88 : #define FP_RETURN_REGISTERS f2, f4
89 :
90 : #elif V8_TARGET_ARCH_MIPS64
91 : // ===========================================================================
92 : // == mips64 =================================================================
93 : // ===========================================================================
94 : #define GP_PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
95 : #define GP_RETURN_REGISTERS v0, v1
96 : #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
97 : #define FP_RETURN_REGISTERS f2, f4
98 :
99 : #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
100 : // ===========================================================================
101 : // == ppc & ppc64 ============================================================
102 : // ===========================================================================
103 : #define GP_PARAM_REGISTERS r10, r3, r4, r5, r6, r7, r8, r9
104 : #define GP_RETURN_REGISTERS r3, r4
105 : #define FP_PARAM_REGISTERS d1, d2, d3, d4, d5, d6, d7, d8
106 : #define FP_RETURN_REGISTERS d1, d2
107 :
108 : #elif V8_TARGET_ARCH_S390X
109 : // ===========================================================================
110 : // == s390x ==================================================================
111 : // ===========================================================================
112 : #define GP_PARAM_REGISTERS r6, r2, r3, r4, r5
113 : #define GP_RETURN_REGISTERS r2, r3
114 : #define FP_PARAM_REGISTERS d0, d2, d4, d6
115 : #define FP_RETURN_REGISTERS d0, d2, d4, d6
116 :
117 : #elif V8_TARGET_ARCH_S390
118 : // ===========================================================================
119 : // == s390 ===================================================================
120 : // ===========================================================================
121 : #define GP_PARAM_REGISTERS r6, r2, r3, r4, r5
122 : #define GP_RETURN_REGISTERS r2, r3
123 : #define FP_PARAM_REGISTERS d0, d2
124 : #define FP_RETURN_REGISTERS d0, d2
125 :
126 : #else
127 : // ===========================================================================
128 : // == unknown ================================================================
129 : // ===========================================================================
130 : // Do not use any registers, we will just always use the stack.
131 : #define GP_PARAM_REGISTERS
132 : #define GP_RETURN_REGISTERS
133 : #define FP_PARAM_REGISTERS
134 : #define FP_RETURN_REGISTERS
135 :
136 : #endif
137 :
138 :
139 : // Helper for allocating either an GP or FP reg, or the next stack slot.
140 : struct Allocator {
141 : constexpr Allocator(const Register* gp, int gpc, const DoubleRegister* fp,
142 : int fpc)
143 : : gp_count(gpc),
144 : gp_offset(0),
145 : gp_regs(gp),
146 : fp_count(fpc),
147 : fp_offset(0),
148 : fp_regs(fp),
149 : stack_offset(0) {}
150 :
151 : int gp_count;
152 : int gp_offset;
153 : const Register* gp_regs;
154 :
155 : int fp_count;
156 : int fp_offset;
157 : const DoubleRegister* fp_regs;
158 :
159 : int stack_offset;
160 :
161 2651583 : LinkageLocation Next(ValueType type) {
162 2651583 : if (IsFloatingPoint(type)) {
163 : // Allocate a floating point register/stack location.
164 1175275 : if (fp_offset < fp_count) {
165 1084996 : DoubleRegister reg = fp_regs[fp_offset++];
166 : #if V8_TARGET_ARCH_ARM
167 : // Allocate floats using a double register, but modify the code to
168 : // reflect how ARM FP registers alias.
169 : // TODO(bbudge) Modify wasm linkage to allow use of all float regs.
170 : if (type == wasm::kWasmF32) {
171 : int float_reg_code = reg.code() * 2;
172 : DCHECK_GT(RegisterConfiguration::kMaxFPRegisters, float_reg_code);
173 : return LinkageLocation::ForRegister(
174 : DoubleRegister::from_code(float_reg_code).code(),
175 : MachineTypeFor(type));
176 : }
177 : #endif
178 1084996 : return LinkageLocation::ForRegister(reg.code(), MachineTypeFor(type));
179 : } else {
180 90279 : int offset = -1 - stack_offset;
181 90279 : stack_offset += Words(type);
182 90279 : return stackloc(offset, MachineTypeFor(type));
183 : }
184 : } else {
185 : // Allocate a general purpose register/stack location.
186 1476308 : if (gp_offset < gp_count) {
187 1418831 : return LinkageLocation::ForRegister(gp_regs[gp_offset++].code(),
188 1418805 : MachineTypeFor(type));
189 : } else {
190 57503 : int offset = -1 - stack_offset;
191 57503 : stack_offset += Words(type);
192 57503 : return stackloc(offset, MachineTypeFor(type));
193 : }
194 : }
195 : }
196 : bool IsFloatingPoint(ValueType type) {
197 2651583 : return type == wasm::kWasmF32 || type == wasm::kWasmF64;
198 : }
199 : int Words(ValueType type) {
200 : if (kPointerSize < 8 &&
201 : (type == wasm::kWasmI64 || type == wasm::kWasmF64)) {
202 : return 2;
203 : }
204 : return 1;
205 : }
206 : };
207 :
208 : static constexpr Register kGPReturnRegisters[] = {GP_RETURN_REGISTERS};
209 : static constexpr DoubleRegister kFPReturnRegisters[] = {FP_RETURN_REGISTERS};
210 : static constexpr Register kGPParamRegisters[] = {GP_PARAM_REGISTERS};
211 : static constexpr DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
212 : static constexpr Allocator return_registers(kGPReturnRegisters,
213 : arraysize(kGPReturnRegisters),
214 : kFPReturnRegisters,
215 : arraysize(kFPReturnRegisters));
216 : static constexpr Allocator parameter_registers(kGPParamRegisters,
217 : arraysize(kGPParamRegisters),
218 : kFPParamRegisters,
219 : arraysize(kFPParamRegisters));
220 :
221 : } // namespace
222 :
223 : // General code uses the above configuration data.
224 4391333 : CallDescriptor* GetWasmCallDescriptor(Zone* zone, wasm::FunctionSig* fsig,
225 : bool supports_tail_calls) {
226 : // The '+ 1' here is to accomodate the wasm_context as first parameter.
227 : LocationSignature::Builder locations(zone, fsig->return_count(),
228 869866 : fsig->parameter_count() + 1);
229 :
230 869951 : Allocator rets = return_registers;
231 :
232 : // Add return location(s).
233 869951 : const int return_count = static_cast<int>(locations.return_count_);
234 1422913 : for (int i = 0; i < return_count; i++) {
235 552965 : ValueType ret = fsig->GetReturn(i);
236 552965 : locations.AddReturn(rets.Next(ret));
237 : }
238 :
239 869948 : Allocator params = parameter_registers;
240 :
241 : // Add parameter for the wasm_context.
242 869948 : locations.AddParam(params.Next(MachineType::PointerRepresentation()));
243 :
244 : // Add register and/or stack parameter(s).
245 869942 : const int parameter_count = static_cast<int>(fsig->parameter_count());
246 2098653 : for (int i = 0; i < parameter_count; i++) {
247 1228694 : ValueType param = fsig->GetParam(i);
248 1228694 : locations.AddParam(params.Next(param));
249 : }
250 :
251 : const RegList kCalleeSaveRegisters = 0;
252 : const RegList kCalleeSaveFPRegisters = 0;
253 :
254 : // The target for wasm calls is always a code object.
255 : MachineType target_type = MachineType::AnyTagged();
256 : LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
257 :
258 : CallDescriptor::Flags flags = CallDescriptor::kUseNativeStack;
259 869959 : if (supports_tail_calls) flags |= CallDescriptor::kSupportsTailCalls;
260 : return new (zone) CallDescriptor( // --
261 : CallDescriptor::kCallCodeObject, // kind
262 : target_type, // target MachineType
263 : target_loc, // target location
264 : locations.Build(), // location_sig
265 : params.stack_offset, // stack_parameter_count
266 : compiler::Operator::kNoProperties, // properties
267 : kCalleeSaveRegisters, // callee-saved registers
268 : kCalleeSaveFPRegisters, // callee-saved fp regs
269 : flags, // flags
270 2609835 : "wasm-call");
271 : }
272 :
273 0 : CallDescriptor* ReplaceTypeInCallDescriptorWith(
274 0 : Zone* zone, CallDescriptor* descriptor, size_t num_replacements,
275 : MachineType input_type, MachineRepresentation output_type) {
276 : size_t parameter_count = descriptor->ParameterCount();
277 : size_t return_count = descriptor->ReturnCount();
278 0 : for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
279 0 : if (descriptor->GetParameterType(i) == input_type) {
280 0 : parameter_count += num_replacements - 1;
281 : }
282 : }
283 0 : for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
284 0 : if (descriptor->GetReturnType(i) == input_type) {
285 0 : return_count += num_replacements - 1;
286 : }
287 : }
288 0 : if (parameter_count == descriptor->ParameterCount() &&
289 : return_count == descriptor->ReturnCount()) {
290 : return descriptor;
291 : }
292 :
293 : LocationSignature::Builder locations(zone, return_count, parameter_count);
294 :
295 0 : Allocator rets = return_registers;
296 :
297 0 : for (size_t i = 0; i < descriptor->ReturnCount(); i++) {
298 0 : if (descriptor->GetReturnType(i) == input_type) {
299 0 : for (size_t j = 0; j < num_replacements; j++) {
300 0 : locations.AddReturn(rets.Next(output_type));
301 : }
302 : } else {
303 : locations.AddReturn(
304 0 : rets.Next(descriptor->GetReturnType(i).representation()));
305 : }
306 : }
307 :
308 0 : Allocator params = parameter_registers;
309 :
310 0 : for (size_t i = 0; i < descriptor->ParameterCount(); i++) {
311 0 : if (descriptor->GetParameterType(i) == input_type) {
312 0 : for (size_t j = 0; j < num_replacements; j++) {
313 0 : locations.AddParam(params.Next(output_type));
314 : }
315 : } else {
316 : locations.AddParam(
317 0 : params.Next(descriptor->GetParameterType(i).representation()));
318 : }
319 : }
320 :
321 : return new (zone) CallDescriptor( // --
322 : descriptor->kind(), // kind
323 : descriptor->GetInputType(0), // target MachineType
324 : descriptor->GetInputLocation(0), // target location
325 : locations.Build(), // location_sig
326 : params.stack_offset, // stack_parameter_count
327 : descriptor->properties(), // properties
328 : descriptor->CalleeSavedRegisters(), // callee-saved registers
329 : descriptor->CalleeSavedFPRegisters(), // callee-saved fp regs
330 : descriptor->flags(), // flags
331 0 : descriptor->debug_name());
332 : }
333 :
334 0 : CallDescriptor* GetI32WasmCallDescriptor(Zone* zone,
335 : CallDescriptor* descriptor) {
336 : return ReplaceTypeInCallDescriptorWith(zone, descriptor, 2,
337 : MachineType::Int64(),
338 0 : MachineRepresentation::kWord32);
339 : }
340 :
341 0 : CallDescriptor* GetI32WasmCallDescriptorForSimd(Zone* zone,
342 : CallDescriptor* descriptor) {
343 : return ReplaceTypeInCallDescriptorWith(zone, descriptor, 4,
344 : MachineType::Simd128(),
345 0 : MachineRepresentation::kWord32);
346 : }
347 :
348 : #undef GP_PARAM_REGISTERS
349 : #undef GP_RETURN_REGISTERS
350 : #undef FP_PARAM_REGISTERS
351 : #undef FP_RETURN_REGISTERS
352 :
353 : } // namespace compiler
354 : } // namespace internal
355 : } // namespace v8
|