wasm-linkage.cc revision 21efce637eb329c94f1323b6a2334a1c977e1a9d
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 15namespace v8 { 16namespace internal { 17// TODO(titzer): this should not be in the WASM namespace. 18namespace wasm { 19 20using compiler::LocationSignature; 21using compiler::CallDescriptor; 22using compiler::LinkageLocation; 23 24namespace { 25MachineType 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. 45LinkageLocation regloc(Register reg) { 46 return LinkageLocation::ForRegister(reg.code()); 47} 48 49 50LinkageLocation regloc(DoubleRegister reg) { 51 return LinkageLocation::ForRegister(reg.code()); 52} 53 54 55LinkageLocation 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. 158struct Allocator { 159 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 178 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 } 210 bool IsFloatingPoint(LocalType type) { 211 return type == kAstF32 || type == kAstF64; 212 } 213 int Words(LocalType type) { 214 if (kPointerSize < 8 && (type == kAstI64 || type == kAstF64)) { 215 return 2; 216 } 217 return 1; 218 } 219}; 220} // namespace 221 222static 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 247static 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. 273CallDescriptor* 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 321CallDescriptor* 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