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 8 #include "src/wasm/wasm-module.h" 9 10 #include "src/compiler/linkage.h" 11 12 #include "src/zone.h" 13 14 namespace v8 { 15 namespace internal { 16 // TODO(titzer): this should not be in the WASM namespace. 17 namespace wasm { 18 19 using compiler::LocationSignature; 20 using compiler::CallDescriptor; 21 using compiler::LinkageLocation; 22 23 namespace { 24 MachineType MachineTypeFor(LocalType type) { 25 switch (type) { 26 case kAstI32: 27 return MachineType::Int32(); 28 case kAstI64: 29 return MachineType::Int64(); 30 case kAstF64: 31 return MachineType::Float64(); 32 case kAstF32: 33 return MachineType::Float32(); 34 default: 35 UNREACHABLE(); 36 return MachineType::AnyTagged(); 37 } 38 } 39 40 41 // Platform-specific configuration for C calling convention. 42 LinkageLocation regloc(Register reg) { 43 return LinkageLocation::ForRegister(reg.code()); 44 } 45 46 47 LinkageLocation regloc(DoubleRegister reg) { 48 return LinkageLocation::ForRegister(reg.code()); 49 } 50 51 52 LinkageLocation stackloc(int i) { 53 return LinkageLocation::ForCallerFrameSlot(i); 54 } 55 56 57 #if V8_TARGET_ARCH_IA32 58 // =========================================================================== 59 // == ia32 =================================================================== 60 // =========================================================================== 61 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi 62 #define GP_RETURN_REGISTERS eax, edx 63 #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6 64 #define FP_RETURN_REGISTERS xmm1, xmm2 65 66 #elif V8_TARGET_ARCH_X64 67 // =========================================================================== 68 // == x64 ==================================================================== 69 // =========================================================================== 70 #define GP_PARAM_REGISTERS rax, rdx, rcx, rbx, rsi, rdi 71 #define GP_RETURN_REGISTERS rax, rdx 72 #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6 73 #define FP_RETURN_REGISTERS xmm1, xmm2 74 75 #elif V8_TARGET_ARCH_X87 76 // =========================================================================== 77 // == x87 ==================================================================== 78 // =========================================================================== 79 #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi 80 #define GP_RETURN_REGISTERS eax, edx 81 #define FP_RETURN_REGISTERS stX_0 82 83 #elif V8_TARGET_ARCH_ARM 84 // =========================================================================== 85 // == arm ==================================================================== 86 // =========================================================================== 87 #define GP_PARAM_REGISTERS r0, r1, r2, r3 88 #define GP_RETURN_REGISTERS r0, r1 89 #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7 90 #define FP_RETURN_REGISTERS d0, d1 91 92 #elif V8_TARGET_ARCH_ARM64 93 // =========================================================================== 94 // == arm64 ==================================================================== 95 // =========================================================================== 96 #define GP_PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7 97 #define GP_RETURN_REGISTERS x0, x1 98 #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7 99 #define FP_RETURN_REGISTERS d0, d1 100 101 #elif V8_TARGET_ARCH_MIPS 102 // =========================================================================== 103 // == mips =================================================================== 104 // =========================================================================== 105 #define GP_PARAM_REGISTERS a0, a1, a2, a3 106 #define GP_RETURN_REGISTERS v0, v1 107 #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14 108 #define FP_RETURN_REGISTERS f2, f4 109 110 #elif V8_TARGET_ARCH_MIPS64 111 // =========================================================================== 112 // == mips64 ================================================================= 113 // =========================================================================== 114 #define GP_PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7 115 #define GP_RETURN_REGISTERS v0, v1 116 #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14 117 #define FP_RETURN_REGISTERS f2, f4 118 119 #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 120 // =========================================================================== 121 // == ppc & ppc64 ============================================================ 122 // =========================================================================== 123 #define GP_PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10 124 #define GP_RETURN_REGISTERS r3, r4 125 #define FP_PARAM_REGISTERS d1, d2, d3, d4, d5, d6, d7, d8 126 #define FP_RETURN_REGISTERS d1, d2 127 128 #else 129 // =========================================================================== 130 // == unknown ================================================================ 131 // =========================================================================== 132 // Don't define anything. We'll just always use the stack. 133 #endif 134 135 136 // Helper for allocating either an GP or FP reg, or the next stack slot. 137 struct Allocator { 138 Allocator(const Register* gp, int gpc, const DoubleRegister* fp, int fpc) 139 : gp_count(gpc), 140 gp_offset(0), 141 gp_regs(gp), 142 fp_count(fpc), 143 fp_offset(0), 144 fp_regs(fp), 145 stack_offset(0) {} 146 147 int gp_count; 148 int gp_offset; 149 const Register* gp_regs; 150 151 int fp_count; 152 int fp_offset; 153 const DoubleRegister* fp_regs; 154 155 int stack_offset; 156 157 LinkageLocation Next(LocalType type) { 158 if (IsFloatingPoint(type)) { 159 // Allocate a floating point register/stack location. 160 if (fp_offset < fp_count) { 161 return regloc(fp_regs[fp_offset++]); 162 } else { 163 int offset = -1 - stack_offset; 164 stack_offset += Words(type); 165 return stackloc(offset); 166 } 167 } else { 168 // Allocate a general purpose register/stack location. 169 if (gp_offset < gp_count) { 170 return regloc(gp_regs[gp_offset++]); 171 } else { 172 int offset = -1 - stack_offset; 173 stack_offset += Words(type); 174 return stackloc(offset); 175 } 176 } 177 } 178 bool IsFloatingPoint(LocalType type) { 179 return type == kAstF32 || type == kAstF64; 180 } 181 int Words(LocalType type) { 182 // The code generation for pushing parameters on the stack does not 183 // distinguish between float32 and float64. Therefore also float32 needs 184 // two words. 185 if (kPointerSize < 8 && 186 (type == kAstI64 || type == kAstF64 || type == kAstF32)) { 187 return 2; 188 } 189 return 1; 190 } 191 }; 192 } // namespace 193 194 195 // General code uses the above configuration data. 196 CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone, 197 FunctionSig* fsig) { 198 MachineSignature::Builder msig(zone, fsig->return_count(), 199 fsig->parameter_count()); 200 LocationSignature::Builder locations(zone, fsig->return_count(), 201 fsig->parameter_count()); 202 203 #ifdef GP_RETURN_REGISTERS 204 static const Register kGPReturnRegisters[] = {GP_RETURN_REGISTERS}; 205 static const int kGPReturnRegistersCount = 206 static_cast<int>(arraysize(kGPReturnRegisters)); 207 #else 208 static const Register* kGPReturnRegisters = nullptr; 209 static const int kGPReturnRegistersCount = 0; 210 #endif 211 212 #ifdef FP_RETURN_REGISTERS 213 static const DoubleRegister kFPReturnRegisters[] = {FP_RETURN_REGISTERS}; 214 static const int kFPReturnRegistersCount = 215 static_cast<int>(arraysize(kFPReturnRegisters)); 216 #else 217 static const DoubleRegister* kFPReturnRegisters = nullptr; 218 static const int kFPReturnRegistersCount = 0; 219 #endif 220 221 Allocator rets(kGPReturnRegisters, kGPReturnRegistersCount, 222 kFPReturnRegisters, kFPReturnRegistersCount); 223 224 // Add return location(s). 225 const int return_count = static_cast<int>(locations.return_count_); 226 for (int i = 0; i < return_count; i++) { 227 LocalType ret = fsig->GetReturn(i); 228 msig.AddReturn(MachineTypeFor(ret)); 229 locations.AddReturn(rets.Next(ret)); 230 } 231 232 #ifdef GP_PARAM_REGISTERS 233 static const Register kGPParamRegisters[] = {GP_PARAM_REGISTERS}; 234 static const int kGPParamRegistersCount = 235 static_cast<int>(arraysize(kGPParamRegisters)); 236 #else 237 static const Register* kGPParamRegisters = nullptr; 238 static const int kGPParamRegistersCount = 0; 239 #endif 240 241 #ifdef FP_PARAM_REGISTERS 242 static const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS}; 243 static const int kFPParamRegistersCount = 244 static_cast<int>(arraysize(kFPParamRegisters)); 245 #else 246 static const DoubleRegister* kFPParamRegisters = nullptr; 247 static const int kFPParamRegistersCount = 0; 248 #endif 249 250 Allocator params(kGPParamRegisters, kGPParamRegistersCount, kFPParamRegisters, 251 kFPParamRegistersCount); 252 253 // Add register and/or stack parameter(s). 254 const int parameter_count = static_cast<int>(fsig->parameter_count()); 255 for (int i = 0; i < parameter_count; i++) { 256 LocalType param = fsig->GetParam(i); 257 msig.AddParam(MachineTypeFor(param)); 258 locations.AddParam(params.Next(param)); 259 } 260 261 const RegList kCalleeSaveRegisters = 0; 262 const RegList kCalleeSaveFPRegisters = 0; 263 264 // The target for WASM calls is always a code object. 265 MachineType target_type = MachineType::AnyTagged(); 266 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); 267 return new (zone) CallDescriptor( // -- 268 CallDescriptor::kCallCodeObject, // kind 269 target_type, // target MachineType 270 target_loc, // target location 271 msig.Build(), // machine_sig 272 locations.Build(), // location_sig 273 params.stack_offset, // stack_parameter_count 274 compiler::Operator::kNoProperties, // properties 275 kCalleeSaveRegisters, // callee-saved registers 276 kCalleeSaveFPRegisters, // callee-saved fp regs 277 CallDescriptor::kUseNativeStack, // flags 278 "c-call"); 279 } 280 } // namespace wasm 281 } // namespace internal 282 } // namespace v8 283