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 17 namespace v8 { 18 namespace internal { 19 // TODO(titzer): this should not be in the WASM namespace. 20 namespace wasm { 21 22 using compiler::LocationSignature; 23 using compiler::CallDescriptor; 24 using compiler::LinkageLocation; 25 26 namespace { 27 28 MachineType 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 46 LinkageLocation regloc(Register reg, MachineType type) { 47 return LinkageLocation::ForRegister(reg.code(), type); 48 } 49 50 LinkageLocation regloc(DoubleRegister reg, MachineType type) { 51 return LinkageLocation::ForRegister(reg.code(), type); 52 } 53 54 LinkageLocation 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. 157 struct 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 222 struct 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 247 static base::LazyInstance<Allocator, ParameterRegistersCreateTrait>::type 248 parameter_registers = LAZY_INSTANCE_INITIALIZER; 249 250 struct 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 275 static base::LazyInstance<Allocator, ReturnRegistersCreateTrait>::type 276 return_registers = LAZY_INSTANCE_INITIALIZER; 277 278 // General code uses the above configuration data. 279 CallDescriptor* 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 322 CallDescriptor* 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 383 CallDescriptor* ModuleEnv::GetI32WasmCallDescriptor( 384 Zone* zone, CallDescriptor* descriptor) { 385 return ReplaceTypeInCallDescriptorWith(zone, descriptor, 2, 386 MachineType::Int64(), 387 MachineRepresentation::kWord32); 388 } 389 390 CallDescriptor* 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