blob: 41acf55c441fc3413480286ab21f9eb5911fbab6 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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.h"
6#include "src/macro-assembler.h"
7
8#include "src/wasm/wasm-module.h"
9
10#include "src/compiler/linkage.h"
11
12#include "src/zone.h"
13
14namespace v8 {
15namespace internal {
16// TODO(titzer): this should not be in the WASM namespace.
17namespace wasm {
18
19using compiler::LocationSignature;
20using compiler::CallDescriptor;
21using compiler::LinkageLocation;
22
23namespace {
24MachineType MachineTypeFor(LocalType type) {
25 switch (type) {
26 case kAstI32:
27 return MachineType::Int32();
28 case kAstI64:
29 return MachineType::Int64();
30 case kAstF64:
31 return MachineType::Float64();
32 case kAstF32:
33 return MachineType::Float32();
34 default:
35 UNREACHABLE();
36 return MachineType::AnyTagged();
37 }
38}
39
40
41// Platform-specific configuration for C calling convention.
42LinkageLocation regloc(Register reg) {
43 return LinkageLocation::ForRegister(reg.code());
44}
45
46
47LinkageLocation regloc(DoubleRegister reg) {
48 return LinkageLocation::ForRegister(reg.code());
49}
50
51
52LinkageLocation stackloc(int i) {
53 return LinkageLocation::ForCallerFrameSlot(i);
54}
55
56
57#if V8_TARGET_ARCH_IA32
58// ===========================================================================
59// == ia32 ===================================================================
60// ===========================================================================
Ben Murdochc5610432016-08-08 18:44:38 +010061#define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000062#define GP_RETURN_REGISTERS eax, edx
63#define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
64#define FP_RETURN_REGISTERS xmm1, xmm2
65
66#elif V8_TARGET_ARCH_X64
67// ===========================================================================
68// == x64 ====================================================================
69// ===========================================================================
70#define GP_PARAM_REGISTERS rax, rdx, rcx, rbx, rsi, rdi
71#define GP_RETURN_REGISTERS rax, rdx
72#define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6
73#define FP_RETURN_REGISTERS xmm1, xmm2
74
75#elif V8_TARGET_ARCH_X87
76// ===========================================================================
77// == x87 ====================================================================
78// ===========================================================================
Ben Murdoch097c5b22016-05-18 11:27:45 +010079#define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080#define GP_RETURN_REGISTERS eax, edx
81#define FP_RETURN_REGISTERS stX_0
82
83#elif V8_TARGET_ARCH_ARM
84// ===========================================================================
85// == arm ====================================================================
86// ===========================================================================
87#define GP_PARAM_REGISTERS r0, r1, r2, r3
88#define GP_RETURN_REGISTERS r0, r1
89#define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
90#define FP_RETURN_REGISTERS d0, d1
91
92#elif V8_TARGET_ARCH_ARM64
93// ===========================================================================
94// == arm64 ====================================================================
95// ===========================================================================
96#define GP_PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7
97#define GP_RETURN_REGISTERS x0, x1
98#define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
99#define FP_RETURN_REGISTERS d0, d1
100
101#elif V8_TARGET_ARCH_MIPS
102// ===========================================================================
103// == mips ===================================================================
104// ===========================================================================
105#define GP_PARAM_REGISTERS a0, a1, a2, a3
106#define GP_RETURN_REGISTERS v0, v1
107#define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
108#define FP_RETURN_REGISTERS f2, f4
109
110#elif V8_TARGET_ARCH_MIPS64
111// ===========================================================================
112// == mips64 =================================================================
113// ===========================================================================
114#define GP_PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
115#define GP_RETURN_REGISTERS v0, v1
116#define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14
117#define FP_RETURN_REGISTERS f2, f4
118
119#elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
120// ===========================================================================
121// == ppc & ppc64 ============================================================
122// ===========================================================================
123#define GP_PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10
124#define GP_RETURN_REGISTERS r3, r4
125#define FP_PARAM_REGISTERS d1, d2, d3, d4, d5, d6, d7, d8
126#define FP_RETURN_REGISTERS d1, d2
127
Ben Murdochda12d292016-06-02 14:46:10 +0100128#elif V8_TARGET_ARCH_S390X
129// ===========================================================================
130// == s390x ==================================================================
131// ===========================================================================
132#define GP_PARAM_REGISTERS r2, r3, r4, r5, r6
133#define GP_RETURN_REGISTERS r2
134#define FP_PARAM_REGISTERS d0, d2, d4, d6
135#define FP_RETURN_REGISTERS d0, d2, d4, d6
136
137#elif V8_TARGET_ARCH_S390
138// ===========================================================================
139// == s390 ===================================================================
140// ===========================================================================
141#define GP_PARAM_REGISTERS r2, r3, r4, r5, r6
142#define GP_RETURN_REGISTERS r2, r3
143#define FP_PARAM_REGISTERS d0, d2
144#define FP_RETURN_REGISTERS d0, d2
145
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146#else
147// ===========================================================================
148// == unknown ================================================================
149// ===========================================================================
150// Don't define anything. We'll just always use the stack.
151#endif
152
153
154// Helper for allocating either an GP or FP reg, or the next stack slot.
155struct Allocator {
156 Allocator(const Register* gp, int gpc, const DoubleRegister* fp, int fpc)
157 : gp_count(gpc),
158 gp_offset(0),
159 gp_regs(gp),
160 fp_count(fpc),
161 fp_offset(0),
162 fp_regs(fp),
163 stack_offset(0) {}
164
165 int gp_count;
166 int gp_offset;
167 const Register* gp_regs;
168
169 int fp_count;
170 int fp_offset;
171 const DoubleRegister* fp_regs;
172
173 int stack_offset;
174
175 LinkageLocation Next(LocalType type) {
176 if (IsFloatingPoint(type)) {
177 // Allocate a floating point register/stack location.
178 if (fp_offset < fp_count) {
179 return regloc(fp_regs[fp_offset++]);
180 } else {
181 int offset = -1 - stack_offset;
182 stack_offset += Words(type);
183 return stackloc(offset);
184 }
185 } else {
186 // Allocate a general purpose register/stack location.
187 if (gp_offset < gp_count) {
188 return regloc(gp_regs[gp_offset++]);
189 } else {
190 int offset = -1 - stack_offset;
191 stack_offset += Words(type);
192 return stackloc(offset);
193 }
194 }
195 }
196 bool IsFloatingPoint(LocalType type) {
197 return type == kAstF32 || type == kAstF64;
198 }
199 int Words(LocalType type) {
200 // The code generation for pushing parameters on the stack does not
201 // distinguish between float32 and float64. Therefore also float32 needs
202 // two words.
203 if (kPointerSize < 8 &&
204 (type == kAstI64 || type == kAstF64 || type == kAstF32)) {
205 return 2;
206 }
207 return 1;
208 }
209};
210} // namespace
211
Ben Murdoch097c5b22016-05-18 11:27:45 +0100212static Allocator GetReturnRegisters() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213#ifdef GP_RETURN_REGISTERS
214 static const Register kGPReturnRegisters[] = {GP_RETURN_REGISTERS};
215 static const int kGPReturnRegistersCount =
216 static_cast<int>(arraysize(kGPReturnRegisters));
217#else
218 static const Register* kGPReturnRegisters = nullptr;
219 static const int kGPReturnRegistersCount = 0;
220#endif
221
222#ifdef FP_RETURN_REGISTERS
223 static const DoubleRegister kFPReturnRegisters[] = {FP_RETURN_REGISTERS};
224 static const int kFPReturnRegistersCount =
225 static_cast<int>(arraysize(kFPReturnRegisters));
226#else
227 static const DoubleRegister* kFPReturnRegisters = nullptr;
228 static const int kFPReturnRegistersCount = 0;
229#endif
230
231 Allocator rets(kGPReturnRegisters, kGPReturnRegistersCount,
232 kFPReturnRegisters, kFPReturnRegistersCount);
233
Ben Murdoch097c5b22016-05-18 11:27:45 +0100234 return rets;
235}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236
Ben Murdoch097c5b22016-05-18 11:27:45 +0100237static Allocator GetParameterRegisters() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238#ifdef GP_PARAM_REGISTERS
239 static const Register kGPParamRegisters[] = {GP_PARAM_REGISTERS};
240 static const int kGPParamRegistersCount =
241 static_cast<int>(arraysize(kGPParamRegisters));
242#else
243 static const Register* kGPParamRegisters = nullptr;
244 static const int kGPParamRegistersCount = 0;
245#endif
246
247#ifdef FP_PARAM_REGISTERS
248 static const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
249 static const int kFPParamRegistersCount =
250 static_cast<int>(arraysize(kFPParamRegisters));
251#else
252 static const DoubleRegister* kFPParamRegisters = nullptr;
253 static const int kFPParamRegistersCount = 0;
254#endif
255
256 Allocator params(kGPParamRegisters, kGPParamRegistersCount, kFPParamRegisters,
257 kFPParamRegistersCount);
258
Ben Murdoch097c5b22016-05-18 11:27:45 +0100259 return params;
260}
261
262// General code uses the above configuration data.
263CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
264 FunctionSig* fsig) {
265 MachineSignature::Builder msig(zone, fsig->return_count(),
266 fsig->parameter_count());
267 LocationSignature::Builder locations(zone, fsig->return_count(),
268 fsig->parameter_count());
269
270 Allocator rets = GetReturnRegisters();
271
272 // Add return location(s).
273 const int return_count = static_cast<int>(locations.return_count_);
274 for (int i = 0; i < return_count; i++) {
275 LocalType ret = fsig->GetReturn(i);
276 msig.AddReturn(MachineTypeFor(ret));
277 locations.AddReturn(rets.Next(ret));
278 }
279
280 Allocator params = GetParameterRegisters();
281
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 // Add register and/or stack parameter(s).
283 const int parameter_count = static_cast<int>(fsig->parameter_count());
284 for (int i = 0; i < parameter_count; i++) {
285 LocalType param = fsig->GetParam(i);
286 msig.AddParam(MachineTypeFor(param));
287 locations.AddParam(params.Next(param));
288 }
289
290 const RegList kCalleeSaveRegisters = 0;
291 const RegList kCalleeSaveFPRegisters = 0;
292
293 // The target for WASM calls is always a code object.
294 MachineType target_type = MachineType::AnyTagged();
295 LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100296
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297 return new (zone) CallDescriptor( // --
298 CallDescriptor::kCallCodeObject, // kind
299 target_type, // target MachineType
300 target_loc, // target location
301 msig.Build(), // machine_sig
302 locations.Build(), // location_sig
303 params.stack_offset, // stack_parameter_count
304 compiler::Operator::kNoProperties, // properties
305 kCalleeSaveRegisters, // callee-saved registers
306 kCalleeSaveFPRegisters, // callee-saved fp regs
307 CallDescriptor::kUseNativeStack, // flags
Ben Murdoch097c5b22016-05-18 11:27:45 +0100308 "wasm-call");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000309}
Ben Murdoch097c5b22016-05-18 11:27:45 +0100310
311CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor(
312 Zone* zone, CallDescriptor* descriptor) {
313 const MachineSignature* signature = descriptor->GetMachineSignature();
314 size_t parameter_count = signature->parameter_count();
315 size_t return_count = signature->return_count();
316 for (size_t i = 0; i < signature->parameter_count(); i++) {
317 if (signature->GetParam(i) == MachineType::Int64()) {
318 // For each int64 input we get two int32 inputs.
319 parameter_count++;
320 }
321 }
322 for (size_t i = 0; i < signature->return_count(); i++) {
323 if (signature->GetReturn(i) == MachineType::Int64()) {
324 // For each int64 return we get two int32 returns.
325 return_count++;
326 }
327 }
328 if (parameter_count == signature->parameter_count() &&
329 return_count == signature->return_count()) {
330 // If there is no int64 parameter or return value, we can just return the
331 // original descriptor.
332 return descriptor;
333 }
334
335 MachineSignature::Builder msig(zone, return_count, parameter_count);
336 LocationSignature::Builder locations(zone, return_count, parameter_count);
337
338 Allocator rets = GetReturnRegisters();
339
340 for (size_t i = 0; i < signature->return_count(); i++) {
341 if (signature->GetReturn(i) == MachineType::Int64()) {
342 // For each int64 return we get two int32 returns.
343 msig.AddReturn(MachineType::Int32());
344 msig.AddReturn(MachineType::Int32());
345 locations.AddReturn(rets.Next(MachineRepresentation::kWord32));
346 locations.AddReturn(rets.Next(MachineRepresentation::kWord32));
347 } else {
348 msig.AddReturn(signature->GetReturn(i));
349 locations.AddReturn(rets.Next(signature->GetReturn(i).representation()));
350 }
351 }
352
353 Allocator params = GetParameterRegisters();
354
355 for (size_t i = 0; i < signature->parameter_count(); i++) {
356 if (signature->GetParam(i) == MachineType::Int64()) {
357 // For each int64 input we get two int32 inputs.
358 msig.AddParam(MachineType::Int32());
359 msig.AddParam(MachineType::Int32());
360 locations.AddParam(params.Next(MachineRepresentation::kWord32));
361 locations.AddParam(params.Next(MachineRepresentation::kWord32));
362 } else {
363 msig.AddParam(signature->GetParam(i));
364 locations.AddParam(params.Next(signature->GetParam(i).representation()));
365 }
366 }
367
368 return new (zone) CallDescriptor( // --
369 descriptor->kind(), // kind
370 descriptor->GetInputType(0), // target MachineType
371 descriptor->GetInputLocation(0), // target location
372 msig.Build(), // machine_sig
373 locations.Build(), // location_sig
374 params.stack_offset, // stack_parameter_count
375 descriptor->properties(), // properties
376 descriptor->CalleeSavedRegisters(), // callee-saved registers
377 descriptor->CalleeSavedFPRegisters(), // callee-saved fp regs
378 descriptor->flags(), // flags
379 descriptor->debug_name());
380
381 return descriptor;
382}
383
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384} // namespace wasm
385} // namespace internal
386} // namespace v8