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