llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: mike-goutokuji (mike-goutokuji)

<details>
<summary>Changes</summary>

- Fix Clang returning vectorcall HVA/HFA types via `sret` when they are not 
C++14 aggregates (e.g. they have base classes, protected members, or 
user-provided constructors).
- MSVC returns these types in XMM registers on x86/x64 vectorcall; Clang was 
incorrectly treating them as indirect returns after applying the usual MSVC 
C++14 aggregate rules in `MicrosoftCXXABI::classifyReturnType`.
- Allow direct register returns for `__vectorcall` functions when the return 
type is a homogeneous aggregate and can still be passed in registers. This is 
analogous to the AArch64 HVA return handling added for #<!-- -->62223, but on 
x86 vectorcall the same relaxation also applies to HFAs.

Fixes #<!-- -->63417

---
Full diff: https://github.com/llvm/llvm-project/pull/203925.diff


3 Files Affected:

- (modified) clang/lib/CodeGen/MicrosoftCXXABI.cpp (+11) 
- (modified) clang/test/CodeGenCXX/homogeneous-aggregates.cpp (+22) 
- (added) clang/test/CodeGenCXX/microsoft-abi-vectorcall-hva.cpp (+30) 


``````````diff
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp 
b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 40c7c00d85395..b24595036a930 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1192,6 +1192,17 @@ bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo 
&FI) const {
   bool isTrivialForABI = RD->canPassInRegisters() &&
                          isTrivialForMSVC(RD, FI.getReturnType(), CGM);
 
+  // On x86 and x64, vectorcall returns HVAs and HFAs in registers even if they
+  // are not C++14 aggregates (e.g. they have base classes), as long as they 
can
+  // still be passed in registers and qualify as homogeneous aggregates.
+  if (!isTrivialForABI && RD->canPassInRegisters() &&
+      FI.getCallingConvention() == llvm::CallingConv::X86_VectorCall) {
+    const Type *Base = nullptr;
+    uint64_t NumElts = 0;
+    if (CGM.getABIInfo().isHomogeneousAggregate(FI.getReturnType(), Base, 
NumElts))
+      isTrivialForABI = true;
+  }
+
   // MSVC always returns structs indirectly from C++ instance methods.
   bool isIndirectReturn = !isTrivialForABI || FI.isInstanceMethod();
 
diff --git a/clang/test/CodeGenCXX/homogeneous-aggregates.cpp 
b/clang/test/CodeGenCXX/homogeneous-aggregates.cpp
index 278c19b384c92..6365472fc4b3e 100644
--- a/clang/test/CodeGenCXX/homogeneous-aggregates.cpp
+++ b/clang/test/CodeGenCXX/homogeneous-aggregates.cpp
@@ -302,3 +302,25 @@ 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 
dead_on_unwind inreg noalias writable sret(%"struct.pr62223::test2") align 8 
%{{.*}}, ptr noundef %{{.*}})
 }
+
+namespace pr113104 {
+// On x86/x64 vectorcall, both HVAs and HFAs are returned in registers even 
when
+// they are not C++14 aggregates (unlike WOA64, where only HVAs get this
+// treatment — see pr62223 above).
+struct HFA {
+  float a;
+  float b;
+};
+
+using HVA = float __attribute__((__vector_size__(16), __aligned__(16)));
+
+struct base_hfa { HFA v1; };
+struct test_hfa : base_hfa { test_hfa(double); protected: HFA v2; };
+test_hfa CC f(test_hfa *x) { return *x; }
+// X64: define dso_local x86_vectorcallcc %"struct.pr113104::test_hfa" 
@"\01_ZN8pr1131041fEPNS_8test_hfaE@@8"(ptr noundef %x)
+
+struct base_hva { HVA v1; };
+struct test_hva : base_hva { test_hva(double); protected: HVA v2; };
+test_hva CC f(test_hva *x) { return *x; }
+// X64: define dso_local x86_vectorcallcc %"struct.pr113104::test_hva" 
@"\01_ZN8pr1131041fEPNS_8test_hvaE@@8"(ptr noundef %x)
+}
diff --git a/clang/test/CodeGenCXX/microsoft-abi-vectorcall-hva.cpp 
b/clang/test/CodeGenCXX/microsoft-abi-vectorcall-hva.cpp
new file mode 100644
index 0000000000000..7739813088111
--- /dev/null
+++ b/clang/test/CodeGenCXX/microsoft-abi-vectorcall-hva.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple i686-pc-windows-msvc -emit-llvm -o - %s | FileCheck 
%s --check-prefix=X86
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -o - %s | 
FileCheck %s --check-prefix=X64
+
+typedef float __m128 __attribute__((__vector_size__(16)));
+
+// HVA with base class
+struct base_hva { __m128 v; };
+struct test_hva : base_hva { test_hva(double); protected: __m128 v2; };
+
+// HFA with base class
+struct base_hfa { double v; };
+struct test_hfa : base_hfa { test_hfa(double); protected: double v2; };
+
+// 1. Vectorcall returns should be direct (not sret)
+test_hva __vectorcall ret_hva_vectorcall(test_hva *x) { return *x; }
+// X86-LABEL: define dso_local x86_vectorcallcc %struct.test_hva 
@"?ret_hva_vectorcall@@YQ?AUtest_hva@@PAU1@@Z"(ptr inreg noundef %x)
+// X64-LABEL: define dso_local x86_vectorcallcc %struct.test_hva 
@"?ret_hva_vectorcall@@YQ?AUtest_hva@@PEAU1@@Z"(ptr noundef %x)
+
+test_hfa __vectorcall ret_hfa_vectorcall(test_hfa *x) { return *x; }
+// X86-LABEL: define dso_local x86_vectorcallcc %struct.test_hfa 
@"?ret_hfa_vectorcall@@YQ?AUtest_hfa@@PAU1@@Z"(ptr inreg noundef %x)
+// X64-LABEL: define dso_local x86_vectorcallcc %struct.test_hfa 
@"?ret_hfa_vectorcall@@YQ?AUtest_hfa@@PEAU1@@Z"(ptr noundef %x)
+
+// 2. Cdecl returns should be indirect (sret) because they are not aggregates
+test_hva __cdecl ret_hva_cdecl(test_hva *x) { return *x; }
+// X86-LABEL: define dso_local void 
@"?ret_hva_cdecl@@YA?AUtest_hva@@PAU1@@Z"(ptr dead_on_unwind noalias writable 
sret(%struct.test_hva) align 16 %agg.result, ptr noundef %x)
+// X64-LABEL: define dso_local void 
@"?ret_hva_cdecl@@YA?AUtest_hva@@PEAU1@@Z"(ptr dead_on_unwind noalias writable 
sret(%struct.test_hva) align 16 %agg.result, ptr noundef %x)
+
+test_hfa __cdecl ret_hfa_cdecl(test_hfa *x) { return *x; }
+// X86-LABEL: define dso_local void 
@"?ret_hfa_cdecl@@YA?AUtest_hfa@@PAU1@@Z"(ptr dead_on_unwind noalias writable 
sret(%struct.test_hfa) align 8 %agg.result, ptr noundef %x)
+// X64-LABEL: define dso_local void 
@"?ret_hfa_cdecl@@YA?AUtest_hfa@@PEAU1@@Z"(ptr dead_on_unwind noalias writable 
sret(%struct.test_hfa) align 8 %agg.result, ptr noundef %x)

``````````

</details>


https://github.com/llvm/llvm-project/pull/203925
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to