aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2020-10-13 19:58:39 -0700
committerReid Kleckner <rnk@google.com>2020-10-15 14:54:42 -0700
commit5fbab4025eb57b12f2842ab188ff07a110708e1d (patch)
tree1b74c4b0080f693219556914c7c453d6d6e72baa /clang/lib/CodeGen
parent6754caa9bf21a759c4080a797f23e2b7a77a71e1 (diff)
downloadllvm-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.cpp50
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;
}