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