• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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