• 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 
8 #include "src/wasm/wasm-module.h"
9 
10 #include "src/compiler/linkage.h"
11 
12 #include "src/zone.h"
13 
14 namespace v8 {
15 namespace internal {
16 // TODO(titzer): this should not be in the WASM namespace.
17 namespace wasm {
18 
19 using compiler::LocationSignature;
20 using compiler::CallDescriptor;
21 using compiler::LinkageLocation;
22 
23 namespace {
MachineTypeFor(LocalType type)24 MachineType 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.
regloc(Register reg)42 LinkageLocation regloc(Register reg) {
43   return LinkageLocation::ForRegister(reg.code());
44 }
45 
46 
regloc(DoubleRegister reg)47 LinkageLocation regloc(DoubleRegister reg) {
48   return LinkageLocation::ForRegister(reg.code());
49 }
50 
51 
stackloc(int i)52 LinkageLocation stackloc(int i) {
53   return LinkageLocation::ForCallerFrameSlot(i);
54 }
55 
56 
57 #if V8_TARGET_ARCH_IA32
58 // ===========================================================================
59 // == ia32 ===================================================================
60 // ===========================================================================
61 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi
62 #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 // ===========================================================================
79 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi
80 #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 
128 #else
129 // ===========================================================================
130 // == unknown ================================================================
131 // ===========================================================================
132 // Don't define anything. We'll just always use the stack.
133 #endif
134 
135 
136 // Helper for allocating either an GP or FP reg, or the next stack slot.
137 struct Allocator {
Allocatorv8::internal::wasm::__anon7133e6080111::Allocator138   Allocator(const Register* gp, int gpc, const DoubleRegister* fp, int fpc)
139       : gp_count(gpc),
140         gp_offset(0),
141         gp_regs(gp),
142         fp_count(fpc),
143         fp_offset(0),
144         fp_regs(fp),
145         stack_offset(0) {}
146 
147   int gp_count;
148   int gp_offset;
149   const Register* gp_regs;
150 
151   int fp_count;
152   int fp_offset;
153   const DoubleRegister* fp_regs;
154 
155   int stack_offset;
156 
Nextv8::internal::wasm::__anon7133e6080111::Allocator157   LinkageLocation Next(LocalType type) {
158     if (IsFloatingPoint(type)) {
159       // Allocate a floating point register/stack location.
160       if (fp_offset < fp_count) {
161         return regloc(fp_regs[fp_offset++]);
162       } else {
163         int offset = -1 - stack_offset;
164         stack_offset += Words(type);
165         return stackloc(offset);
166       }
167     } else {
168       // Allocate a general purpose register/stack location.
169       if (gp_offset < gp_count) {
170         return regloc(gp_regs[gp_offset++]);
171       } else {
172         int offset = -1 - stack_offset;
173         stack_offset += Words(type);
174         return stackloc(offset);
175       }
176     }
177   }
IsFloatingPointv8::internal::wasm::__anon7133e6080111::Allocator178   bool IsFloatingPoint(LocalType type) {
179     return type == kAstF32 || type == kAstF64;
180   }
Wordsv8::internal::wasm::__anon7133e6080111::Allocator181   int Words(LocalType type) {
182     // The code generation for pushing parameters on the stack does not
183     // distinguish between float32 and float64. Therefore also float32 needs
184     // two words.
185     if (kPointerSize < 8 &&
186         (type == kAstI64 || type == kAstF64 || type == kAstF32)) {
187       return 2;
188     }
189     return 1;
190   }
191 };
192 }  // namespace
193 
194 
195 // General code uses the above configuration data.
GetWasmCallDescriptor(Zone * zone,FunctionSig * fsig)196 CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone,
197                                                  FunctionSig* fsig) {
198   MachineSignature::Builder msig(zone, fsig->return_count(),
199                                  fsig->parameter_count());
200   LocationSignature::Builder locations(zone, fsig->return_count(),
201                                        fsig->parameter_count());
202 
203 #ifdef GP_RETURN_REGISTERS
204   static const Register kGPReturnRegisters[] = {GP_RETURN_REGISTERS};
205   static const int kGPReturnRegistersCount =
206       static_cast<int>(arraysize(kGPReturnRegisters));
207 #else
208   static const Register* kGPReturnRegisters = nullptr;
209   static const int kGPReturnRegistersCount = 0;
210 #endif
211 
212 #ifdef FP_RETURN_REGISTERS
213   static const DoubleRegister kFPReturnRegisters[] = {FP_RETURN_REGISTERS};
214   static const int kFPReturnRegistersCount =
215       static_cast<int>(arraysize(kFPReturnRegisters));
216 #else
217   static const DoubleRegister* kFPReturnRegisters = nullptr;
218   static const int kFPReturnRegistersCount = 0;
219 #endif
220 
221   Allocator rets(kGPReturnRegisters, kGPReturnRegistersCount,
222                  kFPReturnRegisters, kFPReturnRegistersCount);
223 
224   // Add return location(s).
225   const int return_count = static_cast<int>(locations.return_count_);
226   for (int i = 0; i < return_count; i++) {
227     LocalType ret = fsig->GetReturn(i);
228     msig.AddReturn(MachineTypeFor(ret));
229     locations.AddReturn(rets.Next(ret));
230   }
231 
232 #ifdef GP_PARAM_REGISTERS
233   static const Register kGPParamRegisters[] = {GP_PARAM_REGISTERS};
234   static const int kGPParamRegistersCount =
235       static_cast<int>(arraysize(kGPParamRegisters));
236 #else
237   static const Register* kGPParamRegisters = nullptr;
238   static const int kGPParamRegistersCount = 0;
239 #endif
240 
241 #ifdef FP_PARAM_REGISTERS
242   static const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
243   static const int kFPParamRegistersCount =
244       static_cast<int>(arraysize(kFPParamRegisters));
245 #else
246   static const DoubleRegister* kFPParamRegisters = nullptr;
247   static const int kFPParamRegistersCount = 0;
248 #endif
249 
250   Allocator params(kGPParamRegisters, kGPParamRegistersCount, kFPParamRegisters,
251                    kFPParamRegistersCount);
252 
253   // Add register and/or stack parameter(s).
254   const int parameter_count = static_cast<int>(fsig->parameter_count());
255   for (int i = 0; i < parameter_count; i++) {
256     LocalType param = fsig->GetParam(i);
257     msig.AddParam(MachineTypeFor(param));
258     locations.AddParam(params.Next(param));
259   }
260 
261   const RegList kCalleeSaveRegisters = 0;
262   const RegList kCalleeSaveFPRegisters = 0;
263 
264   // The target for WASM calls is always a code object.
265   MachineType target_type = MachineType::AnyTagged();
266   LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
267   return new (zone) CallDescriptor(       // --
268       CallDescriptor::kCallCodeObject,    // kind
269       target_type,                        // target MachineType
270       target_loc,                         // target location
271       msig.Build(),                       // machine_sig
272       locations.Build(),                  // location_sig
273       params.stack_offset,                // stack_parameter_count
274       compiler::Operator::kNoProperties,  // properties
275       kCalleeSaveRegisters,               // callee-saved registers
276       kCalleeSaveFPRegisters,             // callee-saved fp regs
277       CallDescriptor::kUseNativeStack,    // flags
278       "c-call");
279 }
280 }  // namespace wasm
281 }  // namespace internal
282 }  // namespace v8
283