[llvm] [SLP]Fix crash on short interleaved gathered-load remainder (PR #210965)

Alexey Bataev via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 21 05:31:14 PDT 2026


https://github.com/alexey-bataev created https://github.com/llvm/llvm-project/pull/210965

A trailing, undersized chunk could keep an InterleaveFactor too
large for it, so RISCVTTIImpl::getInterleavedMemoryOpCost divided
by it and built a zero-element vector type.

Fixes #210849


>From f2ec0b767934e9646a6dde4b3dc581c6b60ff594 Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Tue, 21 Jul 2026 05:31:01 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.7
---
 .../Transforms/Vectorize/SLPVectorizer.cpp    |   6 +-
 ...hered-loads-interleave-factor-remainder.ll | 142 ++++++++++++++++++
 2 files changed, 147 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/Transforms/SLPVectorizer/RISCV/gathered-loads-interleave-factor-remainder.ll

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 9650415998142..9f8c85cb8e7b3 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -10123,7 +10123,11 @@ void BoUpSLP::tryToVectorizeGatheredLoads(
                            }))
                   continue;
                 unsigned Sz = VectorizableTree.size();
-                buildTreeRec(SubSlice, 0, EdgeInfo(), InterleaveFactor);
+                // A chunk smaller than InterleaveFactor cannot form an
+                // interleave group; keep it non-interleaved instead.
+                buildTreeRec(
+                    SubSlice, 0, EdgeInfo(),
+                    SubSlice.size() >= InterleaveFactor ? InterleaveFactor : 0);
                 if (Sz == VectorizableTree.size()) {
                   IsVectorized = false;
                   // Try non-interleaved vectorization with smaller vector
diff --git a/llvm/test/Transforms/SLPVectorizer/RISCV/gathered-loads-interleave-factor-remainder.ll b/llvm/test/Transforms/SLPVectorizer/RISCV/gathered-loads-interleave-factor-remainder.ll
new file mode 100644
index 0000000000000..0ec1672a2ddf5
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/RISCV/gathered-loads-interleave-factor-remainder.ll
@@ -0,0 +1,142 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=slp-vectorizer -mtriple=riscv64-unknown-fuchsia -mattr=+zve64x -S | FileCheck %s
+
+; The trailing, less-than-full-width chunk of gathered loads must not be
+; tagged with the interleave factor computed for the full-width chunks,
+; otherwise the cost model divides the chunk size by the factor and gets 0,
+; tripping the FixedVectorType::get NumElts > 0 assertion.
+
+define void @_Z8keccak_fv() {
+; CHECK-LABEL: define void @_Z8keccak_fv(
+; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[ARRAYIDX12_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 120
+; CHECK-NEXT:    [[DOTPRE105:%.*]] = load i64, ptr [[ARRAYIDX12_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX16_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 160
+; CHECK-NEXT:    [[DOTPRE106:%.*]] = load i64, ptr [[ARRAYIDX16_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX_2_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 16
+; CHECK-NEXT:    [[DOTPRE107:%.*]] = load i64, ptr [[ARRAYIDX_2_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX5_2_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 56
+; CHECK-NEXT:    [[DOTPRE109:%.*]] = load i64, ptr [[ARRAYIDX5_2_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX8_2_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 96
+; CHECK-NEXT:    [[DOTPRE111:%.*]] = load i64, ptr [[ARRAYIDX8_2_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX12_2_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 136
+; CHECK-NEXT:    [[DOTPRE113:%.*]] = load i64, ptr [[ARRAYIDX12_2_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX16_2_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 176
+; CHECK-NEXT:    [[DOTPRE115:%.*]] = load i64, ptr [[ARRAYIDX16_2_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX_3_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 24
+; CHECK-NEXT:    [[DOTPRE116:%.*]] = load i64, ptr [[ARRAYIDX_3_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[DOTPRE120:%.*]] = load i64, ptr null, align 8
+; CHECK-NEXT:    [[ARRAYIDX12_3_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 144
+; CHECK-NEXT:    [[DOTPRE122:%.*]] = load i64, ptr [[ARRAYIDX12_3_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX16_3_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 184
+; CHECK-NEXT:    [[DOTPRE124:%.*]] = load i64, ptr [[ARRAYIDX16_3_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX8_4_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 112
+; CHECK-NEXT:    [[DOTPRE127:%.*]] = load i64, ptr [[ARRAYIDX8_4_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX12_4_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 152
+; CHECK-NEXT:    [[DOTPRE128:%.*]] = load i64, ptr [[ARRAYIDX12_4_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX16_4_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr null, i64 192
+; CHECK-NEXT:    [[DOTPRE129:%.*]] = load i64, ptr [[ARRAYIDX16_4_PHI_TRANS_INSERT]], align 8
+; CHECK-NEXT:    [[ARRAYIDX12_1:%.*]] = getelementptr i8, ptr null, i64 128
+; CHECK-NEXT:    [[ARRAYIDX12_1_PROMOTED:%.*]] = load i64, ptr [[ARRAYIDX12_1]], align 8
+; CHECK-NEXT:    [[ARRAYIDX16_1:%.*]] = getelementptr i8, ptr null, i64 168
+; CHECK-NEXT:    [[ARRAYIDX16_1_PROMOTED:%.*]] = load i64, ptr [[ARRAYIDX16_1]], align 8
+; CHECK-NEXT:    br label %[[FOR_BODY:.*]]
+; CHECK:       [[FOR_BODY]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = phi i64 [ [[ARRAYIDX16_1_PROMOTED]], %[[ENTRY]] ], [ 0, %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP1:%.*]] = phi i64 [ [[ARRAYIDX12_1_PROMOTED]], %[[ENTRY]] ], [ 0, %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP2:%.*]] = phi i64 [ [[DOTPRE129]], %[[ENTRY]] ], [ 0, %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP3:%.*]] = phi i64 [ [[DOTPRE128]], %[[ENTRY]] ], [ 0, %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP4:%.*]] = phi i64 [ [[DOTPRE124]], %[[ENTRY]] ], [ [[AND_4:%.*]], %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP5:%.*]] = phi i64 [ [[DOTPRE122]], %[[ENTRY]] ], [ [[XOR60_3:%.*]], %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP6:%.*]] = phi i64 [ [[DOTPRE120]], %[[ENTRY]] ], [ 0, %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP7:%.*]] = phi i64 [ [[DOTPRE115]], %[[ENTRY]] ], [ 0, %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP8:%.*]] = phi i64 [ [[DOTPRE109]], %[[ENTRY]] ], [ [[XOR37_499:%.*]], %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP9:%.*]] = phi i64 [ [[DOTPRE107]], %[[ENTRY]] ], [ [[OP_RDX1:%.*]], %[[FOR_BODY]] ]
+; CHECK-NEXT:    [[TMP10:%.*]] = xor i64 [[DOTPRE111]], [[DOTPRE113]]
+; CHECK-NEXT:    [[TMP11:%.*]] = xor i64 [[TMP10]], [[TMP7]]
+; CHECK-NEXT:    [[TMP12:%.*]] = xor i64 [[TMP11]], [[TMP9]]
+; CHECK-NEXT:    [[XOR17_2:%.*]] = xor i64 [[TMP12]], [[TMP8]]
+; CHECK-NEXT:    [[XOR_3:%.*]] = xor i64 0, [[DOTPRE116]]
+; CHECK-NEXT:    [[XOR9_3:%.*]] = xor i64 [[XOR_3]], [[TMP6]]
+; CHECK-NEXT:    [[XOR13_3:%.*]] = xor i64 [[XOR9_3]], [[TMP5]]
+; CHECK-NEXT:    [[XOR17_3:%.*]] = xor i64 [[XOR13_3]], [[TMP4]]
+; CHECK-NEXT:    [[XOR29_4:%.*]] = xor i64 [[XOR17_2]], [[XOR17_3]]
+; CHECK-NEXT:    [[XOR37_499]] = xor i64 [[XOR29_4]], [[DOTPRE106]]
+; CHECK-NEXT:    [[OP_RDX:%.*]] = xor i64 0, [[TMP1]]
+; CHECK-NEXT:    [[OP_RDX1]] = xor i64 [[OP_RDX]], [[TMP0]]
+; CHECK-NEXT:    [[XOR17_4:%.*]] = xor i64 [[TMP3]], [[TMP2]]
+; CHECK-NEXT:    [[XOR37_3:%.*]] = xor i64 [[XOR17_4]], [[DOTPRE105]]
+; CHECK-NEXT:    [[AND_3:%.*]] = and i64 [[XOR37_3]], 0
+; CHECK-NEXT:    [[XOR60_3]] = xor i64 0, [[AND_3]]
+; CHECK-NEXT:    [[XOR37_4:%.*]] = xor i64 [[DOTPRE127]], 0
+; CHECK-NEXT:    [[AND_4]] = and i64 [[XOR37_4]], 0
+; CHECK-NEXT:    br label %[[FOR_BODY]]
+;
+entry:
+  %arrayidx12.phi.trans.insert = getelementptr i8, ptr null, i64 120
+  %.pre105 = load i64, ptr %arrayidx12.phi.trans.insert, align 8
+  %arrayidx16.phi.trans.insert = getelementptr i8, ptr null, i64 160
+  %.pre106 = load i64, ptr %arrayidx16.phi.trans.insert, align 8
+  %arrayidx.2.phi.trans.insert = getelementptr i8, ptr null, i64 16
+  %.pre107 = load i64, ptr %arrayidx.2.phi.trans.insert, align 8
+  %arrayidx5.2.phi.trans.insert = getelementptr i8, ptr null, i64 56
+  %.pre109 = load i64, ptr %arrayidx5.2.phi.trans.insert, align 8
+  %arrayidx8.2.phi.trans.insert = getelementptr i8, ptr null, i64 96
+  %.pre111 = load i64, ptr %arrayidx8.2.phi.trans.insert, align 8
+  %arrayidx12.2.phi.trans.insert = getelementptr i8, ptr null, i64 136
+  %.pre113 = load i64, ptr %arrayidx12.2.phi.trans.insert, align 8
+  %arrayidx16.2.phi.trans.insert = getelementptr i8, ptr null, i64 176
+  %.pre115 = load i64, ptr %arrayidx16.2.phi.trans.insert, align 8
+  %arrayidx.3.phi.trans.insert = getelementptr i8, ptr null, i64 24
+  %.pre116 = load i64, ptr %arrayidx.3.phi.trans.insert, align 8
+  %.pre120 = load i64, ptr null, align 8
+  %arrayidx12.3.phi.trans.insert = getelementptr i8, ptr null, i64 144
+  %.pre122 = load i64, ptr %arrayidx12.3.phi.trans.insert, align 8
+  %arrayidx16.3.phi.trans.insert = getelementptr i8, ptr null, i64 184
+  %.pre124 = load i64, ptr %arrayidx16.3.phi.trans.insert, align 8
+  %arrayidx8.4.phi.trans.insert = getelementptr i8, ptr null, i64 112
+  %.pre127 = load i64, ptr %arrayidx8.4.phi.trans.insert, align 8
+  %arrayidx12.4.phi.trans.insert = getelementptr i8, ptr null, i64 152
+  %.pre128 = load i64, ptr %arrayidx12.4.phi.trans.insert, align 8
+  %arrayidx16.4.phi.trans.insert = getelementptr i8, ptr null, i64 192
+  %.pre129 = load i64, ptr %arrayidx16.4.phi.trans.insert, align 8
+  %arrayidx12.1 = getelementptr i8, ptr null, i64 128
+  %arrayidx12.1.promoted = load i64, ptr %arrayidx12.1, align 8
+  %arrayidx16.1 = getelementptr i8, ptr null, i64 168
+  %arrayidx16.1.promoted = load i64, ptr %arrayidx16.1, align 8
+  br label %for.body
+
+for.body:
+  %0 = phi i64 [ %arrayidx16.1.promoted, %entry ], [ 0, %for.body ]
+  %1 = phi i64 [ %arrayidx12.1.promoted, %entry ], [ 0, %for.body ]
+  %2 = phi i64 [ %.pre129, %entry ], [ 0, %for.body ]
+  %3 = phi i64 [ %.pre128, %entry ], [ 0, %for.body ]
+  %4 = phi i64 [ %.pre124, %entry ], [ %and.4, %for.body ]
+  %5 = phi i64 [ %.pre122, %entry ], [ %xor60.3, %for.body ]
+  %6 = phi i64 [ %.pre120, %entry ], [ 0, %for.body ]
+  %7 = phi i64 [ %.pre115, %entry ], [ 0, %for.body ]
+  %8 = phi i64 [ %.pre109, %entry ], [ %xor37.499, %for.body ]
+  %9 = phi i64 [ %.pre107, %entry ], [ %xor54, %for.body ]
+  %10 = xor i64 %.pre111, %.pre113
+  %11 = xor i64 %10, %7
+  %12 = xor i64 %11, %9
+  %xor17.2 = xor i64 %12, %8
+  %xor.3 = xor i64 0, %.pre116
+  %xor9.3 = xor i64 %xor.3, %6
+  %xor13.3 = xor i64 %xor9.3, %5
+  %xor17.3 = xor i64 %xor13.3, %4
+  %xor29.4 = xor i64 %xor17.2, %xor17.3
+  %xor37.499 = xor i64 %xor29.4, %.pre106
+  %xor17.1 = xor i64 %1, %0
+  %xor37.295 = xor i64 %xor17.1, 0
+  %13 = xor i64 0, %xor37.295
+  %xor54 = xor i64 %13, 0
+  %xor17.4 = xor i64 %3, %2
+  %xor37.3 = xor i64 %xor17.4, %.pre105
+  %and.3 = and i64 %xor37.3, 0
+  %xor60.3 = xor i64 0, %and.3
+  %xor37.4 = xor i64 %.pre127, 0
+  %and.4 = and i64 %xor37.4, 0
+  br label %for.body
+}



More information about the llvm-commits mailing list