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/codegen/assembler-inl.h" 6#include "src/codegen/macro-assembler.h" 7#include "src/compiler/globals.h" 8#include "src/compiler/linkage.h" 9#include "src/zone/zone.h" 10 11namespace v8 { 12namespace internal { 13namespace compiler { 14 15namespace { 16 17// Platform-specific configuration for C calling convention. 18#if V8_TARGET_ARCH_IA32 19// =========================================================================== 20// == ia32 =================================================================== 21// =========================================================================== 22#define CALLEE_SAVE_REGISTERS esi, edi, ebx 23#define CALLEE_SAVE_FP_REGISTERS 24 25#elif V8_TARGET_ARCH_X64 26// =========================================================================== 27// == x64 ==================================================================== 28// =========================================================================== 29 30#ifdef V8_TARGET_OS_WIN 31// == x64 windows ============================================================ 32#define STACK_SHADOW_WORDS 4 33#define PARAM_REGISTERS rcx, rdx, r8, r9 34#define FP_PARAM_REGISTERS xmm0, xmm1, xmm2, xmm3 35#define FP_RETURN_REGISTER xmm0 36#define CALLEE_SAVE_REGISTERS rbx, rdi, rsi, r12, r13, r14, r15 37#define CALLEE_SAVE_FP_REGISTERS \ 38 xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 39 40#else // V8_TARGET_OS_WIN 41// == x64 other ============================================================== 42#define PARAM_REGISTERS rdi, rsi, rdx, rcx, r8, r9 43#define FP_PARAM_REGISTERS xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 44#define FP_RETURN_REGISTER xmm0 45#define CALLEE_SAVE_REGISTERS rbx, r12, r13, r14, r15 46#define CALLEE_SAVE_FP_REGISTERS 47#endif // V8_TARGET_OS_WIN 48 49#elif V8_TARGET_ARCH_ARM 50// =========================================================================== 51// == arm ==================================================================== 52// =========================================================================== 53#define PARAM_REGISTERS r0, r1, r2, r3 54#define CALLEE_SAVE_REGISTERS r4, r5, r6, r7, r8, r9, r10 55#define CALLEE_SAVE_FP_REGISTERS d8, d9, d10, d11, d12, d13, d14, d15 56 57#elif V8_TARGET_ARCH_ARM64 58// =========================================================================== 59// == arm64 ==================================================================== 60// =========================================================================== 61#define PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7 62#define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7 63#define FP_RETURN_REGISTER d0 64#define CALLEE_SAVE_REGISTERS x19, x20, x21, x22, x23, x24, x25, x26, x27, x28 65 66#define CALLEE_SAVE_FP_REGISTERS d8, d9, d10, d11, d12, d13, d14, d15 67 68#elif V8_TARGET_ARCH_MIPS 69// =========================================================================== 70// == mips =================================================================== 71// =========================================================================== 72#define STACK_SHADOW_WORDS 4 73#define PARAM_REGISTERS a0, a1, a2, a3 74#define CALLEE_SAVE_REGISTERS s0, s1, s2, s3, s4, s5, s6, s7 75#define CALLEE_SAVE_FP_REGISTERS f20, f22, f24, f26, f28, f30 76 77#elif V8_TARGET_ARCH_MIPS64 78// =========================================================================== 79// == mips64 ================================================================= 80// =========================================================================== 81#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7 82#define CALLEE_SAVE_REGISTERS s0, s1, s2, s3, s4, s5, s6, s7 83#define CALLEE_SAVE_FP_REGISTERS f20, f22, f24, f26, f28, f30 84 85#elif V8_TARGET_ARCH_LOONG64 86// =========================================================================== 87// == loong64 ================================================================ 88// =========================================================================== 89#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7 90#define CALLEE_SAVE_REGISTERS s0, s1, s2, s3, s4, s5, s6, s7, s8, fp 91#define CALLEE_SAVE_FP_REGISTERS f24, f25, f26, f27, f28, f29, f30, f31 92 93#elif V8_TARGET_ARCH_PPC64 94// =========================================================================== 95// == ppc & ppc64 ============================================================ 96// =========================================================================== 97#ifdef V8_TARGET_LITTLE_ENDIAN // ppc64le linux 98#define STACK_SHADOW_WORDS 12 99#else // AIX 100#define STACK_SHADOW_WORDS 14 101#endif 102#define PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10 103#define CALLEE_SAVE_REGISTERS \ 104 r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, \ 105 r29, r30 106 107#define CALLEE_SAVE_FP_REGISTERS \ 108 d14, d15, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, \ 109 d29, d30, d31 110 111#elif V8_TARGET_ARCH_S390X 112// =========================================================================== 113// == s390x ================================================================== 114// =========================================================================== 115#define STACK_SHADOW_WORDS 20 116#define PARAM_REGISTERS r2, r3, r4, r5, r6 117#define CALLEE_SAVE_REGISTERS r6, r7, r8, r9, r10, ip, r13 118#define CALLEE_SAVE_FP_REGISTERS d8, d9, d10, d11, d12, d13, d14, d15 119 120#elif V8_TARGET_ARCH_RISCV64 121// =========================================================================== 122// == riscv64 ================================================================= 123// =========================================================================== 124#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7 125// fp is not part of CALLEE_SAVE_REGISTERS (similar to how MIPS64 or PPC defines 126// it) 127#define CALLEE_SAVE_REGISTERS s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 128#define CALLEE_SAVE_FP_REGISTERS \ 129 fs0, fs1, fs2, fs3, fs4, fs5, fs6, fs7, fs8, fs9, fs10, fs11 130#else 131// =========================================================================== 132// == unknown ================================================================ 133// =========================================================================== 134#define UNSUPPORTED_C_LINKAGE 1 135#endif 136} // namespace 137 138#if defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64) 139// As defined in 140// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019#parameter-passing, 141// Windows calling convention doesn't differentiate between GP and FP params 142// when counting how many of them should be placed in registers. That's why 143// we use the same counter {i} for both types here. 144void BuildParameterLocations(const MachineSignature* msig, 145 size_t kFPParamRegisterCount, 146 size_t kParamRegisterCount, 147 const DoubleRegister* kFPParamRegisters, 148 const v8::internal::Register* kParamRegisters, 149 LocationSignature::Builder* out_locations) { 150#ifdef STACK_SHADOW_WORDS 151 int stack_offset = STACK_SHADOW_WORDS; 152#else 153 int stack_offset = 0; 154#endif 155 CHECK_EQ(kFPParamRegisterCount, kParamRegisterCount); 156 157 for (size_t i = 0; i < msig->parameter_count(); i++) { 158 MachineType type = msig->GetParam(i); 159 bool spill = (i >= kParamRegisterCount); 160 if (spill) { 161 out_locations->AddParam( 162 LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type)); 163 stack_offset++; 164 } else { 165 if (IsFloatingPoint(type.representation())) { 166 out_locations->AddParam( 167 LinkageLocation::ForRegister(kFPParamRegisters[i].code(), type)); 168 } else { 169 out_locations->AddParam( 170 LinkageLocation::ForRegister(kParamRegisters[i].code(), type)); 171 } 172 } 173 } 174} 175#else // defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64) 176// As defined in https://www.agner.org/optimize/calling_conventions.pdf, 177// Section 7, Linux and Mac place parameters in consecutive registers, 178// differentiating between GP and FP params. That's why we maintain two 179// separate counters here. This also applies to Arm systems following 180// the AAPCS and Windows on Arm. 181void BuildParameterLocations(const MachineSignature* msig, 182 size_t kFPParamRegisterCount, 183 size_t kParamRegisterCount, 184 const DoubleRegister* kFPParamRegisters, 185 const v8::internal::Register* kParamRegisters, 186 LocationSignature::Builder* out_locations) { 187#ifdef STACK_SHADOW_WORDS 188 int stack_offset = STACK_SHADOW_WORDS; 189#else 190 int stack_offset = 0; 191#endif 192 size_t num_params = 0; 193 size_t num_fp_params = 0; 194 for (size_t i = 0; i < msig->parameter_count(); i++) { 195 MachineType type = msig->GetParam(i); 196 bool spill = IsFloatingPoint(type.representation()) 197 ? (num_fp_params >= kFPParamRegisterCount) 198 : (num_params >= kParamRegisterCount); 199 if (spill) { 200 out_locations->AddParam( 201 LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type)); 202 stack_offset++; 203 } else { 204 if (IsFloatingPoint(type.representation())) { 205 out_locations->AddParam(LinkageLocation::ForRegister( 206 kFPParamRegisters[num_fp_params].code(), type)); 207 ++num_fp_params; 208 } else { 209 out_locations->AddParam(LinkageLocation::ForRegister( 210 kParamRegisters[num_params].code(), type)); 211 ++num_params; 212 } 213 } 214 } 215} 216#endif // defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64) 217 218// General code uses the above configuration data. 219CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone, 220 const MachineSignature* msig, 221 CallDescriptor::Flags flags) { 222#ifdef UNSUPPORTED_C_LINKAGE 223 // This method should not be called on unknown architectures. 224 FATAL("requested C call descriptor on unsupported architecture"); 225 return nullptr; 226#endif 227 228 DCHECK_LE(msig->parameter_count(), static_cast<size_t>(kMaxCParameters)); 229 230 LocationSignature::Builder locations(zone, msig->return_count(), 231 msig->parameter_count()); 232 233#ifndef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE 234 // Check the types of the signature. 235 for (size_t i = 0; i < msig->parameter_count(); i++) { 236 MachineType type = msig->GetParam(i); 237 CHECK(!IsFloatingPoint(type.representation())); 238 } 239 240 // Check the return types. 241 for (size_t i = 0; i < locations.return_count_; i++) { 242 MachineType type = msig->GetReturn(i); 243 CHECK(!IsFloatingPoint(type.representation())); 244 } 245#endif 246 247 CHECK_GE(2, locations.return_count_); 248 if (locations.return_count_ > 0) { 249#ifdef FP_RETURN_REGISTER 250 const v8::internal::DoubleRegister kFPReturnRegister = FP_RETURN_REGISTER; 251 auto reg = IsFloatingPoint(msig->GetReturn(0).representation()) 252 ? kFPReturnRegister.code() 253 : kReturnRegister0.code(); 254#else 255 auto reg = kReturnRegister0.code(); 256#endif 257 // TODO(chromium:1052746): Use the correctly sized register here (e.g. "al" 258 // if the return type is kBit), so we don't have to use a hacky bitwise AND 259 // elsewhere. 260 locations.AddReturn(LinkageLocation::ForRegister(reg, msig->GetReturn(0))); 261 } 262 263 if (locations.return_count_ > 1) { 264 DCHECK(!IsFloatingPoint(msig->GetReturn(0).representation())); 265 266 locations.AddReturn(LinkageLocation::ForRegister(kReturnRegister1.code(), 267 msig->GetReturn(1))); 268 } 269 270#ifdef PARAM_REGISTERS 271 const v8::internal::Register kParamRegisters[] = {PARAM_REGISTERS}; 272 const int kParamRegisterCount = static_cast<int>(arraysize(kParamRegisters)); 273#else 274 const v8::internal::Register* kParamRegisters = nullptr; 275 const int kParamRegisterCount = 0; 276#endif 277 278#ifdef FP_PARAM_REGISTERS 279 const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS}; 280 const size_t kFPParamRegisterCount = arraysize(kFPParamRegisters); 281#else 282 const DoubleRegister* kFPParamRegisters = nullptr; 283 const size_t kFPParamRegisterCount = 0; 284#endif 285 286 // Add register and/or stack parameter(s). 287 BuildParameterLocations(msig, kFPParamRegisterCount, kParamRegisterCount, 288 kFPParamRegisters, kParamRegisters, &locations); 289 290 const RegList kCalleeSaveRegisters = {CALLEE_SAVE_REGISTERS}; 291 const DoubleRegList kCalleeSaveFPRegisters = {CALLEE_SAVE_FP_REGISTERS}; 292 293 // The target for C calls is always an address (i.e. machine pointer). 294 MachineType target_type = MachineType::Pointer(); 295 LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type); 296 flags |= CallDescriptor::kNoAllocate; 297 298 return zone->New<CallDescriptor>( // -- 299 CallDescriptor::kCallAddress, // kind 300 target_type, // target MachineType 301 target_loc, // target location 302 locations.Build(), // location_sig 303 0, // stack_parameter_count 304 Operator::kNoThrow, // properties 305 kCalleeSaveRegisters, // callee-saved registers 306 kCalleeSaveFPRegisters, // callee-saved fp regs 307 flags, "c-call"); 308} 309 310} // namespace compiler 311} // namespace internal 312} // namespace v8 313