629db0a6cd
This will make accidental includes much easier to see and fix. Without this, you might get compiler or linker errors instead. R=jkummerow@chromium.org Bug: v8:11238 Cq-Include-Trybots: luci.v8.try:v8_linux64_no_wasm_compile_rel Change-Id: I235d779f9c1ed3af5d736f1554ded427935ddc9b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2756531 Commit-Queue: Clemens Backes <clemensb@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#73422}
258 lines
11 KiB
C++
258 lines
11 KiB
C++
// Copyright 2018 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.
|
|
|
|
#if !V8_ENABLE_WEBASSEMBLY
|
|
#error This header should only be included if WebAssembly is enabled.
|
|
#endif // !V8_ENABLE_WEBASSEMBLY
|
|
|
|
#ifndef V8_WASM_WASM_LINKAGE_H_
|
|
#define V8_WASM_WASM_LINKAGE_H_
|
|
|
|
#include "src/codegen/aligned-slot-allocator.h"
|
|
#include "src/codegen/assembler-arch.h"
|
|
#include "src/codegen/machine-type.h"
|
|
#include "src/codegen/signature.h"
|
|
#include "src/wasm/value-type.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace wasm {
|
|
|
|
// TODO(wasm): optimize calling conventions to be both closer to C++ (to
|
|
// reduce adapter costs for fast Wasm <-> C++ calls) and to be more efficient
|
|
// in general.
|
|
|
|
#if V8_TARGET_ARCH_IA32
|
|
// ===========================================================================
|
|
// == ia32 ===================================================================
|
|
// ===========================================================================
|
|
constexpr Register kGpParamRegisters[] = {esi, eax, edx, ecx};
|
|
constexpr Register kGpReturnRegisters[] = {eax, edx};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3,
|
|
xmm4, xmm5, xmm6};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2};
|
|
|
|
#elif V8_TARGET_ARCH_X64
|
|
// ===========================================================================
|
|
// == x64 ====================================================================
|
|
// ===========================================================================
|
|
constexpr Register kGpParamRegisters[] = {rsi, rax, rdx, rcx, rbx, r9};
|
|
constexpr Register kGpReturnRegisters[] = {rax, rdx};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {xmm1, xmm2, xmm3,
|
|
xmm4, xmm5, xmm6};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {xmm1, xmm2};
|
|
|
|
#elif V8_TARGET_ARCH_ARM
|
|
// ===========================================================================
|
|
// == arm ====================================================================
|
|
// ===========================================================================
|
|
constexpr Register kGpParamRegisters[] = {r3, r0, r2, r6};
|
|
constexpr Register kGpReturnRegisters[] = {r0, r1};
|
|
// ARM d-registers must be in even/odd D-register pairs for correct allocation.
|
|
constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1};
|
|
|
|
#elif V8_TARGET_ARCH_ARM64
|
|
// ===========================================================================
|
|
// == arm64 ====================================================================
|
|
// ===========================================================================
|
|
constexpr Register kGpParamRegisters[] = {x7, x0, x2, x3, x4, x5, x6};
|
|
constexpr Register kGpReturnRegisters[] = {x0, x1};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {d0, d1, d2, d3, d4, d5, d6, d7};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {d0, d1};
|
|
|
|
#elif V8_TARGET_ARCH_MIPS
|
|
// ===========================================================================
|
|
// == mips ===================================================================
|
|
// ===========================================================================
|
|
constexpr Register kGpParamRegisters[] = {a0, a2, a3};
|
|
constexpr Register kGpReturnRegisters[] = {v0, v1};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {f2, f4, f6, f8, f10, f12, f14};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {f2, f4};
|
|
|
|
#elif V8_TARGET_ARCH_MIPS64
|
|
// ===========================================================================
|
|
// == mips64 =================================================================
|
|
// ===========================================================================
|
|
constexpr Register kGpParamRegisters[] = {a0, a2, a3, a4, a5, a6, a7};
|
|
constexpr Register kGpReturnRegisters[] = {v0, v1};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {f2, f4, f6, f8, f10, f12, f14};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {f2, f4};
|
|
|
|
#elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64
|
|
// ===========================================================================
|
|
// == ppc & ppc64 ============================================================
|
|
// ===========================================================================
|
|
constexpr Register kGpParamRegisters[] = {r10, r3, r5, r6, r7, r8, r9};
|
|
constexpr Register kGpReturnRegisters[] = {r3, r4};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {d1, d2, d3, d4, d5, d6, d7, d8};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {d1, d2};
|
|
|
|
#elif V8_TARGET_ARCH_S390X
|
|
// ===========================================================================
|
|
// == s390x ==================================================================
|
|
// ===========================================================================
|
|
constexpr Register kGpParamRegisters[] = {r6, r2, r4, r5};
|
|
constexpr Register kGpReturnRegisters[] = {r2, r3};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {d0, d2, d4, d6};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2, d4, d6};
|
|
|
|
#elif V8_TARGET_ARCH_S390
|
|
// ===========================================================================
|
|
// == s390 ===================================================================
|
|
// ===========================================================================
|
|
constexpr Register kGpParamRegisters[] = {r6, r2, r4, r5};
|
|
constexpr Register kGpReturnRegisters[] = {r2, r3};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {d0, d2};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {d0, d2};
|
|
|
|
#elif V8_TARGET_ARCH_RISCV64
|
|
// ===========================================================================
|
|
// == riscv64 =================================================================
|
|
// ===========================================================================
|
|
// Note that kGpParamRegisters and kFpParamRegisters are used in
|
|
// Builtins::Generate_WasmCompileLazy (builtins-riscv64.cc)
|
|
constexpr Register kGpParamRegisters[] = {a0, a2, a3, a4, a5, a6};
|
|
constexpr Register kGpReturnRegisters[] = {a0, a1};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {fa0, fa1, fa2, fa3,
|
|
fa4, fa5, fa6};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {fa0, fa1};
|
|
|
|
#else
|
|
// ===========================================================================
|
|
// == unknown ================================================================
|
|
// ===========================================================================
|
|
// Do not use any registers, we will just always use the stack.
|
|
constexpr Register kGpParamRegisters[] = {};
|
|
constexpr Register kGpReturnRegisters[] = {};
|
|
constexpr DoubleRegister kFpParamRegisters[] = {};
|
|
constexpr DoubleRegister kFpReturnRegisters[] = {};
|
|
|
|
#endif
|
|
|
|
// The parameter index where the instance parameter should be placed in wasm
|
|
// call descriptors. This is used by the Int64Lowering::LowerNode method.
|
|
constexpr int kWasmInstanceParameterIndex = 0;
|
|
|
|
class LinkageAllocator {
|
|
public:
|
|
template <size_t kNumGpRegs, size_t kNumFpRegs>
|
|
constexpr LinkageAllocator(const Register (&gp)[kNumGpRegs],
|
|
const DoubleRegister (&fp)[kNumFpRegs])
|
|
: LinkageAllocator(gp, kNumGpRegs, fp, kNumFpRegs) {}
|
|
|
|
constexpr LinkageAllocator(const Register* gp, int gpc,
|
|
const DoubleRegister* fp, int fpc)
|
|
: gp_count_(gpc), gp_regs_(gp), fp_count_(fpc), fp_regs_(fp) {}
|
|
|
|
bool CanAllocateGP() const { return gp_offset_ < gp_count_; }
|
|
bool CanAllocateFP(MachineRepresentation rep) const {
|
|
#if V8_TARGET_ARCH_ARM
|
|
switch (rep) {
|
|
case MachineRepresentation::kFloat32: {
|
|
// Get the next D-register (Liftoff only uses the even S-registers).
|
|
int next = fp_allocator_.NextSlot(2) / 2;
|
|
// Only the lower 16 D-registers alias S-registers.
|
|
return next < fp_count_ && fp_regs_[next].code() < 16;
|
|
}
|
|
case MachineRepresentation::kFloat64: {
|
|
int next = fp_allocator_.NextSlot(2) / 2;
|
|
return next < fp_count_;
|
|
}
|
|
case MachineRepresentation::kSimd128: {
|
|
int next = fp_allocator_.NextSlot(4) / 2;
|
|
return next < fp_count_ - 1; // 2 D-registers are required.
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
return false;
|
|
}
|
|
#else
|
|
return fp_offset_ < fp_count_;
|
|
#endif
|
|
}
|
|
|
|
int NextGpReg() {
|
|
DCHECK_LT(gp_offset_, gp_count_);
|
|
return gp_regs_[gp_offset_++].code();
|
|
}
|
|
|
|
int NextFpReg(MachineRepresentation rep) {
|
|
DCHECK(CanAllocateFP(rep));
|
|
#if V8_TARGET_ARCH_ARM
|
|
switch (rep) {
|
|
case MachineRepresentation::kFloat32: {
|
|
// Liftoff uses only even-numbered S-registers, and encodes them using
|
|
// the code of the corresponding D-register. This limits the calling
|
|
// interface to only using the even-numbered S-registers.
|
|
int d_reg_code = NextFpReg(MachineRepresentation::kFloat64);
|
|
DCHECK_GT(16, d_reg_code); // D16 - D31 don't alias S-registers.
|
|
return d_reg_code * 2;
|
|
}
|
|
case MachineRepresentation::kFloat64: {
|
|
int next = fp_allocator_.Allocate(2) / 2;
|
|
return fp_regs_[next].code();
|
|
}
|
|
case MachineRepresentation::kSimd128: {
|
|
int next = fp_allocator_.Allocate(4) / 2;
|
|
int d_reg_code = fp_regs_[next].code();
|
|
// Check that result and the next D-register pair.
|
|
DCHECK_EQ(0, d_reg_code % 2);
|
|
DCHECK_EQ(d_reg_code + 1, fp_regs_[next + 1].code());
|
|
return d_reg_code / 2;
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
#else
|
|
return fp_regs_[fp_offset_++].code();
|
|
#endif
|
|
}
|
|
|
|
// Stackslots are counted upwards starting from 0 (or the offset set by
|
|
// {SetStackOffset}. If {type} needs more than one stack slot, the lowest
|
|
// used stack slot is returned.
|
|
int NextStackSlot(MachineRepresentation type) {
|
|
int num_slots =
|
|
AlignedSlotAllocator::NumSlotsForWidth(ElementSizeInBytes(type));
|
|
int slot = slot_allocator_.Allocate(num_slots);
|
|
return slot;
|
|
}
|
|
|
|
// Set an offset for the stack slots returned by {NextStackSlot} and
|
|
// {NumStackSlots}. Can only be called before any call to {NextStackSlot}.
|
|
void SetStackOffset(int offset) {
|
|
DCHECK_LE(0, offset);
|
|
DCHECK_EQ(0, slot_allocator_.Size());
|
|
slot_allocator_.AllocateUnaligned(offset);
|
|
}
|
|
|
|
int NumStackSlots() const { return slot_allocator_.Size(); }
|
|
|
|
void EndSlotArea() { slot_allocator_.AllocateUnaligned(0); }
|
|
|
|
private:
|
|
const int gp_count_;
|
|
int gp_offset_ = 0;
|
|
const Register* const gp_regs_;
|
|
|
|
const int fp_count_;
|
|
#if V8_TARGET_ARCH_ARM
|
|
// Use an aligned slot allocator to model ARM FP register aliasing. The slots
|
|
// are 32 bits, so 2 slots are required for a D-register, 4 for a Q-register.
|
|
AlignedSlotAllocator fp_allocator_;
|
|
#else
|
|
int fp_offset_ = 0;
|
|
#endif
|
|
const DoubleRegister* const fp_regs_;
|
|
|
|
AlignedSlotAllocator slot_allocator_;
|
|
};
|
|
|
|
} // namespace wasm
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#endif // V8_WASM_WASM_LINKAGE_H_
|