• 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.bit() | edi.bit() | ebx.bit()
23 
24 #elif V8_TARGET_ARCH_X64
25 // ===========================================================================
26 // == x64 ====================================================================
27 // ===========================================================================
28 
29 #ifdef V8_TARGET_OS_WIN
30 // == x64 windows ============================================================
31 #define STACK_SHADOW_WORDS 4
32 #define PARAM_REGISTERS rcx, rdx, r8, r9
33 #define FP_PARAM_REGISTERS xmm0, xmm1, xmm2, xmm3
34 #define CALLEE_SAVE_REGISTERS                                             \
35   rbx.bit() | rdi.bit() | rsi.bit() | r12.bit() | r13.bit() | r14.bit() | \
36       r15.bit()
37 #define CALLEE_SAVE_FP_REGISTERS                                        \
38   (1 << xmm6.code()) | (1 << xmm7.code()) | (1 << xmm8.code()) |        \
39       (1 << xmm9.code()) | (1 << xmm10.code()) | (1 << xmm11.code()) |  \
40       (1 << xmm12.code()) | (1 << xmm13.code()) | (1 << xmm14.code()) | \
41       (1 << xmm15.code())
42 #else  // V8_TARGET_OS_WIN
43 // == x64 other ==============================================================
44 #define PARAM_REGISTERS rdi, rsi, rdx, rcx, r8, r9
45 #define FP_PARAM_REGISTERS xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
46 #define CALLEE_SAVE_REGISTERS \
47   rbx.bit() | r12.bit() | r13.bit() | r14.bit() | r15.bit()
48 #endif  // V8_TARGET_OS_WIN
49 
50 #elif V8_TARGET_ARCH_ARM
51 // ===========================================================================
52 // == arm ====================================================================
53 // ===========================================================================
54 #define PARAM_REGISTERS r0, r1, r2, r3
55 #define CALLEE_SAVE_REGISTERS \
56   r4.bit() | r5.bit() | r6.bit() | r7.bit() | r8.bit() | r9.bit() | r10.bit()
57 #define CALLEE_SAVE_FP_REGISTERS                                  \
58   (1 << d8.code()) | (1 << d9.code()) | (1 << d10.code()) |       \
59       (1 << d11.code()) | (1 << d12.code()) | (1 << d13.code()) | \
60       (1 << d14.code()) | (1 << d15.code())
61 
62 
63 #elif V8_TARGET_ARCH_ARM64
64 // ===========================================================================
65 // == arm64 ====================================================================
66 // ===========================================================================
67 #define PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7
68 #define CALLEE_SAVE_REGISTERS                                     \
69   (1 << x19.code()) | (1 << x20.code()) | (1 << x21.code()) |     \
70       (1 << x22.code()) | (1 << x23.code()) | (1 << x24.code()) | \
71       (1 << x25.code()) | (1 << x26.code()) | (1 << x27.code()) | \
72       (1 << x28.code())
73 
74 #define CALLEE_SAVE_FP_REGISTERS                                  \
75   (1 << d8.code()) | (1 << d9.code()) | (1 << d10.code()) |       \
76       (1 << d11.code()) | (1 << d12.code()) | (1 << d13.code()) | \
77       (1 << d14.code()) | (1 << d15.code())
78 
79 #elif V8_TARGET_ARCH_MIPS
80 // ===========================================================================
81 // == mips ===================================================================
82 // ===========================================================================
83 #define STACK_SHADOW_WORDS 4
84 #define PARAM_REGISTERS a0, a1, a2, a3
85 #define CALLEE_SAVE_REGISTERS                                                  \
86   s0.bit() | s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() | s6.bit() | \
87       s7.bit()
88 #define CALLEE_SAVE_FP_REGISTERS \
89   f20.bit() | f22.bit() | f24.bit() | f26.bit() | f28.bit() | f30.bit()
90 
91 #elif V8_TARGET_ARCH_MIPS64
92 // ===========================================================================
93 // == mips64 =================================================================
94 // ===========================================================================
95 #define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
96 #define CALLEE_SAVE_REGISTERS                                                  \
97   s0.bit() | s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() | s6.bit() | \
98       s7.bit()
99 #define CALLEE_SAVE_FP_REGISTERS \
100   f20.bit() | f22.bit() | f24.bit() | f26.bit() | f28.bit() | f30.bit()
101 
102 #elif V8_TARGET_ARCH_PPC64
103 // ===========================================================================
104 // == ppc & ppc64 ============================================================
105 // ===========================================================================
106 #ifdef V8_TARGET_LITTLE_ENDIAN  // ppc64le linux
107 #define STACK_SHADOW_WORDS 12
108 #else  // AIX
109 #define STACK_SHADOW_WORDS 14
110 #endif
111 #define PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10
112 #define CALLEE_SAVE_REGISTERS                                                 \
113   r14.bit() | r15.bit() | r16.bit() | r17.bit() | r18.bit() | r19.bit() |     \
114       r20.bit() | r21.bit() | r22.bit() | r23.bit() | r24.bit() | r25.bit() | \
115       r26.bit() | r27.bit() | r28.bit() | r29.bit() | r30.bit()
116 #define CALLEE_SAVE_FP_REGISTERS                                              \
117   d14.bit() | d15.bit() | d16.bit() | d17.bit() | d18.bit() | d19.bit() |     \
118       d20.bit() | d21.bit() | d22.bit() | d23.bit() | d24.bit() | d25.bit() | \
119       d26.bit() | d27.bit() | d28.bit() | d29.bit() | d30.bit() | d31.bit()
120 
121 #elif V8_TARGET_ARCH_S390X
122 // ===========================================================================
123 // == s390x ==================================================================
124 // ===========================================================================
125 #define STACK_SHADOW_WORDS 20
126 #define PARAM_REGISTERS r2, r3, r4, r5, r6
127 #define CALLEE_SAVE_REGISTERS \
128   r6.bit() | r7.bit() | r8.bit() | r9.bit() | r10.bit() | ip.bit() | r13.bit()
129 #define CALLEE_SAVE_FP_REGISTERS                                        \
130   d8.bit() | d9.bit() | d10.bit() | d11.bit() | d12.bit() | d13.bit() | \
131       d14.bit() | d15.bit()
132 
133 #else
134 // ===========================================================================
135 // == unknown ================================================================
136 // ===========================================================================
137 #define UNSUPPORTED_C_LINKAGE 1
138 #endif
139 }  // namespace
140 
141 #if defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64)
142 // As defined in
143 // https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019#parameter-passing,
144 // Windows calling convention doesn't differentiate between GP and FP params
145 // when counting how many of them should be placed in registers. That's why
146 // 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)147 void BuildParameterLocations(const MachineSignature* msig,
148                              size_t kFPParamRegisterCount,
149                              size_t kParamRegisterCount,
150                              const DoubleRegister* kFPParamRegisters,
151                              const v8::internal::Register* kParamRegisters,
152                              LocationSignature::Builder* out_locations) {
153 #ifdef STACK_SHADOW_WORDS
154   int stack_offset = STACK_SHADOW_WORDS;
155 #else
156   int stack_offset = 0;
157 #endif
158   CHECK_EQ(kFPParamRegisterCount, kParamRegisterCount);
159 
160   for (size_t i = 0; i < msig->parameter_count(); i++) {
161     MachineType type = msig->GetParam(i);
162     bool spill = (i >= kParamRegisterCount);
163     if (spill) {
164       out_locations->AddParam(
165           LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type));
166       stack_offset++;
167     } else {
168       if (IsFloatingPoint(type.representation())) {
169         out_locations->AddParam(
170             LinkageLocation::ForRegister(kFPParamRegisters[i].code(), type));
171       } else {
172         out_locations->AddParam(
173             LinkageLocation::ForRegister(kParamRegisters[i].code(), type));
174       }
175     }
176   }
177 }
178 #else  // defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64)
179 // As defined in https://www.agner.org/optimize/calling_conventions.pdf,
180 // Section 7, Linux and Mac place parameters in consecutive registers,
181 // differentiating between GP and FP params. That's why we maintain two
182 // separate counters here. This also applies to Arm systems following
183 // 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)184 void BuildParameterLocations(const MachineSignature* msig,
185                              size_t kFPParamRegisterCount,
186                              size_t kParamRegisterCount,
187                              const DoubleRegister* kFPParamRegisters,
188                              const v8::internal::Register* kParamRegisters,
189                              LocationSignature::Builder* out_locations) {
190 #ifdef STACK_SHADOW_WORDS
191   int stack_offset = STACK_SHADOW_WORDS;
192 #else
193   int stack_offset = 0;
194 #endif
195   size_t num_params = 0;
196   size_t num_fp_params = 0;
197   for (size_t i = 0; i < msig->parameter_count(); i++) {
198     MachineType type = msig->GetParam(i);
199     bool spill = IsFloatingPoint(type.representation())
200                      ? (num_fp_params >= kFPParamRegisterCount)
201                      : (num_params >= kParamRegisterCount);
202     if (spill) {
203       out_locations->AddParam(
204           LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type));
205       stack_offset++;
206     } else {
207       if (IsFloatingPoint(type.representation())) {
208         out_locations->AddParam(LinkageLocation::ForRegister(
209             kFPParamRegisters[num_fp_params].code(), type));
210         ++num_fp_params;
211       } else {
212         out_locations->AddParam(LinkageLocation::ForRegister(
213             kParamRegisters[num_params].code(), type));
214         ++num_params;
215       }
216     }
217   }
218 }
219 #endif  // defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64)
220 
221 // General code uses the above configuration data.
GetSimplifiedCDescriptor(Zone * zone,const MachineSignature * msig,CallDescriptor::Flags flags)222 CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
223                                                   const MachineSignature* msig,
224                                                   CallDescriptor::Flags flags) {
225 #ifdef UNSUPPORTED_C_LINKAGE
226   // This method should not be called on unknown architectures.
227   FATAL("requested C call descriptor on unsupported architecture");
228   return nullptr;
229 #endif
230 
231   DCHECK_LE(msig->parameter_count(), static_cast<size_t>(kMaxCParameters));
232 
233   LocationSignature::Builder locations(zone, msig->return_count(),
234                                        msig->parameter_count());
235 
236 #ifndef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
237   // Check the types of the signature.
238   for (size_t i = 0; i < msig->parameter_count(); i++) {
239     MachineRepresentation rep = msig->GetParam(i).representation();
240     CHECK_NE(MachineRepresentation::kFloat32, rep);
241     CHECK_NE(MachineRepresentation::kFloat64, rep);
242   }
243 #endif
244 
245   // Add return location(s). We don't support FP returns for now.
246   for (size_t i = 0; i < locations.return_count_; i++) {
247     MachineType type = msig->GetReturn(i);
248     CHECK(!IsFloatingPoint(type.representation()));
249   }
250 
251   CHECK_GE(2, locations.return_count_);
252   if (locations.return_count_ > 0) {
253     locations.AddReturn(LinkageLocation::ForRegister(kReturnRegister0.code(),
254                                                      msig->GetReturn(0)));
255   }
256   if (locations.return_count_ > 1) {
257     locations.AddReturn(LinkageLocation::ForRegister(kReturnRegister1.code(),
258                                                      msig->GetReturn(1)));
259   }
260 
261 #ifdef PARAM_REGISTERS
262   const v8::internal::Register kParamRegisters[] = {PARAM_REGISTERS};
263   const int kParamRegisterCount = static_cast<int>(arraysize(kParamRegisters));
264 #else
265   const v8::internal::Register* kParamRegisters = nullptr;
266   const int kParamRegisterCount = 0;
267 #endif
268 
269 #ifdef FP_PARAM_REGISTERS
270   const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
271   const size_t kFPParamRegisterCount = arraysize(kFPParamRegisters);
272 #else
273   const DoubleRegister* kFPParamRegisters = nullptr;
274   const size_t kFPParamRegisterCount = 0;
275 #endif
276 
277   // Add register and/or stack parameter(s).
278   BuildParameterLocations(msig, kFPParamRegisterCount, kParamRegisterCount,
279                           kFPParamRegisters, kParamRegisters, &locations);
280 
281 #ifdef CALLEE_SAVE_REGISTERS
282   const RegList kCalleeSaveRegisters = CALLEE_SAVE_REGISTERS;
283 #else
284   const RegList kCalleeSaveRegisters = 0;
285 #endif
286 
287 #ifdef CALLEE_SAVE_FP_REGISTERS
288   const RegList kCalleeSaveFPRegisters = CALLEE_SAVE_FP_REGISTERS;
289 #else
290   const RegList kCalleeSaveFPRegisters = 0;
291 #endif
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