https://github.com/henrybw updated https://github.com/llvm/llvm-project/pull/157365
>From 8f42b86f8d487b9f488a7cf7ec5d0e127f736b12 Mon Sep 17 00:00:00 2001 From: Henry Baba-Weiss <[email protected]> Date: Sun, 7 Sep 2025 14:16:16 -0700 Subject: [PATCH 1/8] [clang][CodeGen][MSVC] Return vector types from methods indirectly The MSVC ABI almost always returns vector types directly, but on x86 and x86_64, there seems to be a special case for member functions, which return vector types indirectly. Fixes #104. --- clang/docs/ReleaseNotes.rst | 3 ++ clang/lib/CodeGen/MicrosoftCXXABI.cpp | 23 +++++++----- .../CodeGenCXX/microsoft-abi-vector-types.cpp | 36 +++++++++++++++++++ 3 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d1ef91b7e7c14..1be917221aa2c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -90,6 +90,9 @@ C++ Specific Potentially Breaking Changes ABI Changes in This Version --------------------------- +- Fixed Microsoft calling convention for returning vector types from C++ member + functions. Such vector types should be returned indirectly. (GH#104) + AST Dumping Potentially Breaking Changes ---------------------------------------- - How nested name specifiers are dumped and printed changes, keeping track of clang AST changes. diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 88f0648660965..2d76eebcecd08 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1168,15 +1168,20 @@ static bool isTrivialForMSVC(const CXXRecordDecl *RD, QualType Ty, } bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const { - const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl(); - if (!RD) - return false; - - bool isTrivialForABI = RD->canPassInRegisters() && - isTrivialForMSVC(RD, FI.getReturnType(), CGM); - - // MSVC always returns structs indirectly from C++ instance methods. - bool isIndirectReturn = !isTrivialForABI || FI.isInstanceMethod(); + bool isIndirectReturn = false; + if (const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl()) { + bool isTrivialForABI = RD->canPassInRegisters() && + isTrivialForMSVC(RD, FI.getReturnType(), CGM); + + // MSVC always returns structs indirectly from C++ instance methods. + isIndirectReturn = !isTrivialForABI || FI.isInstanceMethod(); + } else if (isa<VectorType>(FI.getReturnType())) { + // On x86, MSVC seems to only return vector types indirectly from non- + // vectorcall C++ instance methods. + isIndirectReturn = + CGM.getTarget().getTriple().isX86() && FI.isInstanceMethod() && + FI.getCallingConvention() != llvm::CallingConv::X86_VectorCall; + } if (isIndirectReturn) { CharUnits Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType()); diff --git a/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp new file mode 100644 index 0000000000000..e046fb4bb3169 --- /dev/null +++ b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=i686-pc-windows-msvc | FileCheck %s +// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc | FileCheck %s + +// To match the MSVC ABI, vector types must be returned indirectly from member +// functions (as long as they do not use the vectorcall calling convention), +// but must be returned directly everywhere else. + +#include <xmmintrin.h> + +struct Foo { + __m128 method_m128(); + __m128 __vectorcall vectorcall_method_m128(); +}; + +__m128 Foo::method_m128() { + return __m128{}; +// GH104 +// CHECK: store <4 x float> +// CHECK: ret void +} + +__m128 __vectorcall Foo::vectorcall_method_m128() { + return __m128{}; +// CHECK: ret <4 x float> +} + +__m128 func_m128() { + return __m128{}; +// CHECK: ret <4 x float> +} + +__m128 __vectorcall vectorcall_func_m128() { + return __m128{}; +// CHECK: ret <4 x float> +} + >From fd8dd19556578bad4cc620fa76d4f00022269782 Mon Sep 17 00:00:00 2001 From: Henry Baba-Weiss <[email protected]> Date: Mon, 8 Sep 2025 16:56:50 -0700 Subject: [PATCH 2/8] amend! [clang][CodeGen][MSVC] Return vector types from methods indirectly [clang][CodeGen][MSVC] Return vector types from methods indirectly The MSVC ABI almost always returns vector types directly, but on x86 and x86_64, there seems to be a special case for member functions, which return vector types indirectly. This is an ABI change and has the potential to cause backward compatibility issues with previous Clang releases. Fixes #104. --- clang/docs/ReleaseNotes.rst | 7 +++++-- clang/include/clang/Basic/ABIVersions.def | 6 ++++++ clang/lib/CodeGen/MicrosoftCXXABI.cpp | 5 ++++- clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp | 11 +++++++++-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 1be917221aa2c..286a2889e3f36 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -90,8 +90,11 @@ C++ Specific Potentially Breaking Changes ABI Changes in This Version --------------------------- -- Fixed Microsoft calling convention for returning vector types from C++ member - functions. Such vector types should be returned indirectly. (GH#104) +- Fixed Microsoft calling convention to return vector types from C++ member + functions indirectly. This change resolves incompatibilities with code + compiled by MSVC but will introduce incompatibilities with code compiled by + Clang 21 and earlier versions, unless the ``-fclang-abi-compat=21`` option is + used. (#GH104) AST Dumping Potentially Breaking Changes ---------------------------------------- diff --git a/clang/include/clang/Basic/ABIVersions.def b/clang/include/clang/Basic/ABIVersions.def index f6524bc3bafb9..b8bd86f5f6aab 100644 --- a/clang/include/clang/Basic/ABIVersions.def +++ b/clang/include/clang/Basic/ABIVersions.def @@ -127,6 +127,12 @@ ABI_VER_MAJOR(19) /// - Incorrectly return C++ records in AVX registers on x86_64. ABI_VER_MAJOR(20) +/// Attempt to be ABI-compatible with code generated by Clang 21.0.x. +/// This causes clang to: +/// - Return vector types directly from member functions on x86 and x86_64 on +/// Windows, which is not compatible with the MSVC ABI. +ABI_VER_MAJOR(21) + /// Conform to the underlying platform's C and C++ ABIs as closely as we can. ABI_VER_LATEST(Latest) diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 2d76eebcecd08..e687d59fc19d8 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1180,7 +1180,10 @@ bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const { // vectorcall C++ instance methods. isIndirectReturn = CGM.getTarget().getTriple().isX86() && FI.isInstanceMethod() && - FI.getCallingConvention() != llvm::CallingConv::X86_VectorCall; + FI.getCallingConvention() != llvm::CallingConv::X86_VectorCall && + // Clang <= 21.0 did not do this. + getContext().getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver21; } if (isIndirectReturn) { diff --git a/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp index e046fb4bb3169..0fa80c1d48ee7 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp @@ -1,5 +1,11 @@ -// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=i686-pc-windows-msvc | FileCheck %s -// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc | FileCheck %s +// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=i686-pc-windows-msvc \ +// RUN: | FileCheck %s +// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc \ +// RUN: | FileCheck %s +// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=i686-pc-windows-msvc \ +// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=CLANG21 %s +// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc \ +// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=CLANG21 %s // To match the MSVC ABI, vector types must be returned indirectly from member // functions (as long as they do not use the vectorcall calling convention), @@ -17,6 +23,7 @@ __m128 Foo::method_m128() { // GH104 // CHECK: store <4 x float> // CHECK: ret void +// CLANG21: ret <4 x float> } __m128 __vectorcall Foo::vectorcall_method_m128() { >From 59701809d77f131af7d387b99d4de1b62a875b83 Mon Sep 17 00:00:00 2001 From: Henry Baba-Weiss <[email protected]> Date: Thu, 11 Sep 2025 17:44:42 -0700 Subject: [PATCH 3/8] fixup! [clang][CodeGen][MSVC] Return vector types from methods indirectly Add ARM64 coverage to the test. --- .../CodeGenCXX/microsoft-abi-vector-types.cpp | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp index 0fa80c1d48ee7..073a35aa5edee 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp @@ -1,16 +1,21 @@ // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=i686-pc-windows-msvc \ -// RUN: | FileCheck %s +// RUN: | FileCheck --check-prefixes=X86 %s // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc \ -// RUN: | FileCheck %s +// RUN: | FileCheck --check-prefixes=X86 %s +// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=aarch64-pc-windows-msvc \ +// RUN: | FileCheck --check-prefixes=AARCH64 %s // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=i686-pc-windows-msvc \ -// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=CLANG21 %s +// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=X86-CLANG21 %s // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc \ -// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=CLANG21 %s +// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=X86-CLANG21 %s +// RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=aarch64-pc-windows-msvc \ +// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=AARCH64-CLANG21 %s // To match the MSVC ABI, vector types must be returned indirectly from member -// functions (as long as they do not use the vectorcall calling convention), -// but must be returned directly everywhere else. +// functions on x86 and x86-64 (as long as they do not use the vectorcall +// calling convention), but must be returned directly everywhere else. +#if defined(__i386__) || defined(__x86_64__) #include <xmmintrin.h> struct Foo { @@ -21,23 +26,53 @@ struct Foo { __m128 Foo::method_m128() { return __m128{}; // GH104 -// CHECK: store <4 x float> -// CHECK: ret void -// CLANG21: ret <4 x float> +// X86: store <4 x float> +// X86: ret void +// X86-CLANG21: ret <4 x float> } __m128 __vectorcall Foo::vectorcall_method_m128() { return __m128{}; -// CHECK: ret <4 x float> +// X86: ret <4 x float> } __m128 func_m128() { return __m128{}; -// CHECK: ret <4 x float> +// X86: ret <4 x float> } __m128 __vectorcall vectorcall_func_m128() { return __m128{}; -// CHECK: ret <4 x float> +// X86: ret <4 x float> } +#endif +#ifdef __aarch64__ +#include <arm_neon.h> + +struct Foo { + float32x4_t method_f32x4(); + float32x4_t __vectorcall vectorcall_method_f32x4(); +}; + +float32x4_t Foo::method_f32x4() { + return float32x4_t{}; +// AARCH64: ret <4 x float> +// AARCH64-CLANG21: ret <4 x float> +} + +float32x4_t __vectorcall Foo::vectorcall_method_f32x4() { + return float32x4_t{}; +// AARCH64: ret <4 x float> +} + +float32x4_t func_f32x4() { + return float32x4_t{}; +// AARCH64: ret <4 x float> +} + +float32x4_t __vectorcall vectorcall_func_f32x4() { + return float32x4_t{}; +// AARCH64: ret <4 x float> +} +#endif >From 017bfea1483ea46405eb78932822d4b914abfdb9 Mon Sep 17 00:00:00 2001 From: Henry Baba-Weiss <[email protected]> Date: Thu, 11 Sep 2025 18:44:36 -0700 Subject: [PATCH 4/8] fixup! [clang][CodeGen][MSVC] Return vector types from methods indirectly Simplify the test by conditionally defining the platform's vector type. --- .../CodeGenCXX/microsoft-abi-vector-types.cpp | 75 +++++++------------ 1 file changed, 26 insertions(+), 49 deletions(-) diff --git a/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp index 073a35aa5edee..487bedbd11c37 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp @@ -1,15 +1,15 @@ // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=i686-pc-windows-msvc \ -// RUN: | FileCheck --check-prefixes=X86 %s +// RUN: | FileCheck --check-prefixes=CHECK,X86 %s // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc \ -// RUN: | FileCheck --check-prefixes=X86 %s +// RUN: | FileCheck --check-prefixes=CHECK,X86 %s // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=aarch64-pc-windows-msvc \ -// RUN: | FileCheck --check-prefixes=AARCH64 %s +// RUN: | FileCheck --check-prefixes=CHECK,AARCH64 %s // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=i686-pc-windows-msvc \ -// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=X86-CLANG21 %s +// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=CHECK,CLANG21 %s // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc \ -// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=X86-CLANG21 %s +// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=CHECK,CLANG21 %s // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=aarch64-pc-windows-msvc \ -// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=AARCH64-CLANG21 %s +// RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=CHECK,CLANG21 %s // To match the MSVC ABI, vector types must be returned indirectly from member // functions on x86 and x86-64 (as long as they do not use the vectorcall @@ -17,62 +17,39 @@ #if defined(__i386__) || defined(__x86_64__) #include <xmmintrin.h> - -struct Foo { - __m128 method_m128(); - __m128 __vectorcall vectorcall_method_m128(); -}; - -__m128 Foo::method_m128() { - return __m128{}; -// GH104 -// X86: store <4 x float> -// X86: ret void -// X86-CLANG21: ret <4 x float> -} - -__m128 __vectorcall Foo::vectorcall_method_m128() { - return __m128{}; -// X86: ret <4 x float> -} - -__m128 func_m128() { - return __m128{}; -// X86: ret <4 x float> -} - -__m128 __vectorcall vectorcall_func_m128() { - return __m128{}; -// X86: ret <4 x float> -} +#define VECTOR_TYPE __m128 #endif #ifdef __aarch64__ #include <arm_neon.h> +#define VECTOR_TYPE float32x4_t +#endif struct Foo { - float32x4_t method_f32x4(); - float32x4_t __vectorcall vectorcall_method_f32x4(); + VECTOR_TYPE method_ret_vec(); + VECTOR_TYPE __vectorcall vectorcall_method_ret_vec(); }; -float32x4_t Foo::method_f32x4() { - return float32x4_t{}; +VECTOR_TYPE Foo::method_ret_vec() { + return VECTOR_TYPE{}; +// GH104 +// X86: store <4 x float> +// X86: ret void // AARCH64: ret <4 x float> -// AARCH64-CLANG21: ret <4 x float> +// CLANG21: ret <4 x float> } -float32x4_t __vectorcall Foo::vectorcall_method_f32x4() { - return float32x4_t{}; -// AARCH64: ret <4 x float> +VECTOR_TYPE __vectorcall Foo::vectorcall_method_ret_vec() { + return VECTOR_TYPE{}; +// CHECK: ret <4 x float> } -float32x4_t func_f32x4() { - return float32x4_t{}; -// AARCH64: ret <4 x float> +VECTOR_TYPE func_ret_vec() { + return VECTOR_TYPE{}; +// CHECK: ret <4 x float> } -float32x4_t __vectorcall vectorcall_func_f32x4() { - return float32x4_t{}; -// AARCH64: ret <4 x float> +VECTOR_TYPE __vectorcall vectorcall_func_ret_vec() { + return VECTOR_TYPE{}; +// CHECK: ret <4 x float> } -#endif >From c0f4b2256209e6c2f06b118fc4852b9e991ca7aa Mon Sep 17 00:00:00 2001 From: Henry Baba-Weiss <[email protected]> Date: Thu, 2 Oct 2025 20:23:52 -0700 Subject: [PATCH 5/8] amend! [clang][CodeGen][MSVC] Return vector types from methods indirectly [clang][CodeGen][MSVC] Match how MSVC returns vector types from member functions The MSVC ABI usually returns vector types directly, but on x86 and x86-64, there seems to be a special case for C++ member functions, which return vector types indirectly (with the exception of member functions using the `__vectorcall` calling convention, which return vector types > 64 bits directly). This is an ABI change and has the potential to cause backward compatibility issues with previous Clang releases. Fixes #104. --- clang/lib/CodeGen/MicrosoftCXXABI.cpp | 32 ++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index e687d59fc19d8..05b132ada92a3 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1168,26 +1168,32 @@ static bool isTrivialForMSVC(const CXXRecordDecl *RD, QualType Ty, } bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const { + QualType RetTy = FI.getReturnType(); bool isIndirectReturn = false; - if (const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl()) { - bool isTrivialForABI = RD->canPassInRegisters() && - isTrivialForMSVC(RD, FI.getReturnType(), CGM); + + if (const CXXRecordDecl *RD = RetTy->getAsCXXRecordDecl()) { + bool isTrivialForABI = + RD->canPassInRegisters() && isTrivialForMSVC(RD, RetTy, CGM); // MSVC always returns structs indirectly from C++ instance methods. isIndirectReturn = !isTrivialForABI || FI.isInstanceMethod(); - } else if (isa<VectorType>(FI.getReturnType())) { - // On x86, MSVC seems to only return vector types indirectly from non- - // vectorcall C++ instance methods. - isIndirectReturn = - CGM.getTarget().getTriple().isX86() && FI.isInstanceMethod() && - FI.getCallingConvention() != llvm::CallingConv::X86_VectorCall && - // Clang <= 21.0 did not do this. - getContext().getLangOpts().getClangABICompat() > - LangOptions::ClangABI::Ver21; + } else if (isa<VectorType>(RetTy) && + getContext().getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver21) { + // On x86, MSVC usually returns vector types indirectly from C++ instance + // methods. (Clang <= 21.0 always returned vector types directly.) + if (CGM.getTarget().getTriple().isX86() && FI.isInstanceMethod()) { + // However, MSVC returns vector types > 64 bits directly from vectorcall + // instance methods. + if (FI.getCallingConvention() == llvm::CallingConv::X86_VectorCall) + isIndirectReturn = getContext().getTypeSize(RetTy) == 64; + else + isIndirectReturn = true; + } } if (isIndirectReturn) { - CharUnits Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType()); + CharUnits Align = CGM.getContext().getTypeAlignInChars(RetTy); FI.getReturnInfo() = ABIArgInfo::getIndirect( Align, /*AddrSpace=*/CGM.getDataLayout().getAllocaAddrSpace(), /*ByVal=*/false); >From c6b0cd3308cc6882ebd5bbb223a25d5fef7f86b3 Mon Sep 17 00:00:00 2001 From: Henry Baba-Weiss <[email protected]> Date: Tue, 30 Sep 2025 22:05:35 -0700 Subject: [PATCH 6/8] fixup! [clang][CodeGen][MSVC] Return vector types from methods indirectly Rework the test to also cover 64-bit vector types. --- .../CodeGenCXX/microsoft-abi-vector-types.cpp | 70 ++++++++++++++----- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp index 487bedbd11c37..c80d4674ade53 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-vector-types.cpp @@ -11,45 +11,83 @@ // RUN: %clang_cc1 -ffreestanding -emit-llvm %s -o - -triple=aarch64-pc-windows-msvc \ // RUN: -fclang-abi-compat=21 | FileCheck --check-prefixes=CHECK,CLANG21 %s -// To match the MSVC ABI, vector types must be returned indirectly from member -// functions on x86 and x86-64 (as long as they do not use the vectorcall -// calling convention), but must be returned directly everywhere else. +// To match the MSVC ABI, vector types are usually returned directly, but on x86 +// and x86-64 they must be returned indirectly from member functions (unless +// they use the vectorcall calling convention and the vector type is > 64 bits). #if defined(__i386__) || defined(__x86_64__) #include <xmmintrin.h> -#define VECTOR_TYPE __m128 + +#define VECTOR64_TYPE __m64 +#define VECTOR128_TYPE __m128 + +#define VECTORCALL __vectorcall #endif #ifdef __aarch64__ #include <arm_neon.h> -#define VECTOR_TYPE float32x4_t + +// These were chosen such that they lower to the same types that the x86 vector +// types lower to (e.g. int64x1_t and __m64 both lower to <1 x i64>). +#define VECTOR64_TYPE int64x1_t +#define VECTOR128_TYPE float32x4_t + +#define VECTORCALL #endif struct Foo { - VECTOR_TYPE method_ret_vec(); - VECTOR_TYPE __vectorcall vectorcall_method_ret_vec(); + VECTOR64_TYPE method_ret_vec64(); + VECTOR128_TYPE method_ret_vec128(); + + VECTOR64_TYPE VECTORCALL vc_method_ret_vec64(); + VECTOR128_TYPE VECTORCALL vc_method_ret_vec128(); }; -VECTOR_TYPE Foo::method_ret_vec() { - return VECTOR_TYPE{}; -// GH104 +VECTOR64_TYPE Foo::method_ret_vec64() { + return VECTOR64_TYPE{}; +// X86: store <1 x i64> +// X86: ret void +// AARCH64: ret <1 x i64> +// CLANG21: ret <1 x i64> +} + +VECTOR128_TYPE Foo::method_ret_vec128() { + return VECTOR128_TYPE{}; // X86: store <4 x float> // X86: ret void // AARCH64: ret <4 x float> // CLANG21: ret <4 x float> } -VECTOR_TYPE __vectorcall Foo::vectorcall_method_ret_vec() { - return VECTOR_TYPE{}; +VECTOR64_TYPE VECTORCALL Foo::vc_method_ret_vec64() { + return VECTOR64_TYPE{}; +// X86: store <1 x i64> +// X86: ret void +// AARCH64: ret <1 x i64> +// CLANG21: ret <1 x i64> +} + +VECTOR128_TYPE VECTORCALL Foo::vc_method_ret_vec128() { + return VECTOR128_TYPE{}; // CHECK: ret <4 x float> } -VECTOR_TYPE func_ret_vec() { - return VECTOR_TYPE{}; +VECTOR64_TYPE func_ret_vec64() { + return VECTOR64_TYPE{}; +// CHECK: ret <1 x i64> +} + +VECTOR128_TYPE func_ret_vec128() { + return VECTOR128_TYPE{}; // CHECK: ret <4 x float> } -VECTOR_TYPE __vectorcall vectorcall_func_ret_vec() { - return VECTOR_TYPE{}; +VECTOR64_TYPE VECTORCALL vc_func_ret_vec64() { + return VECTOR64_TYPE{}; +// CHECK: ret <1 x i64> +} + +VECTOR128_TYPE VECTORCALL vc_func_ret_vec128() { + return VECTOR128_TYPE{}; // CHECK: ret <4 x float> } >From 71cd7fd8eae20ead470d1eb22c1c813b54093dce Mon Sep 17 00:00:00 2001 From: Henry Baba-Weiss <[email protected]> Date: Thu, 2 Oct 2025 20:47:14 -0700 Subject: [PATCH 7/8] fixup! [clang][CodeGen][MSVC] Return vector types from methods indirectly Tweak wording of ABI note and update release note to say Clang now matches MSVC. --- clang/docs/ReleaseNotes.rst | 10 +++++----- clang/include/clang/Basic/ABIVersions.def | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 286a2889e3f36..36e7baff58e79 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -90,11 +90,11 @@ C++ Specific Potentially Breaking Changes ABI Changes in This Version --------------------------- -- Fixed Microsoft calling convention to return vector types from C++ member - functions indirectly. This change resolves incompatibilities with code - compiled by MSVC but will introduce incompatibilities with code compiled by - Clang 21 and earlier versions, unless the ``-fclang-abi-compat=21`` option is - used. (#GH104) +- Fixed Microsoft calling convention to match how MSVC returns vector types from + C++ member functions on x86-64. This change resolves incompatibilities with + code compiled by MSVC but will introduce incompatibilities with code compiled + by Clang 21 and earlier versions, unless the ``-fclang-abi-compat=21`` option + is used. (#GH104) AST Dumping Potentially Breaking Changes ---------------------------------------- diff --git a/clang/include/clang/Basic/ABIVersions.def b/clang/include/clang/Basic/ABIVersions.def index b8bd86f5f6aab..a08338db22992 100644 --- a/clang/include/clang/Basic/ABIVersions.def +++ b/clang/include/clang/Basic/ABIVersions.def @@ -129,8 +129,8 @@ ABI_VER_MAJOR(20) /// Attempt to be ABI-compatible with code generated by Clang 21.0.x. /// This causes clang to: -/// - Return vector types directly from member functions on x86 and x86_64 on -/// Windows, which is not compatible with the MSVC ABI. +/// - Always return vector types directly from member functions on x86 and +/// x86_64 on Windows, which is not compatible with the MSVC ABI. ABI_VER_MAJOR(21) /// Conform to the underlying platform's C and C++ ABIs as closely as we can. >From 2964b824e203ed6a3e7dde8df0e57c1a204e9e29 Mon Sep 17 00:00:00 2001 From: Henry Baba-Weiss <[email protected]> Date: Thu, 2 Oct 2025 22:07:46 -0700 Subject: [PATCH 8/8] fixup! [clang][CodeGen][MSVC] Return vector types from methods indirectly Specify x86/x86-64 in release note. --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 36e7baff58e79..4b287c5d15f19 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -91,7 +91,7 @@ ABI Changes in This Version --------------------------- - Fixed Microsoft calling convention to match how MSVC returns vector types from - C++ member functions on x86-64. This change resolves incompatibilities with + C++ member functions on x86/x86-64. This change resolves incompatibilities with code compiled by MSVC but will introduce incompatibilities with code compiled by Clang 21 and earlier versions, unless the ``-fclang-abi-compat=21`` option is used. (#GH104) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
