diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -625,6 +625,8 @@ virtual std::pair LoadVTablePtr(CodeGenFunction &CGF, Address This, const CXXRecordDecl *RD) = 0; + + static bool isCXX14Aggregate(const CXXRecordDecl *RD); }; // Create an instance of a C++ ABI class: diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -310,3 +310,27 @@ return AddedStructorArgCounts(AddedArgs.Prefix.size(), AddedArgs.Suffix.size()); } + +bool CGCXXABI::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. + // No base classes + // No virtual functions + // 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 false; + if (RD->getNumBases() > 0) + return false; + if (RD->isPolymorphic()) + return false; + if (RD->hasNonTrivialCopyAssignment()) + return false; + for (const CXXConstructorDecl *Ctor : RD->ctors()) + if (Ctor->isUserProvided()) + return false; + if (RD->hasNonTrivialDestructor()) + return false; + return true; +} diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1070,30 +1070,6 @@ return isDeletingDtor(GD); } -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. - // No base classes - // No virtual functions - // 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 false; - if (RD->getNumBases() > 0) - return false; - if (RD->isPolymorphic()) - return false; - if (RD->hasNonTrivialCopyAssignment()) - return false; - for (const CXXConstructorDecl *Ctor : RD->ctors()) - if (Ctor->isUserProvided()) - return false; - if (RD->hasNonTrivialDestructor()) - return false; - return true; -} - bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const { const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl(); if (!RD) diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -5133,6 +5133,14 @@ Members += FldMembers; } + + const auto TT = CGT.getTarget().getTriple(); + // MSVC Windows on Arm64 considers a type not HFA if it is not an + // aggregate according to the C++14 spec. This is not consistent with the + // AAPCS64, but is defacto spec on that platform. + if (TT.isAArch64() && TT.isWindowsMSVCEnvironment() && + !CGCXXABI::isCXX14Aggregate(CXXRD)) + return false; } for (const auto *FD : RD->fields()) { diff --git a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp --- a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp @@ -468,3 +468,31 @@ // WIN64-LABEL: define dso_local void @"?g@C@pr30293@@QEAAXXZ"(%"struct.pr30293::C"* {{[^,]*}} %this) // WIN64: declare dso_local void @"?h@C@pr30293@@UEAAXUSmallWithDtor@@@Z"(i8*, i32) } + +namespace pr47611 { +// MSVC on Arm includes "isCXX14Aggregate" as part of its definition of +// Homogeneous Floating-point Aggregate (HFA). Additionally, it has a different +// handling of C++14 aggregates, which can lead to confusion. + +// Pod is a trivial HFA. +struct Pod { + double b[2]; +}; +// Not an aggregate according to C++14 spec => not HFA according to MSVC. +struct NotCXX14Aggregate { + NotCXX14Aggregate(); + Pod p; +}; +// NotPod is a C++14 aggregate. But not HFA, because it contains +// NotCXX14Aggregate (which itself is not HFA because it's not a C++14 +// aggregate). +struct NotPod { + NotCXX14Aggregate x; +}; +// WOA64-LABEL: define dso_local %"struct.pr47611::Pod" @"?copy@pr47611@@YA?AUPod@1@PEAU21@@Z"(%"struct.pr47611::Pod"* %x) +Pod copy(Pod *x) { return *x; } // MSVC: ldp d0,d1,[x0], Clang: ldp d0,d1,[x0] +// WOA64-LABEL: define dso_local void @"?copy@pr47611@@YA?AUNotCXX14Aggregate@1@PEAU21@@Z"(%"struct.pr47611::NotCXX14Aggregate"* inreg noalias sret(%"struct.pr47611::NotCXX14Aggregate") align 8 %agg.result, %"struct.pr47611::NotCXX14Aggregate"* %x) +NotCXX14Aggregate copy(NotCXX14Aggregate *x) { return *x; } // MSVC: stp x8,x9,[x0], Clang: str q0,[x0] +// WOA64-LABEL: define dso_local [2 x i64] @"?copy@pr47611@@YA?AUNotPod@1@PEAU21@@Z"(%"struct.pr47611::NotPod"* %x) +NotPod copy(NotPod *x) { return *x; } +};