forked from OSchip/llvm-project
[COFF, ARM64] Decide when to mark struct returns as SRet
Summary: Refer the MS ARM64 ABI Convention for the behavior for struct returns: https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions#return-values Reviewers: mstorsjo, compnerd, rnk, javed.absar, yinma, efriedma Reviewed By: rnk, efriedma Subscribers: haripul, TomTan, yinma, efriedma, kristof.beyls, chrib, llvm-commits Differential Revision: https://reviews.llvm.org/D49464 llvm-svn: 338050
This commit is contained in:
parent
3bdd60095f
commit
2a153101bf
|
@ -96,6 +96,7 @@ private:
|
|||
bool InReg : 1; // isDirect() || isExtend() || isIndirect()
|
||||
bool CanBeFlattened: 1; // isDirect()
|
||||
bool SignExt : 1; // isExtend()
|
||||
bool SuppressSRet : 1; // isIndirect()
|
||||
|
||||
bool canHavePaddingType() const {
|
||||
return isDirect() || isExtend() || isIndirect() || isExpand();
|
||||
|
@ -111,13 +112,14 @@ private:
|
|||
}
|
||||
|
||||
ABIArgInfo(Kind K)
|
||||
: TheKind(K), PaddingInReg(false), InReg(false) {
|
||||
: TheKind(K), PaddingInReg(false), InReg(false), SuppressSRet(false) {
|
||||
}
|
||||
|
||||
public:
|
||||
ABIArgInfo()
|
||||
: TypeData(nullptr), PaddingType(nullptr), DirectOffset(0),
|
||||
TheKind(Direct), PaddingInReg(false), InReg(false) {}
|
||||
TheKind(Direct), PaddingInReg(false), InReg(false),
|
||||
SuppressSRet(false) {}
|
||||
|
||||
static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0,
|
||||
llvm::Type *Padding = nullptr,
|
||||
|
@ -406,6 +408,16 @@ public:
|
|||
CanBeFlattened = Flatten;
|
||||
}
|
||||
|
||||
bool getSuppressSRet() const {
|
||||
assert(isIndirect() && "Invalid kind!");
|
||||
return SuppressSRet;
|
||||
}
|
||||
|
||||
void setSuppressSRet(bool Suppress) {
|
||||
assert(isIndirect() && "Invalid kind!");
|
||||
SuppressSRet = Suppress;
|
||||
}
|
||||
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -1988,7 +1988,8 @@ void CodeGenModule::ConstructAttributeList(
|
|||
// Attach attributes to sret.
|
||||
if (IRFunctionArgs.hasSRetArg()) {
|
||||
llvm::AttrBuilder SRETAttrs;
|
||||
SRETAttrs.addAttribute(llvm::Attribute::StructRet);
|
||||
if (!RetAI.getSuppressSRet())
|
||||
SRETAttrs.addAttribute(llvm::Attribute::StructRet);
|
||||
hasUsedSRet = true;
|
||||
if (RetAI.getInReg())
|
||||
SRETAttrs.addAttribute(llvm::Attribute::InReg);
|
||||
|
|
|
@ -1060,10 +1060,22 @@ bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
|
|||
// the second parameter.
|
||||
FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
|
||||
FI.getReturnInfo().setSRetAfterThis(FI.isInstanceMethod());
|
||||
|
||||
// aarch64-windows requires that instance methods use X1 for the return
|
||||
// address. So for aarch64-windows we do not mark the
|
||||
// return as SRet.
|
||||
FI.getReturnInfo().setSuppressSRet(CGM.getTarget().getTriple().getArch() ==
|
||||
llvm::Triple::aarch64);
|
||||
return true;
|
||||
} else if (!RD->isPOD()) {
|
||||
// If it's a free function, non-POD types are returned indirectly.
|
||||
FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
|
||||
|
||||
// aarch64-windows requires that non-POD, non-instance returns use X0 for
|
||||
// the return address. So for aarch64-windows we do not mark the return as
|
||||
// SRet.
|
||||
FI.getReturnInfo().setSuppressSRet(CGM.getTarget().getTriple().getArch() ==
|
||||
llvm::Triple::aarch64);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// RUN: %clang_cc1 -triple aarch64-windows -ffreestanding -emit-llvm -O0 \
|
||||
// RUN: -x c++ -o - %s | FileCheck %s
|
||||
|
||||
struct pod { int a, b, c, d, e; };
|
||||
|
||||
struct non_pod {
|
||||
int a;
|
||||
non_pod() {}
|
||||
};
|
||||
|
||||
struct pod s;
|
||||
struct non_pod t;
|
||||
|
||||
struct pod bar() { return s; }
|
||||
struct non_pod foo() { return t; }
|
||||
// CHECK: define {{.*}} void @{{.*}}bar{{.*}}(%struct.pod* noalias sret %agg.result)
|
||||
// CHECK: define {{.*}} void @{{.*}}foo{{.*}}(%struct.non_pod* noalias %agg.result)
|
||||
|
||||
|
||||
// Check instance methods.
|
||||
struct pod2 { int x; };
|
||||
struct Baz { pod2 baz(); };
|
||||
|
||||
int qux() { return Baz().baz().x; }
|
||||
// CHECK: declare {{.*}} void @{{.*}}baz@Baz{{.*}}(%struct.Baz*, %struct.pod2*)
|
Loading…
Reference in New Issue