[llvm] [SLP]Fix erasing scalars used by narrowed reduction chain instructions (PR #218174)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 22 17:48:54 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Alexey Bataev (alexey-bataev)
<details>
<summary>Changes</summary>
Narrowed reduction chain instructions may use non-root tree scalars;
clear such uses before erasing the scalars.
Fixes https://github.com/llvm/llvm-project/pull/216062#issuecomment-5381262165
---
Full diff: https://github.com/llvm/llvm-project/pull/218174.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp (+20-3)
- (added) llvm/test/Transforms/SLPVectorizer/AArch64/narrowed-reduction-chain-use.ll (+60)
``````````diff
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 6a947cda11751..8d49f8b9fda9d 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -748,6 +748,12 @@ class slpvectorizer::BoUpSLP {
/// Construct a vectorizable tree that starts at \p Roots.
void buildTree(ArrayRef<Value *> Roots);
+ /// Sets the narrowed reduction chain instructions, dropped together with
+ /// the reduction.
+ void setNarrowedChainInsts(ArrayRef<Instruction *> Insts) {
+ NarrowedChainInsts.insert(Insts.begin(), Insts.end());
+ }
+
/// Returns true if the last buildTree() observed a may-alias memory
/// dependency between two distinct, range-checkable base objects, i.e. a
/// dependency that could be turned into a runtime alias check.
@@ -958,6 +964,7 @@ class slpvectorizer::BoUpSLP {
ExtraBitWidthNodes.clear();
InstrElementSize.clear();
UserIgnoreList = nullptr;
+ NarrowedChainInsts.clear();
PostponedGathers.clear();
ValueToGatherNodes.clear();
TreeEntryToStridedPtrInfoMap.clear();
@@ -5528,6 +5535,10 @@ class slpvectorizer::BoUpSLP {
/// List of users to ignore during scheduling and that don't need extracting.
const SmallDenseSet<Value *> *UserIgnoreList = nullptr;
+ /// Narrowed reduction chain instructions, dropped together with the
+ /// reduction. Subset of UserIgnoreList.
+ SmallPtrSet<Value *, 4> NarrowedChainInsts;
+
/// A DenseMapInfo implementation for holding DenseMaps and DenseSets of
/// sorted SmallVectors of unsigned.
struct OrdersTypeDenseMapInfo {
@@ -26182,7 +26193,11 @@ Value *BoUpSLP::vectorizeTree(
!(GatheredLoadsEntriesFirst.has_value() &&
IE->Idx >= *GatheredLoadsEntriesFirst && getRootNode().isGather() &&
is_contained(getRootNodeScalars(), I)) &&
- !(!getRootNode().isGather() && getRootNode().isCopyableElement(I)))
+ !(!getRootNode().isGather() && getRootNode().isCopyableElement(I)) &&
+ // Dropped narrowed reduction chain instructions may still use
+ // non-root scalars; such uses must be cleared as well.
+ none_of(I->users(),
+ [&](User *U) { return NarrowedChainInsts.contains(U); }))
continue;
SmallVector<SelectInst *> LogicalOpSelects;
I->replaceUsesWithIf(PoisonValue::get(I->getType()), [&](Use &U) {
@@ -31243,10 +31258,12 @@ class HorizontalReduction {
return RedValI && V.isDeleted(RedValI);
}))
break;
- if (RK == ReductionOrdering::Ordered)
+ if (RK == ReductionOrdering::Ordered) {
V.buildTree(VL);
- else
+ } else {
V.buildTree(VL, IgnoreList);
+ V.setNarrowedChainInsts(NarrowedChainInsts);
+ }
if (V.isTreeTinyAndNotFullyVectorizable(RK ==
ReductionOrdering::Unordered)) {
constexpr unsigned CandidatesLimit = 64;
diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/narrowed-reduction-chain-use.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/narrowed-reduction-chain-use.ll
new file mode 100644
index 0000000000000..5f1bae8a63bea
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/narrowed-reduction-chain-use.ll
@@ -0,0 +1,60 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=slp-vectorizer -S -mtriple=aarch64-linux-gnu | FileCheck %s
+
+
+define ptr @test(ptr %q, ptr %z) {
+; CHECK-LABEL: define ptr @test(
+; CHECK-SAME: ptr [[Q:%.*]], ptr [[Z:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br label %[[FOR_COND:.*]]
+; CHECK: [[FOR_COND]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[FOR_COND]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [4 x i8], ptr [[Z]], i64 [[IV]]
+; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[L]], i64 0
+; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[TMP0]], <2 x i32> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], <i32 6, i32 -1>
+; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <2 x i32> [[TMP2]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 1>
+; CHECK-NEXT: [[TMP4:%.*]] = lshr <4 x i32> [[TMP3]], <i32 2, i32 1, i32 7, i32 3>
+; CHECK-NEXT: [[TMP5:%.*]] = and <4 x i32> [[TMP4]], <i32 -1, i32 255, i32 255, i32 252>
+; CHECK-NEXT: [[TMP6:%.*]] = zext <4 x i32> [[TMP5]] to <4 x i64>
+; CHECK-NEXT: [[TMP7:%.*]] = shl <4 x i64> [[TMP6]], <i64 33, i64 0, i64 1, i64 1>
+; CHECK-NEXT: [[TMP8:%.*]] = call i64 @llvm.vector.reduce.or.v4i64(<4 x i64> [[TMP7]])
+; CHECK-NEXT: [[TMP9:%.*]] = and i32 [[L]], 6
+; CHECK-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
+; CHECK-NEXT: [[TMP11:%.*]] = shl i64 [[TMP10]], 38
+; CHECK-NEXT: [[OP_RDX:%.*]] = or disjoint i64 [[TMP8]], [[TMP11]]
+; CHECK-NEXT: [[ARRAYIDX16:%.*]] = getelementptr inbounds nuw [8 x i8], ptr [[Q]], i64 [[IV]]
+; CHECK-NEXT: store i64 [[OP_RDX]], ptr [[ARRAYIDX16]], align 8
+; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
+; CHECK-NEXT: br label %[[FOR_COND]]
+;
+entry:
+ br label %for.cond
+
+for.cond:
+ %iv = phi i64 [ %iv.next, %for.cond ], [ 0, %entry ]
+ %arrayidx = getelementptr inbounds nuw [4 x i8], ptr %z, i64 %iv
+ %l = load i32, ptr %arrayidx, align 4
+ %shr = lshr i32 %l, 1
+ %and = and i32 %l, 6
+ %l3 = lshr i32 %l, 3
+ %shl = and i32 %l3, 252
+ %shr9 = lshr i32 %l, 7
+ %shl10 = shl nuw nsw i32 %and, 5
+ %shr11 = lshr i32 %and, 2
+ %or12 = or disjoint i32 %shl10, %shr11
+ %conv2.i = zext nneg i32 %or12 to i64
+ %m5 = and i32 %shr, 255
+ %shr9.masked = and i32 %shr9, 255
+ %o6 = or i32 %shl, %shr9.masked
+ %s7 = shl nuw nsw i32 %o6, 1
+ %or.i.i27 = or i32 %s7, %m5
+ %or.i.i = zext nneg i32 %or.i.i27 to i64
+ %sext.i = shl nuw nsw i64 %conv2.i, 33
+ %or5.i.i = or disjoint i64 %sext.i, %or.i.i
+ %arrayidx16 = getelementptr inbounds nuw [8 x i8], ptr %q, i64 %iv
+ store i64 %or5.i.i, ptr %arrayidx16, align 8
+ %iv.next = add nuw nsw i64 %iv, 1
+ br label %for.cond
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/218174
More information about the llvm-commits
mailing list