[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