mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-10 12:59:21 +03:00
Use IndirectByvalRewrite for non-POD args and extern(C++) on Posix (#2728)
Fixing one aspect of issue #2702; not tackling the different destruction rules yet.
This commit is contained in:
parent
f8880c6c38
commit
3ca43c51b8
15 changed files with 61 additions and 30 deletions
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ public:
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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 ®Count);
|
||||
void rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg, RegCount ®Count);
|
||||
|
||||
LLValue *prepareVaStart(DLValue *ap) override;
|
||||
|
||||
|
@ -252,11 +253,15 @@ 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());
|
||||
}
|
||||
|
||||
|
@ -264,10 +269,21 @@ void X86_64TargetABI::rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg) {
|
|||
llvm_unreachable("Please use the other overload explicitly.");
|
||||
}
|
||||
|
||||
void X86_64TargetABI::rewriteArgument(IrFuncTyArg &arg, RegCount ®Count) {
|
||||
void X86_64TargetABI::rewriteArgument(IrFuncTy &fty, IrFuncTyArg &arg,
|
||||
RegCount ®Count) {
|
||||
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 {
|
||||
|
@ -280,11 +296,12 @@ void X86_64TargetABI::rewriteArgument(IrFuncTyArg &arg, RegCount ®Count) {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ struct X86TargetABI : TargetABI {
|
|||
const bool isMSVC;
|
||||
bool returnStructsInRegs;
|
||||
IntegerRewrite integerRewrite;
|
||||
IndirectByvalRewrite indirectByvalRewrite;
|
||||
|
||||
X86TargetABI()
|
||||
: isOSX(global.params.targetTriple->isMacOSX()),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a0f157abcc2d2779aa44cd9d6dec84aa56950d81
|
||||
Subproject commit b0b28297a8befba66640c7b4462ecdc12c40c318
|
Loading…
Add table
Add a link
Reference in a new issue