• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
11 namespace v8 {
12 namespace internal {
13 namespace compiler {
14 
15 namespace {
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.
BuildParameterLocations(const MachineSignature * msig,size_t kFPParamRegisterCount,size_t kParamRegisterCount,const DoubleRegister * kFPParamRegisters,const v8::internal::Register * kParamRegisters,LocationSignature::Builder * out_locations)144 void 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.
BuildParameterLocations(const MachineSignature * msig,size_t kFPParamRegisterCount,size_t kParamRegisterCount,const DoubleRegister * kFPParamRegisters,const v8::internal::Register * kParamRegisters,LocationSignature::Builder * out_locations)181 void 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.
GetSimplifiedCDescriptor(Zone * zone,const MachineSignature * msig,CallDescriptor::Flags flags)219 CallDescriptor* 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