Skip to content

Commit

Permalink
Use IndirectByvalRewrite for non-POD args and extern(C++) on Posix (#…
Browse files Browse the repository at this point in the history
…2728)

Fixing one aspect of issue #2702; not tackling the different destruction
rules yet.
  • Loading branch information
kinke committed Jun 19, 2018
1 parent f8880c6 commit 3ca43c5
Show file tree
Hide file tree
Showing 15 changed files with 61 additions and 30 deletions.
4 changes: 2 additions & 2 deletions gen/abi-aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ struct AArch64TargetABI : TargetABI {
if (!isPOD(rt))
return true;

return passByVal(rt);
return passByVal(tf, rt);
}

bool passByVal(Type *t) override {
bool passByVal(TypeFunction *, Type *t) override {
t = t->toBasetype();
return t->ty == Tsarray ||
(t->ty == Tstruct && t->size() > 16 && !isHFA((TypeStruct *)t));
Expand Down
2 changes: 1 addition & 1 deletion gen/abi-arm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct ArmTargetABI : TargetABI {
!isHFA((TypeStruct *)rt)));
}

bool passByVal(Type *t) override {
bool passByVal(TypeFunction *, Type *t) override {
// AAPCS does not use an indirect arg to pass aggregates, however
// clang uses byval for types > 64-bytes, then llvm backend
// converts back to non-byval. Without this special handling the
Expand Down
2 changes: 1 addition & 1 deletion gen/abi-mips64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct MIPS64TargetABI : TargetABI {
return (rt->ty == Tstruct || rt->ty == Tsarray);
}

bool passByVal(Type *t) override {
bool passByVal(TypeFunction *, Type *t) override {
TY ty = t->toBasetype()->ty;
return ty == Tstruct || ty == Tsarray;
}
Expand Down
2 changes: 1 addition & 1 deletion gen/abi-nvptx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct NVPTXTargetABI : TargetABI {
else
return llvm::CallingConv::PTX_Device;
}
bool passByVal(Type *t) override {
bool passByVal(TypeFunction *, Type *t) override {
t = t->toBasetype();
return ((t->ty == Tsarray || t->ty == Tstruct) && t->size() > 64);
}
Expand Down
2 changes: 1 addition & 1 deletion gen/abi-ppc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct PPCTargetABI : TargetABI {
return rt->ty == Tsarray || rt->ty == Tstruct;
}

bool passByVal(Type *t) override {
bool passByVal(TypeFunction *, Type *t) override {
// On ppc, aggregates are always passed as an indirect value.
// On ppc64, they are always passed by value. However, clang
// used byval for type > 64 bytes.
Expand Down
4 changes: 2 additions & 2 deletions gen/abi-ppc64le.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ struct PPC64LETargetABI : TargetABI {
if (!isPOD(rt))
return true;

return passByVal(rt);
return passByVal(tf, rt);
}

bool passByVal(Type *t) override {
bool passByVal(TypeFunction *, Type *t) override {
t = t->toBasetype();
return t->ty == Tsarray || (t->ty == Tstruct && t->size() > 16 &&
!isHFA((TypeStruct *)t, nullptr, 8));
Expand Down
2 changes: 1 addition & 1 deletion gen/abi-spirv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct SPIRVTargetABI : TargetABI {
else
return llvm::CallingConv::SPIR_FUNC;
}
bool passByVal(Type *t) override {
bool passByVal(TypeFunction *, Type *t) override {
t = t->toBasetype();
return ((t->ty == Tsarray || t->ty == Tstruct) && t->size() > 64);
}
Expand Down
2 changes: 1 addition & 1 deletion gen/abi-win64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ struct Win64TargetABI : TargetABI {
return passPointerToHiddenCopy(rt, /*isReturnValue=*/true, tf->linkage);
}

bool passByVal(Type *t) override {
bool passByVal(TypeFunction *, Type *) override {
// LLVM's byval attribute is not compatible with the Win64 ABI
return false;
}
Expand Down
43 changes: 30 additions & 13 deletions gen/abi-x86-64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,15 +217,16 @@ struct ImplicitByvalRewrite : ABIRewrite {
struct X86_64TargetABI : TargetABI {
X86_64_C_struct_rewrite struct_rewrite;
ImplicitByvalRewrite byvalRewrite;
IndirectByvalRewrite indirectByvalRewrite;

bool returnInArg(TypeFunction *tf) override;

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

void rewriteFunctionType(IrFuncTy &fty) override;
void rewriteVarargs(IrFuncTy &fty, std::vector<IrFuncTyArg *> &args) override;
void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) override;
void rewriteArgument(IrFuncTyArg &arg, RegCount &regCount);
void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg, RegCount &regCount);

LLValue *prepareVaStart(DLValue *ap) override;

Expand All @@ -252,22 +253,37 @@ bool X86_64TargetABI::returnInArg(TypeFunction *tf) {
return false;
}

Type *rt = tf->next;
return passByVal(rt);
Type *rt = tf->next->toBasetype();
return dmd_abi::passByVal(rt);
}

bool X86_64TargetABI::passByVal(Type *t) {
bool X86_64TargetABI::passByVal(TypeFunction *tf, Type *t) {
// indirectly by-value for extern(C++) functions and non-POD args
if (tf->linkage == LINKcpp && !isPOD(t))
return false;

return dmd_abi::passByVal(t->toBasetype());
}

void X86_64TargetABI::rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) {
llvm_unreachable("Please use the other overload explicitly.");
}

void X86_64TargetABI::rewriteArgument(IrFuncTyArg &arg, RegCount &regCount) {
void X86_64TargetABI::rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg,
RegCount &regCount) {
LLType *originalLType = arg.ltype;
Type *t = arg.type->toBasetype();

// indirectly by-value for extern(C++) functions and non-POD args
if (fty.type->linkage == LINKcpp && !isPOD(t)) {
indirectByvalRewrite.applyTo(arg);
if (regCount.int_regs > 0) {
regCount.int_regs--;
}

return;
}

LLType *abiTy = getAbiType(t);
if (abiTy && !LLTypeMemoryLayout::typesAreEquivalent(abiTy, originalLType)) {
IF_LOG {
Expand All @@ -280,11 +296,12 @@ void X86_64TargetABI::rewriteArgument(IrFuncTyArg &arg, RegCount &regCount) {
}

if (regCount.trySubtract(arg) == RegCount::ArgumentWouldFitInPartially) {
// pass LL structs implicitly ByVal, otherwise LLVM passes
// them partially in registers, partially in memory
// pass the LL struct with byval attribute to prevent LLVM from passing it
// partially in registers, partially in memory
assert(originalLType->isStructTy());
IF_LOG Logger::cout() << "Passing implicitly ByVal: " << arg.type->toChars()
<< " (" << *originalLType << ")\n";
IF_LOG Logger::cout() << "Passing byval to prevent register/memory mix: "
<< arg.type->toChars() << " (" << *originalLType
<< ")\n";
byvalRewrite.applyTo(arg);
}
}
Expand All @@ -298,7 +315,7 @@ void X86_64TargetABI::rewriteFunctionType(IrFuncTy &fty) {
Logger::println("x86-64 ABI: Transforming return type");
LOG_SCOPE;
RegCount dummy;
rewriteArgument(*fty.ret, dummy);
rewriteArgument(fty, *fty.ret, dummy);
}

// IMPLICIT PARAMETERS
Expand Down Expand Up @@ -336,7 +353,7 @@ void X86_64TargetABI::rewriteFunctionType(IrFuncTy &fty) {
continue;
}

rewriteArgument(arg, regCount);
rewriteArgument(fty, arg, regCount);
}

// regCount (fty.tag) is now in the state after all implicit & formal args,
Expand All @@ -351,7 +368,7 @@ void X86_64TargetABI::rewriteVarargs(IrFuncTy &fty,

for (auto arg : args) {
if (!arg->byref) { // don't rewrite ByVal arguments
rewriteArgument(*arg, regCount);
rewriteArgument(fty, *arg, regCount);
}
}
}
Expand Down
14 changes: 13 additions & 1 deletion gen/abi-x86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct X86TargetABI : TargetABI {
const bool isMSVC;
bool returnStructsInRegs;
IntegerRewrite integerRewrite;
IndirectByvalRewrite indirectByvalRewrite;

X86TargetABI()
: isOSX(global.params.targetTriple->isMacOSX()),
Expand Down Expand Up @@ -118,7 +119,11 @@ struct X86TargetABI : TargetABI {
return !canRewriteAsInt(rt);
}

bool passByVal(Type *t) override {
bool passByVal(TypeFunction *tf, Type *t) override {
// indirectly by-value for extern(C++) functions and non-POD args on Posix
if (!isMSVC && tf->linkage == LINKcpp && !isPOD(t))
return false;

// pass all structs and static arrays with the LLVM byval attribute
return DtoIsInMemoryOnly(t);
}
Expand Down Expand Up @@ -182,6 +187,13 @@ struct X86TargetABI : TargetABI {

// all other arguments are passed on the stack, don't rewrite
}
// extern(C++) on Posix: non-POD args are passed indirectly by-value
else if (!isMSVC && fty.type->linkage == LINKcpp) {
for (auto arg : fty.args) {
if (!arg->byref && !isPOD(arg->type))
indirectByvalRewrite.applyTo(*arg);
}
}

workaroundIssue1356(fty.args);

Expand Down
6 changes: 4 additions & 2 deletions gen/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,9 @@ struct UnknownTargetABI : TargetABI {
return (rt->ty == Tstruct || rt->ty == Tsarray);
}

bool passByVal(Type *t) override { return t->toBasetype()->ty == Tstruct; }
bool passByVal(TypeFunction *, Type *t) override {
return t->toBasetype()->ty == Tstruct;
}

void rewriteFunctionType(IrFuncTy &) override {
// why?
Expand Down Expand Up @@ -361,7 +363,7 @@ struct IntrinsicABI : TargetABI {

bool returnInArg(TypeFunction *tf) override { return false; }

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

bool reverseExplicitParams(TypeFunction *) override { return false; }

Expand Down
2 changes: 1 addition & 1 deletion gen/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ struct TargetABI {
/// parameter.
/// The LL caller needs to pass a pointer to the original argument (the memcpy
/// source).
virtual bool passByVal(Type *t) = 0;
virtual bool passByVal(TypeFunction *tf, Type *t) = 0;

/// Returns true if the 'this' argument is to be passed before the 'sret'
/// argument.
Expand Down
2 changes: 1 addition & 1 deletion gen/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype,
// ref/out
attrs.addDereferenceable(loweredDType->size());
} else {
if (abi->passByVal(loweredDType)) {
if (abi->passByVal(f, loweredDType)) {
// LLVM ByVal parameters are pointers to a copy in the function
// parameters stack. The caller needs to provide a pointer to the
// original argument.
Expand Down
2 changes: 1 addition & 1 deletion gen/tocall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ static void addExplicitArguments(std::vector<LLValue *> &args, AttrSet &attrs,
std::vector<IrFuncTyArg *> optionalIrArgs;
for (size_t i = formalDArgCount; i < explicitDArgCount; i++) {
Type *argType = argexps[i]->type;
bool passByVal = gABI->passByVal(argType);
bool passByVal = gABI->passByVal(irFty.type, argType);

AttrBuilder initialAttrs;
if (passByVal) {
Expand Down
2 changes: 1 addition & 1 deletion tests/d2/dmd-testsuite

0 comments on commit 3ca43c5

Please sign in to comment.