https://github.com/m-amirpour created 
https://github.com/llvm/llvm-project/pull/233070

Fixes #233063.

`LowerFunnelShift`'s pre-AVX2 256-bit split path calls
`DAG.getNode(FSHL/FSHR, ...)` and then `splitVectorOp` on the result. When
all operands are constants — e.g. `ucmp(x, x)` expanded to a zero vector
by the vector legalizer — `getNode` constant-folds the funnel shift into a
`BUILD_VECTOR`. `splitVectorOp` then treats the 8 scalar `BUILD_VECTOR`
operands as sub-vectors, producing a malformed `v4i32 BUILD_VECTOR` with
8 operands:

- **+asserts**: `Assertion 'VT.getVectorNumElements() == (unsigned)NumOps
  && "Incorrect element count in BUILD_VECTOR!"' failed.`
- **Release**: `free(): invalid size` (heap corruption).

Bail out to the generic path when the node was constant-folded.

## Test

- Reproducer from the issue: `llc -O2 -mattr=+avx crash-min.ll -o /dev/null`
  - before: assertion / SIGABRT
  - after: exits 0
- New regression test: `llvm/test/CodeGen/X86/funnel-shift-avx-constant-fold.ll`
- `ninja check-llvm-codegen-x86`: 5762 tests, 0 failures
  (5745 pass, 15 XFAIL, 2 unsupported)
- `clang-format`: no changes

>From 6a88d0e980d3605297592a17ef2b5cfad137db69 Mon Sep 17 00:00:00 2001
From: m-amirpour <[email protected]>
Date: Fri, 16 Oct 2026 17:09:03 +0330
Subject: [PATCH 1/2] [clang] Add regression test for GH205000

---
 clang/test/SemaCXX/cxx2c-fold-exprs.cpp | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp 
b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
index f0819ed04881b3..0778ed7fe66372 100644
--- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
+++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
@@ -752,3 +752,18 @@ static_assert(count == 2);
 
 }
 
+namespace GH205000 {
+
+template <int N>
+struct StringLiteral {
+  constexpr StringLiteral(const auto... c)
+    requires (__is_same(decltype(c), const char) && ...) {}
+  constexpr StringLiteral(const char (&s)[N]) {}
+};
+
+template <StringLiteral... fields>
+struct Lit {};
+
+using Unit = Lit<"a">;
+
+}

>From ad41cf14b096a1dda89af6c801367fe8218189b4 Mon Sep 17 00:00:00 2001
From: m-amirpour <[email protected]>
Date: Sat, 17 Oct 2026 14:48:12 +0330
Subject: [PATCH 2/2] [X86] Fix LowerFunnelShift crash when folding yields
 BUILD_VECTOR

LowerFunnelShift's pre-AVX2 256-bit split path calls
DAG.getNode(FSHL/FSHR, ...) and then splitVectorOp on the result. When all
operands are constants -- e.g. ucmp(x, x) expanded to a zero vector by the
vector legalizer -- getNode constant-folds the funnel shift into a
BUILD_VECTOR. splitVectorOp then treats the 8 scalar BUILD_VECTOR operands
as sub-vectors, producing a malformed v4i32 BUILD_VECTOR with 8 operands:
an assertion failure ("Incorrect element count in BUILD_VECTOR!") in
asserts builds, and heap corruption in Release builds.

Bail out to the generic path when the node was constant-folded.

Fixes https://github.com/llvm/llvm-project/issues/233063
---
 llvm/lib/Target/X86/X86ISelLowering.cpp       |  9 ++++++++
 .../X86/funnel-shift-avx-constant-fold.ll     | 22 +++++++++++++++++++
 2 files changed, 31 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/funnel-shift-avx-constant-fold.ll

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp 
b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 416761793904f9..d5ec8d9f3704b6 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -32290,7 +32290,16 @@ static SDValue LowerFunnelShift(SDValue Op, const 
X86Subtarget &Subtarget,
         (VT.is512BitVector() && !Subtarget.useBWIRegs() &&
          EltSizeInBits < 32)) {
       // Pre-mask the amount modulo using the wider vector.
+      unsigned OrigOpc = Op.getOpcode();
       Op = DAG.getNode(Op.getOpcode(), DL, VT, Op0, Op1, AmtMod);
+
+      // If constant folding turned the funnel shift into a BUILD_VECTOR (e.g.
+      // ucmp(x, x) was expanded to a zero vector by the legalizer), don't try
+      // to split a non-funnel-shift node: its operands are scalars, not
+      // sub-vectors. Let the generic legalizer handle it instead.
+      if (Op.getOpcode() != OrigOpc)
+        return Op;
+
       return splitVectorOp(Op, DAG, DL);
     }
 
diff --git a/llvm/test/CodeGen/X86/funnel-shift-avx-constant-fold.ll 
b/llvm/test/CodeGen/X86/funnel-shift-avx-constant-fold.ll
new file mode 100644
index 00000000000000..db5cceeb9faed6
--- /dev/null
+++ b/llvm/test/CodeGen/X86/funnel-shift-avx-constant-fold.ll
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 
UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx | FileCheck %s
+
+; Regression test for https://github.com/llvm/llvm-project/issues/233063
+; LowerFunnelShift's pre-AVX2 256-bit split path called splitVectorOp on a
+; node that constant-folded into a BUILD_VECTOR, producing a malformed
+; v4i32 BUILD_VECTOR with 8 scalar operands (assert, or heap corruption in
+; Release builds).
+
+define <8 x i32> @fshr_constant_fold(<8 x i32> %x) {
+; CHECK-LABEL: fshr_constant_fold:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vmovaps {{.*#+}} ymm0 = [8,8,24,16,40,24,56,32]
+; CHECK-NEXT:    retq
+  %v0 = call <8 x i32> @llvm.ucmp.v8i32.v8i32(<8 x i32> %x, <8 x i32> %x)
+  %v1 = call <8 x i32> @llvm.fshr.v8i32(<8 x i32> %v0, <8 x i32> <i32 16, i32 
32, i32 48, i32 64, i32 80, i32 96, i32 112, i32 128>,
+                                        <8 x i32> <i32 1, i32 2, i32 1, i32 2, 
i32 1, i32 2, i32 1, i32 2>)
+  ret <8 x i32> %v1
+}
+
+declare <8 x i32> @llvm.ucmp.v8i32.v8i32(<8 x i32>, <8 x i32>)
+declare <8 x i32> @llvm.fshr.v8i32(<8 x i32>, <8 x i32>, <8 x i32>)

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

Reply via email to