Index: include/clang/CodeGen/CGFunctionInfo.h =================================================================== --- include/clang/CodeGen/CGFunctionInfo.h +++ include/clang/CodeGen/CGFunctionInfo.h @@ -95,7 +95,6 @@ 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,14 +110,13 @@ } ABIArgInfo(Kind K) - : TheKind(K), PaddingInReg(false), InReg(false), SuppressSRet(false) { + : TheKind(K), PaddingInReg(false), InReg(false) { } public: ABIArgInfo() : TypeData(nullptr), PaddingType(nullptr), DirectOffset(0), - TheKind(Direct), PaddingInReg(false), InReg(false), - SuppressSRet(false) {} + TheKind(Direct), PaddingInReg(false), InReg(false) {} static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0, llvm::Type *Padding = nullptr, @@ -407,16 +405,6 @@ CanBeFlattened = Flatten; } - bool getSuppressSRet() const { - assert(isIndirect() && "Invalid kind!"); - return SuppressSRet; - } - - void setSuppressSRet(bool Suppress) { - assert(isIndirect() && "Invalid kind!"); - SuppressSRet = Suppress; - } - void dump() const; }; Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1999,8 +1999,7 @@ // Attach attributes to sret. if (IRFunctionArgs.hasSRetArg()) { llvm::AttrBuilder SRETAttrs; - if (!RetAI.getSuppressSRet()) - SRETAttrs.addAttribute(llvm::Attribute::StructRet); + SRETAttrs.addAttribute(llvm::Attribute::StructRet); hasUsedSRet = true; if (RetAI.getInReg()) SRETAttrs.addAttribute(llvm::Attribute::InReg); Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -1052,32 +1052,43 @@ } bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const { + // For AArch64 see: + // https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=vs-2019#return-values + + // 1. For return types <= 16 bytes, use the C return semantics. + + // 2. For instance methods, "this" is passed to the callee in X0 and the + // struct address in X1. So the callee needs to copy X1 to X0 before + // returning. + + // 3. For non-instance methods which return a non-POD struct, the address of + // the struct is passed to the callee in X0. We use the "inreg" attribute on + // a parameter to indicate a non-POD struct. + + // 4. Example of POD struct: struct pod { int x; } + // Example of non-POD struct: struct nonpod { int x; nonpod() {} } + + bool isAArch64 = CGM.getTarget().getTriple().isAArch64(); + + if (isAArch64) { + uint64_t RetTySize = getContext().getTypeSize(FI.getReturnType()); + if (RetTySize <= 16) + return false; + } + const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl(); if (!RD) return false; - CharUnits Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType()); - if (FI.isInstanceMethod()) { - // If it's an instance method, aggregates are always returned indirectly via - // the second parameter. - FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false); - FI.getReturnInfo().setSRetAfterThis(FI.isInstanceMethod()); + bool isIndirectReturn = !RD->isPOD(); + bool isInstanceMethod = 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. + CharUnits Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType()); + if (isIndirectReturn || isInstanceMethod) { FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false); + FI.getReturnInfo().setSRetAfterThis(isInstanceMethod); + FI.getReturnInfo().setInReg(isAArch64 && isIndirectReturn); - // 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; } Index: test/CodeGen/arm64-microsoft-arguments.cpp =================================================================== --- test/CodeGen/arm64-microsoft-arguments.cpp +++ test/CodeGen/arm64-microsoft-arguments.cpp @@ -14,7 +14,7 @@ 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: define {{.*}} void @{{.*}}foo{{.*}}(%struct.non_pod* inreg noalias sret %agg.result) // Check instance methods. @@ -22,4 +22,4 @@ struct Baz { pod2 baz(); }; int qux() { return Baz().baz().x; } -// CHECK: declare {{.*}} void @{{.*}}baz@Baz{{.*}}(%struct.Baz*, %struct.pod2*) +// CHECK: declare {{.*}} void @{{.*}}baz@Baz{{.*}}(%struct.Baz*, %struct.pod2* sret)