Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ABI stuff for -preview=in #3578

Merged
merged 1 commit into from
Jan 8, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions dmd/target.d
Original file line number Diff line number Diff line change
@@ -661,6 +661,8 @@ version (IN_LLVM)
TypeTuple toArgTypes(Type t);
bool isReturnOnStack(TypeFunction tf, bool needsThis);
// unused: ulong parameterSize(const ref Loc loc, Type t);
bool preferPassByRef(Type t);
Expression getTargetInfo(const(char)* name, const ref Loc loc);
}
else // !IN_LLVM
{
@@ -879,7 +881,6 @@ else // !IN_LLVM
const sz = t.size(loc);
return params.is64bit ? (sz + 7) & ~7 : (sz + 3) & ~3;
}
} // !IN_LLVM

/**
* Decides whether an `in` parameter of the specified POD type is to be
@@ -939,12 +940,6 @@ else // !IN_LLVM
}
}

version (IN_LLVM)
{
extern (C++) Expression getTargetInfo(const(char)* name, const ref Loc loc);
}
else
{
// this guarantees `getTargetInfo` and `allTargetInfos` remain in sync
private enum TargetInfoKeys
{
13 changes: 13 additions & 0 deletions gen/abi-aarch64.cpp
Original file line number Diff line number Diff line change
@@ -70,6 +70,19 @@ struct AArch64TargetABI : TargetABI {
return false;
}

// Prefer a ref if the POD cannot be passed in registers, i.e., if
// IndirectByvalRewrite would be applied.
bool preferPassByRef(Type *t) override {
t = t->toBasetype();

if (!(t->ty == Tstruct || t->ty == Tsarray))
return false;

auto argTypes = getArgTypes(t);
return argTypes // not 0-sized
&& argTypes->arguments->empty(); // cannot be passed in registers
}

bool passByVal(TypeFunction *, Type *) override { return false; }

void rewriteFunctionType(IrFuncTy &fty) override {
16 changes: 14 additions & 2 deletions gen/abi-win64.cpp
Original file line number Diff line number Diff line change
@@ -44,14 +44,19 @@ struct Win64TargetABI : TargetABI {

bool passPointerToHiddenCopy(Type *t, bool isReturnValue,
TypeFunction *tf) const {
return passPointerToHiddenCopy(t, isReturnValue, tf->linkage, tf);
}

bool passPointerToHiddenCopy(Type *t, bool isReturnValue, LINK linkage,
TypeFunction *tf = nullptr) const {
// 80-bit real/ireal:
// * returned on the x87 stack (for DMD inline asm compliance and what LLVM
// defaults to)
// * passed by ref to hidden copy
if (isX87(t))
return !isReturnValue;

const bool isMSVCpp = isMSVC && tf->linkage == LINK::cpp;
const bool isMSVCpp = isMSVC && linkage == LINK::cpp;

// Handle non-PODs:
if (isReturnValue) {
@@ -77,7 +82,8 @@ struct Win64TargetABI : TargetABI {
}

// __vectorcall: Homogeneous Vector Aggregates are passed in registers
if (isExternD(tf) && isHVA(t, hfvaToArray.maxElements))
const bool isD = tf ? isExternD(tf) : linkage == LINK::d;
if (isD && isHVA(t, hfvaToArray.maxElements))
return false;

// Remaining aggregates which can NOT be rewritten as integers (size > 8
@@ -136,6 +142,12 @@ struct Win64TargetABI : TargetABI {
return passPointerToHiddenCopy(rt, /*isReturnValue=*/true, tf);
}

// Prefer a ref if the POD cannot be passed in a register, i.e., if
// IndirectByvalRewrite would be applied.
bool preferPassByRef(Type *t) override {
return passPointerToHiddenCopy(t->toBasetype(), false, LINK::d);
}

bool passByVal(TypeFunction *, Type *) override {
// LLVM's byval attribute is not compatible with the Win64 ABI
return false;
8 changes: 8 additions & 0 deletions gen/abi-x86-64.cpp
Original file line number Diff line number Diff line change
@@ -148,6 +148,8 @@ struct X86_64TargetABI : TargetABI {

bool returnInArg(TypeFunction *tf, bool needsThis) override;

bool preferPassByRef(Type *t) override;

bool passByVal(TypeFunction *tf, Type *t) override;

void rewriteFunctionType(IrFuncTy &fty) override;
@@ -190,6 +192,12 @@ bool X86_64TargetABI::returnInArg(TypeFunction *tf, bool) {
return passInMemory(rt);
}

// Prefer a ref if the POD cannot be passed in registers, i.e., if the LLVM
// ByVal attribute would be applied, *and* the size is > 16.
bool X86_64TargetABI::preferPassByRef(Type *t) {
return t->size() > 16 && passInMemory(t->toBasetype());
}

bool X86_64TargetABI::passByVal(TypeFunction *tf, Type *t) {
// indirectly by-value for non-POD args
if (!isPOD(t))
8 changes: 8 additions & 0 deletions gen/abi.cpp
Original file line number Diff line number Diff line change
@@ -156,6 +156,14 @@ bool TargetABI::isExternD(TypeFunction *tf) {

//////////////////////////////////////////////////////////////////////////////

bool TargetABI::preferPassByRef(Type *t) {
// simple base heuristic: use a ref for all types > 2 machine words
d_uns64 machineWordSize = global.params.is64bit ? 8 : 4;
return t->size() > 2 * machineWordSize;
}

//////////////////////////////////////////////////////////////////////////////

bool TargetABI::reverseExplicitParams(TypeFunction *tf) {
// Required by druntime for extern(D), except for `, ...`-style variadics.
return isExternD(tf) && tf->parameterList.length() > 1;
4 changes: 4 additions & 0 deletions gen/abi.h
Original file line number Diff line number Diff line change
@@ -124,6 +124,10 @@ struct TargetABI {
/// attribute.
virtual bool returnInArg(TypeFunction *tf, bool needsThis) = 0;

/// Returns true if the specified parameter type (a POD) should be passed by
/// ref for `in` params with -preview=in.
virtual bool preferPassByRef(Type *t);

/// Returns true if the D type is passed using the LLVM ByVal attribute.
///
/// ByVal arguments are bitcopied to the callee's function parameters stack in
2 changes: 2 additions & 0 deletions gen/target.cpp
Original file line number Diff line number Diff line change
@@ -216,6 +216,8 @@ bool Target::isReturnOnStack(TypeFunction *tf, bool needsThis) {
return gABI->returnInArg(tf, needsThis);
}

bool Target::preferPassByRef(Type *t) { return gABI->preferPassByRef(t); }

Expression *Target::getTargetInfo(const char *name_, const Loc &loc) {
const llvm::StringRef name(name_);
const auto &triple = *global.params.targetTriple;