Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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" |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 7 | #include "src/register-configuration.h" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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(); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 35 | case kAstS128: |
| 36 | return MachineType::Simd128(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | // =========================================================================== |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame] | 64 | #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | // =========================================================================== |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 82 | #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 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); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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) { |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 214 | if (kPointerSize < 8 && (type == kAstI64 || type == kAstF64)) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 215 | return 2; |
| 216 | } |
| 217 | return 1; |
| 218 | } |
| 219 | }; |
| 220 | } // namespace |
| 221 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 222 | static Allocator GetReturnRegisters() { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 244 | return rets; |
| 245 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 246 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 247 | static Allocator GetParameterRegisters() { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 306 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 318 | "wasm-call"); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 319 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 394 | } // namespace wasm |
| 395 | } // namespace internal |
| 396 | } // namespace v8 |