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 { 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. 45 LinkageLocation regloc(Register reg) { 46 return LinkageLocation::ForRegister(reg.code()); 47 } 48 49 50 LinkageLocation regloc(DoubleRegister reg) { 51 return LinkageLocation::ForRegister(reg.code()); 52 } 53 54 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 { 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 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 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. 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 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