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