diff options
author | Reid Kleckner <rnk@google.com> | 2020-10-13 19:58:39 -0700 |
---|---|---|
committer | Reid Kleckner <rnk@google.com> | 2020-10-15 14:54:42 -0700 |
commit | 5fbab4025eb57b12f2842ab188ff07a110708e1d (patch) | |
tree | 1b74c4b0080f693219556914c7c453d6d6e72baa /clang/lib/CodeGen | |
parent | 6754caa9bf21a759c4080a797f23e2b7a77a71e1 (diff) | |
download | llvm-5fbab4025eb57b12f2842ab188ff07a110708e1d.zip llvm-5fbab4025eb57b12f2842ab188ff07a110708e1d.tar.gz llvm-5fbab4025eb57b12f2842ab188ff07a110708e1d.tar.bz2 |
[MS] Apply `inreg` to AArch64 sret parms on instance methods
The documentation rules indicate that instance methods should return
large, trivially copyable aggregates via X1/X0 and not X8 as is normally
done when returning such structs from free functions:
https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=vs-2019#return-values
Fixes PR47836, a bug in the initial implementation of these rules.
I tried to simplify the logic a bit as well while I'm here.
Differential Revision: https://reviews.llvm.org/D89362
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 50 |
1 files changed, 27 insertions, 23 deletions
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index cae7909..31e7e4c 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1070,11 +1070,7 @@ bool MicrosoftCXXABI::hasMostDerivedReturn(GlobalDecl GD) const { return isDeletingDtor(GD); } -static bool IsSizeGreaterThan128(const CXXRecordDecl *RD) { - return RD->getASTContext().getTypeSize(RD->getTypeForDecl()) > 128; -} - -static bool hasMicrosoftABIRestrictions(const CXXRecordDecl *RD) { +static bool isCXX14Aggregate(const CXXRecordDecl *RD) { // For AArch64, we use the C++14 definition of an aggregate, so we also // check for: // No private or protected non static data members. @@ -1083,19 +1079,19 @@ static bool hasMicrosoftABIRestrictions(const CXXRecordDecl *RD) { // Additionally, we need to ensure that there is a trivial copy assignment // operator, a trivial destructor and no user-provided constructors. if (RD->hasProtectedFields() || RD->hasPrivateFields()) - return true; + return false; if (RD->getNumBases() > 0) - return true; + return false; if (RD->isPolymorphic()) - return true; + return false; if (RD->hasNonTrivialCopyAssignment()) - return true; + return false; for (const CXXConstructorDecl *Ctor : RD->ctors()) if (Ctor->isUserProvided()) - return true; + return false; if (RD->hasNonTrivialDestructor()) - return true; - return false; + return false; + return true; } bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const { @@ -1103,21 +1099,29 @@ bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const { if (!RD) return false; + // Normally, the C++ concept of "is trivially copyable" is used to determine + // if a struct can be returned directly. However, as MSVC and the language + // have evolved, the definition of "trivially copyable" has changed, while the + // ABI must remain stable. AArch64 uses the C++14 concept of an "aggregate", + // while other ISAs use the older concept of "plain old data". + bool isTrivialForABI = RD->isPOD(); bool isAArch64 = CGM.getTarget().getTriple().isAArch64(); - bool isSimple = !isAArch64 || !hasMicrosoftABIRestrictions(RD); - bool isIndirectReturn = - isAArch64 ? (!RD->canPassInRegisters() || - IsSizeGreaterThan128(RD)) - : !RD->isPOD(); - bool isInstanceMethod = FI.isInstanceMethod(); - - if (isIndirectReturn || !isSimple || isInstanceMethod) { + if (isAArch64) + isTrivialForABI = RD->canPassInRegisters() && isCXX14Aggregate(RD); + + // MSVC always returns structs indirectly from C++ instance methods. + bool isIndirectReturn = !isTrivialForABI || FI.isInstanceMethod(); + + if (isIndirectReturn) { CharUnits Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType()); FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false); - FI.getReturnInfo().setSRetAfterThis(isInstanceMethod); - FI.getReturnInfo().setInReg(isAArch64 && - !(isSimple && IsSizeGreaterThan128(RD))); + // MSVC always passes `this` before the `sret` parameter. + FI.getReturnInfo().setSRetAfterThis(FI.isInstanceMethod()); + + // On AArch64, use the `inreg` attribute if the object is considered to not + // be trivially copyable, or if this is an instance method struct return. + FI.getReturnInfo().setInReg(isAArch64); return true; } |