diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 76701dc723b6c..2b653e5af6f5a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -63,6 +63,11 @@ ABI Changes in This Version MSVC uses a different mangling for these objects, compatibility is not affected. (#GH85423). +- Records carrying the trivial_abi attribute are now returned directly in registers + in more cases when using the Microsoft ABI. It is not possible to pass trivial_abi + records between MSVC and Clang, so there is no ABI compatibility requirement. This + is an ABI break with old versions of Clang. (#GH87993) + AST Dumping Potentially Breaking Changes ---------------------------------------- diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index d38a26940a3cb..b930913badcd3 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1105,6 +1105,11 @@ bool MicrosoftCXXABI::hasMostDerivedReturn(GlobalDecl GD) const { static bool isTrivialForMSVC(const CXXRecordDecl *RD, QualType Ty, CodeGenModule &CGM) { + // If the record is marked with the trivial_abi attribute, we don't + // have to conform to the standard MSVC ABI. + if (RD->hasAttr()) + return true; + // 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().) diff --git a/clang/test/CodeGenCXX/trivial_abi_msvc.cpp b/clang/test/CodeGenCXX/trivial_abi_msvc.cpp new file mode 100644 index 0000000000000..0af1d63acd1a5 --- /dev/null +++ b/clang/test/CodeGenCXX/trivial_abi_msvc.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++11 -fcxx-exceptions -fexceptions -emit-llvm -o - %s | FileCheck %s + +// CHECK: %[[STRUCT_TRIVIAL:.*]] = type { ptr } +struct __attribute__((trivial_abi)) Trivial { + int *p; + Trivial() : p(0) {} + Trivial(const Trivial &) noexcept = default; +}; + +// CHECK-LABEL: define{{.*}} i64 @"?retTrivial@@YA?AUTrivial@@XZ"( +// CHECK: %retval = alloca %[[STRUCT_TRIVIAL]], align 8 +// CHECK: %call = call noundef ptr @"??0Trivial@@QEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %retval) +// CHECK: %coerce.dive = getelementptr inbounds %[[STRUCT_TRIVIAL]], ptr %retval, i32 0, i32 0 +// CHECK: %0 = load ptr, ptr %coerce.dive, align 8 +// CHECK: %coerce.val.pi = ptrtoint ptr %0 to i64 +// CHECK: ret i64 %coerce.val.pi +Trivial retTrivial() { + Trivial s; + return s; +} + +struct TrivialInstance { + Trivial instanceMethod(); + static Trivial staticMethod(); +}; + +// We need to make sure that instanceMethod has a sret return value since `this` will always go in the register. +// CHECK-LABEL: define{{.*}} void @"?instanceMethod@TrivialInstance@@QEAA?AUTrivial@@XZ"({{.*}} sret(%struct.Trivial{{.*}} +Trivial TrivialInstance::instanceMethod() { return {}; } +// CHECK-LABEL: define{{.*}} i64 @"?staticMethod@TrivialInstance@@SA?AUTrivial@@XZ"( +Trivial TrivialInstance::staticMethod() { return {}; }