c-linkage.cc 15.5 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#include "src/codegen/assembler-inl.h"
#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 12 13 14 15 16

namespace v8 {
namespace internal {
namespace compiler {

namespace {

17
// Platform-specific configuration for C calling convention.
18 19 20 21 22 23 24 25 26 27 28
#if V8_TARGET_ARCH_IA32
// ===========================================================================
// == ia32 ===================================================================
// ===========================================================================
#define CALLEE_SAVE_REGISTERS esi.bit() | edi.bit() | ebx.bit()

#elif V8_TARGET_ARCH_X64
// ===========================================================================
// == x64 ====================================================================
// ===========================================================================

29
#ifdef V8_TARGET_OS_WIN
30 31 32
// == x64 windows ============================================================
#define STACK_SHADOW_WORDS 4
#define PARAM_REGISTERS rcx, rdx, r8, r9
33
#define FP_PARAM_REGISTERS xmm0, xmm1, xmm2, xmm3
34
#define FP_RETURN_REGISTER xmm0
35 36 37 38 39 40 41 42
#define CALLEE_SAVE_REGISTERS                                             \
  rbx.bit() | rdi.bit() | rsi.bit() | r12.bit() | r13.bit() | r14.bit() | \
      r15.bit()
#define CALLEE_SAVE_FP_REGISTERS                                        \
  (1 << xmm6.code()) | (1 << xmm7.code()) | (1 << xmm8.code()) |        \
      (1 << xmm9.code()) | (1 << xmm10.code()) | (1 << xmm11.code()) |  \
      (1 << xmm12.code()) | (1 << xmm13.code()) | (1 << xmm14.code()) | \
      (1 << xmm15.code())
43
#else  // V8_TARGET_OS_WIN
44 45
// == x64 other ==============================================================
#define PARAM_REGISTERS rdi, rsi, rdx, rcx, r8, r9
46
#define FP_PARAM_REGISTERS xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
47
#define FP_RETURN_REGISTER xmm0
48 49
#define CALLEE_SAVE_REGISTERS \
  rbx.bit() | r12.bit() | r13.bit() | r14.bit() | r15.bit()
50
#endif  // V8_TARGET_OS_WIN
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

#elif V8_TARGET_ARCH_ARM
// ===========================================================================
// == arm ====================================================================
// ===========================================================================
#define PARAM_REGISTERS r0, r1, r2, r3
#define CALLEE_SAVE_REGISTERS \
  r4.bit() | r5.bit() | r6.bit() | r7.bit() | r8.bit() | r9.bit() | r10.bit()
#define CALLEE_SAVE_FP_REGISTERS                                  \
  (1 << d8.code()) | (1 << d9.code()) | (1 << d10.code()) |       \
      (1 << d11.code()) | (1 << d12.code()) | (1 << d13.code()) | \
      (1 << d14.code()) | (1 << d15.code())

#elif V8_TARGET_ARCH_ARM64
// ===========================================================================
// == arm64 ====================================================================
// ===========================================================================
#define PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7
69 70
#define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7
#define FP_RETURN_REGISTER d0
71 72 73 74
#define CALLEE_SAVE_REGISTERS                                     \
  (1 << x19.code()) | (1 << x20.code()) | (1 << x21.code()) |     \
      (1 << x22.code()) | (1 << x23.code()) | (1 << x24.code()) | \
      (1 << x25.code()) | (1 << x26.code()) | (1 << x27.code()) | \
75
      (1 << x28.code())
76 77 78 79 80 81 82 83 84 85

#define CALLEE_SAVE_FP_REGISTERS                                  \
  (1 << d8.code()) | (1 << d9.code()) | (1 << d10.code()) |       \
      (1 << d11.code()) | (1 << d12.code()) | (1 << d13.code()) | \
      (1 << d14.code()) | (1 << d15.code())

#elif V8_TARGET_ARCH_MIPS
// ===========================================================================
// == mips ===================================================================
// ===========================================================================
akos.palfi's avatar
akos.palfi committed
86
#define STACK_SHADOW_WORDS 4
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
#define PARAM_REGISTERS a0, a1, a2, a3
#define CALLEE_SAVE_REGISTERS                                                  \
  s0.bit() | s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() | s6.bit() | \
      s7.bit()
#define CALLEE_SAVE_FP_REGISTERS \
  f20.bit() | f22.bit() | f24.bit() | f26.bit() | f28.bit() | f30.bit()

#elif V8_TARGET_ARCH_MIPS64
// ===========================================================================
// == mips64 =================================================================
// ===========================================================================
#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
#define CALLEE_SAVE_REGISTERS                                                  \
  s0.bit() | s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() | s6.bit() | \
      s7.bit()
#define CALLEE_SAVE_FP_REGISTERS \
  f20.bit() | f22.bit() | f24.bit() | f26.bit() | f28.bit() | f30.bit()

105 106 107 108 109 110 111 112 113 114 115 116
#elif V8_TARGET_ARCH_LOONG64
// ===========================================================================
// == loong64 ================================================================
// ===========================================================================
#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
#define CALLEE_SAVE_REGISTERS                                                  \
  s0.bit() | s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() | s6.bit() | \
      s7.bit() | s8.bit() | fp.bit()
#define CALLEE_SAVE_FP_REGISTERS                                          \
  f24.bit() | f25.bit() | f26.bit() | f27.bit() | f28.bit() | f29.bit() | \
      f30.bit() | f31.bit()

117
#elif V8_TARGET_ARCH_PPC64
118 119 120
// ===========================================================================
// == ppc & ppc64 ============================================================
// ===========================================================================
121 122 123 124 125
#ifdef V8_TARGET_LITTLE_ENDIAN  // ppc64le linux
#define STACK_SHADOW_WORDS 12
#else  // AIX
#define STACK_SHADOW_WORDS 14
#endif
126 127 128 129
#define PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10
#define CALLEE_SAVE_REGISTERS                                                 \
  r14.bit() | r15.bit() | r16.bit() | r17.bit() | r18.bit() | r19.bit() |     \
      r20.bit() | r21.bit() | r22.bit() | r23.bit() | r24.bit() | r25.bit() | \
130 131 132 133 134
      r26.bit() | r27.bit() | r28.bit() | r29.bit() | r30.bit()
#define CALLEE_SAVE_FP_REGISTERS                                              \
  d14.bit() | d15.bit() | d16.bit() | d17.bit() | d18.bit() | d19.bit() |     \
      d20.bit() | d21.bit() | d22.bit() | d23.bit() | d24.bit() | d25.bit() | \
      d26.bit() | d27.bit() | d28.bit() | d29.bit() | d30.bit() | d31.bit()
135

136 137 138 139
#elif V8_TARGET_ARCH_S390X
// ===========================================================================
// == s390x ==================================================================
// ===========================================================================
140
#define STACK_SHADOW_WORDS 20
141 142 143 144 145 146 147
#define PARAM_REGISTERS r2, r3, r4, r5, r6
#define CALLEE_SAVE_REGISTERS \
  r6.bit() | r7.bit() | r8.bit() | r9.bit() | r10.bit() | ip.bit() | r13.bit()
#define CALLEE_SAVE_FP_REGISTERS                                        \
  d8.bit() | d9.bit() | d10.bit() | d11.bit() | d12.bit() | d13.bit() | \
      d14.bit() | d15.bit()

Brice Dobry's avatar
Brice Dobry committed
148 149 150 151 152 153 154 155 156 157 158 159 160
#elif V8_TARGET_ARCH_RISCV64
// ===========================================================================
// == riscv64 =================================================================
// ===========================================================================
#define PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7
// fp is not part of CALLEE_SAVE_REGISTERS (similar to how MIPS64 or PPC defines
// it)
#define CALLEE_SAVE_REGISTERS                                                  \
  s1.bit() | s2.bit() | s3.bit() | s4.bit() | s5.bit() | s6.bit() | s7.bit() | \
      s8.bit() | s9.bit() | s10.bit() | s11.bit()
#define CALLEE_SAVE_FP_REGISTERS                                          \
  fs0.bit() | fs1.bit() | fs2.bit() | fs3.bit() | fs4.bit() | fs5.bit() | \
      fs6.bit() | fs7.bit() | fs8.bit() | fs9.bit() | fs10.bit() | fs11.bit()
161 162 163 164
#else
// ===========================================================================
// == unknown ================================================================
// ===========================================================================
165
#define UNSUPPORTED_C_LINKAGE 1
166 167 168
#endif
}  // namespace

169
#if defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64)
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
// As defined in
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019#parameter-passing,
// Windows calling convention doesn't differentiate between GP and FP params
// when counting how many of them should be placed in registers. That's why
// we use the same counter {i} for both types here.
void BuildParameterLocations(const MachineSignature* msig,
                             size_t kFPParamRegisterCount,
                             size_t kParamRegisterCount,
                             const DoubleRegister* kFPParamRegisters,
                             const v8::internal::Register* kParamRegisters,
                             LocationSignature::Builder* out_locations) {
#ifdef STACK_SHADOW_WORDS
  int stack_offset = STACK_SHADOW_WORDS;
#else
  int stack_offset = 0;
#endif
  CHECK_EQ(kFPParamRegisterCount, kParamRegisterCount);

  for (size_t i = 0; i < msig->parameter_count(); i++) {
    MachineType type = msig->GetParam(i);
    bool spill = (i >= kParamRegisterCount);
    if (spill) {
      out_locations->AddParam(
          LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type));
      stack_offset++;
    } else {
      if (IsFloatingPoint(type.representation())) {
        out_locations->AddParam(
            LinkageLocation::ForRegister(kFPParamRegisters[i].code(), type));
      } else {
        out_locations->AddParam(
            LinkageLocation::ForRegister(kParamRegisters[i].code(), type));
      }
    }
  }
}
206
#else  // defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64)
207 208 209
// As defined in https://www.agner.org/optimize/calling_conventions.pdf,
// Section 7, Linux and Mac place parameters in consecutive registers,
// differentiating between GP and FP params. That's why we maintain two
210 211
// separate counters here. This also applies to Arm systems following
// the AAPCS and Windows on Arm.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
void BuildParameterLocations(const MachineSignature* msig,
                             size_t kFPParamRegisterCount,
                             size_t kParamRegisterCount,
                             const DoubleRegister* kFPParamRegisters,
                             const v8::internal::Register* kParamRegisters,
                             LocationSignature::Builder* out_locations) {
#ifdef STACK_SHADOW_WORDS
  int stack_offset = STACK_SHADOW_WORDS;
#else
  int stack_offset = 0;
#endif
  size_t num_params = 0;
  size_t num_fp_params = 0;
  for (size_t i = 0; i < msig->parameter_count(); i++) {
    MachineType type = msig->GetParam(i);
    bool spill = IsFloatingPoint(type.representation())
                     ? (num_fp_params >= kFPParamRegisterCount)
                     : (num_params >= kParamRegisterCount);
    if (spill) {
      out_locations->AddParam(
          LinkageLocation::ForCallerFrameSlot(-1 - stack_offset, type));
      stack_offset++;
    } else {
      if (IsFloatingPoint(type.representation())) {
        out_locations->AddParam(LinkageLocation::ForRegister(
            kFPParamRegisters[num_fp_params].code(), type));
        ++num_fp_params;
      } else {
        out_locations->AddParam(LinkageLocation::ForRegister(
            kParamRegisters[num_params].code(), type));
        ++num_params;
      }
    }
  }
}
247
#endif  // defined(V8_TARGET_OS_WIN) && defined(V8_TARGET_ARCH_X64)
248 249

// General code uses the above configuration data.
250 251 252
CallDescriptor* Linkage::GetSimplifiedCDescriptor(Zone* zone,
                                                  const MachineSignature* msig,
                                                  CallDescriptor::Flags flags) {
253 254 255 256 257 258
#ifdef UNSUPPORTED_C_LINKAGE
  // This method should not be called on unknown architectures.
  FATAL("requested C call descriptor on unsupported architecture");
  return nullptr;
#endif

259 260
  DCHECK_LE(msig->parameter_count(), static_cast<size_t>(kMaxCParameters));

261 262
  LocationSignature::Builder locations(zone, msig->return_count(),
                                       msig->parameter_count());
263 264

#ifndef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
265 266
  // Check the types of the signature.
  for (size_t i = 0; i < msig->parameter_count(); i++) {
267 268
    MachineType type = msig->GetParam(i);
    CHECK(!IsFloatingPoint(type.representation()));
269
  }
270

271
  // Check the return types.
272 273 274 275
  for (size_t i = 0; i < locations.return_count_; i++) {
    MachineType type = msig->GetReturn(i);
    CHECK(!IsFloatingPoint(type.representation()));
  }
276
#endif
277

278
  CHECK_GE(2, locations.return_count_);
279
  if (locations.return_count_ > 0) {
280 281 282 283 284 285 286 287
#ifdef FP_RETURN_REGISTER
    const v8::internal::DoubleRegister kFPReturnRegister = FP_RETURN_REGISTER;
    auto reg = IsFloatingPoint(msig->GetReturn(0).representation())
                   ? kFPReturnRegister.code()
                   : kReturnRegister0.code();
#else
    auto reg = kReturnRegister0.code();
#endif
288 289 290
    // TODO(chromium:1052746): Use the correctly sized register here (e.g. "al"
    // if the return type is kBit), so we don't have to use a hacky bitwise AND
    // elsewhere.
291
    locations.AddReturn(LinkageLocation::ForRegister(reg, msig->GetReturn(0)));
292
  }
293

294
  if (locations.return_count_ > 1) {
295 296
    DCHECK(!IsFloatingPoint(msig->GetReturn(0).representation()));

297 298
    locations.AddReturn(LinkageLocation::ForRegister(kReturnRegister1.code(),
                                                     msig->GetReturn(1)));
299 300 301
  }

#ifdef PARAM_REGISTERS
302
  const v8::internal::Register kParamRegisters[] = {PARAM_REGISTERS};
303
  const int kParamRegisterCount = static_cast<int>(arraysize(kParamRegisters));
304
#else
305
  const v8::internal::Register* kParamRegisters = nullptr;
306
  const int kParamRegisterCount = 0;
307 308
#endif

309 310 311
#ifdef FP_PARAM_REGISTERS
  const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS};
  const size_t kFPParamRegisterCount = arraysize(kFPParamRegisters);
312
#else
313 314
  const DoubleRegister* kFPParamRegisters = nullptr;
  const size_t kFPParamRegisterCount = 0;
315
#endif
316

317
  // Add register and/or stack parameter(s).
318 319
  BuildParameterLocations(msig, kFPParamRegisterCount, kParamRegisterCount,
                          kFPParamRegisters, kParamRegisters, &locations);
320 321 322 323 324 325 326 327 328 329 330 331 332 333

#ifdef CALLEE_SAVE_REGISTERS
  const RegList kCalleeSaveRegisters = CALLEE_SAVE_REGISTERS;
#else
  const RegList kCalleeSaveRegisters = 0;
#endif

#ifdef CALLEE_SAVE_FP_REGISTERS
  const RegList kCalleeSaveFPRegisters = CALLEE_SAVE_FP_REGISTERS;
#else
  const RegList kCalleeSaveFPRegisters = 0;
#endif

  // The target for C calls is always an address (i.e. machine pointer).
334
  MachineType target_type = MachineType::Pointer();
335
  LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
336
  flags |= CallDescriptor::kNoAllocate;
337

338
  return zone->New<CallDescriptor>(  // --
339 340 341 342
      CallDescriptor::kCallAddress,  // kind
      target_type,                   // target MachineType
      target_loc,                    // target location
      locations.Build(),             // location_sig
343
      0,                             // stack_parameter_count
344
      Operator::kNoThrow,            // properties
345 346
      kCalleeSaveRegisters,          // callee-saved registers
      kCalleeSaveFPRegisters,        // callee-saved fp regs
347
      flags, "c-call");
348
}
349 350 351 352

}  // namespace compiler
}  // namespace internal
}  // namespace v8