Skip to content

Commit

Permalink
[clang codegen] Fix ABI for HVA returns on AArch64 MSVC.
Browse files Browse the repository at this point in the history
MSVC normally has a bunch of restrictions on returning values directly
which don't apply to passing values directly.  (This roughly corresponds
to the definition of a C++14 aggregate.)  However, these restrictions
don't apply to HVAs; make sure we check for that.

Fixes #62223

Differential Revision: https://reviews.llvm.org/D153179
  • Loading branch information
efriedma-quic committed Jun 26, 2023
1 parent 73eecc9 commit a1540e4
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 2 deletions.
18 changes: 16 additions & 2 deletions clang/lib/CodeGen/MicrosoftCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//
//===----------------------------------------------------------------------===//

#include "ABIInfo.h"
#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGVTables.h"
Expand Down Expand Up @@ -1099,7 +1100,19 @@ bool MicrosoftCXXABI::hasMostDerivedReturn(GlobalDecl GD) const {
return isDeletingDtor(GD);
}

static bool isTrivialForMSVC(const CXXRecordDecl *RD) {
static bool isTrivialForMSVC(const CXXRecordDecl *RD, QualType Ty,
CodeGenModule &CGM) {
// On AArch64, HVAs that can be passed in registers can also be returned
// in registers. (Note this is using the MSVC definition of an HVA; see
// isPermittedToBeHomogeneousAggregate().)
const Type *Base = nullptr;
uint64_t NumElts = 0;
if (CGM.getTarget().getTriple().isAArch64() &&
CGM.getTypes().getABIInfo().isHomogeneousAggregate(Ty, Base, NumElts) &&
isa<VectorType>(Base)) {
return true;
}

// We use the C++14 definition of an aggregate, so we also
// check for:
// No private or protected non static data members.
Expand Down Expand Up @@ -1128,7 +1141,8 @@ bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
if (!RD)
return false;

bool isTrivialForABI = RD->canPassInRegisters() && isTrivialForMSVC(RD);
bool isTrivialForABI = RD->canPassInRegisters() &&
isTrivialForMSVC(RD, FI.getReturnType(), CGM);

// MSVC always returns structs indirectly from C++ instance methods.
bool isIndirectReturn = !isTrivialForABI || FI.isInstanceMethod();
Expand Down
17 changes: 17 additions & 0 deletions clang/test/CodeGenCXX/homogeneous-aggregates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,20 @@ struct HFA {
double foo(HFA v) { return v.x + v.y; }
// WOA64: define dso_local noundef double @"?foo@non_empty_field@@YANUHFA@1@@Z"([4 x double] %{{.*}})
}

namespace pr62223 {
// HVAs don't follow the normal rules for return values. That means they can
// have base classes, user-defined ctors, and protected/private members.
// (The same restrictions that apply to HVA arguments still apply.)
typedef double V __attribute((ext_vector_type(2)));
struct base { V v; };
struct test : base { test(double); protected: V v2;};
test f(test *x) { return *x; }
// WOA64: define dso_local %"struct.pr62223::test" @"?f@pr62223@@YA?AUtest@1@PEAU21@@Z"(ptr noundef %{{.*}})

// The above rule only apples to HVAs, not HFAs.
struct base2 { double v; };
struct test2 : base2 { test2(double); protected: double v2;};
test2 f(test2 *x) { return *x; }
// WOA64: define dso_local void @"?f@pr62223@@YA?AUtest2@1@PEAU21@@Z"(ptr inreg noalias sret(%"struct.pr62223::test2") align 8 %{{.*}}, ptr noundef %{{.*}})
}

0 comments on commit a1540e4

Please sign in to comment.