From: Mandeep Singh Grang Date: Thu, 26 Jul 2018 18:07:59 +0000 (+0000) Subject: [COFF, ARM64] Decide when to mark struct returns as SRet X-Git-Tag: llvmorg-7.0.0-rc1~498 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2a153101bffaeea3dc39ff2970bb04e5fd1d8e1e;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h index 5ea655cb..cf64e9f 100644 --- a/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -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; }; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index f60136c..f066ce1 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -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); diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index e5e9cf6..a1122dc 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -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; } diff --git a/clang/test/CodeGen/arm64-microsoft-arguments.cpp b/clang/test/CodeGen/arm64-microsoft-arguments.cpp new file mode 100644 index 0000000..3ef4688 --- /dev/null +++ b/clang/test/CodeGen/arm64-microsoft-arguments.cpp @@ -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*)