[clang] [clang][Sema] Reject lax vector conversions involving `x87` long double (PR #228192)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 1 11:48:49 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Akash Manna (akash-manna-sky)
<details>
<summary>Changes</summary>
Fixes #<!-- -->173254
Fixes #<!-- -->63548
On x86, `long double` is an 80-bit x87 value stored in 16 bytes (12 on i386). `Sema::areVectorTypesSameSize` compares storage sizes, so it treated a one-element `long double` vector and a two-element `long long` vector as the same size, and the lax vector conversion rules inserted a `CK_BitCast` between them. LLVM gives `x86_fp80` a width of 80 bits, so CodeGen created an invalid `bitcast` and hit the `castIsValid` assertion. In #<!-- -->173254 the cast is on the argument of `__builtin_ia32_aesenc128`; in #<!-- -->63548 it is on the `return`, where the `__int128` vector produced by the comparison is converted back to the `long double` vector.
`areVectorTypesSameSize` now returns false when exactly one of the two element types is x87 `long double`, so these conversions are diagnosed as incompatible types instead of reaching CodeGen. Conversions where both sides are x87 `long double`, such as a one-element vector to the scalar, are still accepted, and `long double` in other formats is not affected.
---
Full diff: https://github.com/llvm/llvm-project/pull/228192.diff
4 Files Affected:
- (modified) clang/docs/ReleaseNotes.md (+1)
- (modified) clang/lib/Sema/SemaExpr.cpp (+8)
- (added) clang/test/Sema/vector-cast-x87.c (+46)
- (modified) clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp (+2-4)
``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 3c6acf353f93f..7471abbc0fc51 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -533,6 +533,7 @@ features cannot lower the translation-unit ABI level;
- Fixed incorrect handling of C++ import preprocessing token when a digraph character after import. (#GH190693)
- Fixed a crash when emitting RTTI for a `dllexport` class, or the fundamental type descriptors for `__cxxabiv1::__fundamental_type_info`, under `-fvisibility=hidden`. (#GH207963)
- Fixed an assertion failure when passing a wide string literal to `__builtin_nan`. (#GH212108)
+- Fixed an assertion failure when converting between an x87 `long double` vector and another vector type of the same size. (#GH173254), (#GH63548)
- Fixed a constraint comparison bug in partial ordering. (#GH182671)
- Fixed a rejected-valid case that used an explicit object parameter in an out-of-line definition of a nested class member. (#GH136472)
- Fixed an assertion on omp taskloop transparent (#GH197162)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index be1dc9f85d4f7..ceb827aa590f2 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -8070,6 +8070,14 @@ bool Sema::areVectorTypesSameSize(QualType SrcTy, QualType DestTy) {
if (!breakDownVectorType(DestTy, DestLen, DestEltTy))
return false;
+ // x87 long double has padding bits, so it cannot be bitcast to another type.
+ auto IsX87LongDouble = [&](QualType T) {
+ return T->isRealFloatingType() && &Context.getFloatTypeSemantics(T) ==
+ &llvm::APFloat::x87DoubleExtended();
+ };
+ if (IsX87LongDouble(SrcEltTy) != IsX87LongDouble(DestEltTy))
+ return false;
+
// ASTContext::getTypeSize will return the size rounded up to a
// power of 2, so instead of using that, we need to use the raw
// element size multiplied by the element count.
diff --git a/clang/test/Sema/vector-cast-x87.c b/clang/test/Sema/vector-cast-x87.c
new file mode 100644
index 0000000000000..800a57ba9c245
--- /dev/null
+++ b/clang/test/Sema/vector-cast-x87.c
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +aes -fsyntax-only -Wno-unused-value -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +aes -fsyntax-only -Wno-unused-value -mlong-double-128 -verify=quad %s
+// quad-no-diagnostics
+
+// GH173254
+typedef long double v16dl __attribute__ ((vector_size (16)));
+
+void foo(v16dl *a, v16dl *b) {
+ __builtin_ia32_aesenc128(*a, *b); // expected-error {{passing 'v16dl' (vector of 1 'long double' value) to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(long long)))) long long' (vector of 2 'long long' values)}}
+}
+
+// GH63548
+typedef long double T __attribute__((vector_size(32)));
+
+T sum(T first, T second) { return first > second; } // expected-error {{returning '__attribute__((__vector_size__(2 * sizeof(__int128)))) __int128' (vector of 2 '__int128' values) from a function with incompatible result type 'T' (vector of 2 'long double' values)}}
+
+typedef double v16d __attribute__((vector_size(16)));
+typedef double v32d __attribute__((vector_size(32)));
+typedef long long v2ll __attribute__((vector_size(16)));
+typedef __int128 v1i128 __attribute__((vector_size(16)));
+
+v16d vector_cast(v16dl a) {
+ return (v16d)a; // expected-error {{invalid conversion between vector type 'v16d' (vector of 2 'double' values) and 'v16dl' (vector of 1 'long double' value) of different size}}
+}
+
+__int128 integer_cast(v16dl a) {
+ return (__int128)a; // expected-error {{invalid conversion between vector type 'v16dl' (vector of 1 'long double' value) and integer type '__int128' of different size}}
+}
+
+v2ll scalar_operand(v2ll a, long double b) {
+ return a + b; // expected-error {{cannot convert between scalar type 'long double' and vector type 'v2ll' (vector of 2 'long long' values) as implicit conversion would cause truncation}}
+}
+
+long double scalar_result(v1i128 a) {
+ return a; // expected-error {{returning 'v1i128' (vector of 1 '__int128' value) from a function with incompatible result type 'long double'}}
+}
+
+long double same_element(v16dl a) {
+ return a;
+}
+
+void foo_double(v16d *a, v16d *b) {
+ __builtin_ia32_aesenc128(*a, *b);
+}
+
+v32d sum_double(v32d first, v32d second) { return first > second; }
diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp
index b37b362c81e75..840464668e028 100644
--- a/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp
+++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp
@@ -56,11 +56,9 @@ namespace c_cast {
// FIXME: re-enable the corresponding test cases in CodeGen/const-init.c when
// constexpr bitcast with x86_fp80 is supported
- // expected-error at +2 {{constexpr variable 'b' must be initialized by a constant expression}}
- // expected-note at +1 {{constexpr bit cast involving type 'long double' is not yet supported}}
+ // expected-error at +1 {{C-style cast from vector 'v2f80' (vector of 2 'long double' values) to vector 'v12i16' (vector of 12 'short' values) of different size}}
constexpr static v12i16 b = (v12i16)(v2f80){1,2};
- // expected-error at +2 {{constexpr variable 'c' must be initialized by a constant expression}}
- // expected-note at +1 {{constexpr bit cast involving type 'long double' is not yet supported}}
+ // expected-error at +1 {{C-style cast from vector 'v12i16' (vector of 12 'short' values) to vector 'v2f80' (vector of 2 'long double' values) of different size}}
constexpr static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0};
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/228192
More information about the cfe-commits
mailing list