[llvm] bdd1b0a - [SLP]Fix erasing reduced vals after partial shuffled-extract group merge

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 25 10:48:37 PDT 2026


Author: Alexey Bataev
Date: 2026-08-25T13:48:32-04:00
New Revision: bdd1b0aa73e75d6e45af1f6b0fee2275c68f2adb

URL: https://github.com/llvm/llvm-project/commit/bdd1b0aa73e75d6e45af1f6b0fee2275c68f2adb
DIFF: https://github.com/llvm/llvm-project/commit/bdd1b0aa73e75d6e45af1f6b0fee2275c68f2adb.diff

LOG: [SLP]Fix erasing reduced vals after partial shuffled-extract group merge

The merge copied only extractelements from the next reduced-values
group but skipped the whole group when collecting externally used
values, so a leftover reduced value could be erased while still used
by reduction ops. Merge only groups made solely of extractelements.

Fixes #218709

Reviewers: 

Pull Request: https://github.com/llvm/llvm-project/pull/218734

Added: 
    llvm/test/Transforms/SLPVectorizer/X86/reduced-val-vectorized-in-tree.ll

Modified: 
    llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index e548d205e6dcb..50d81058968d4 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -31099,9 +31099,14 @@ class HorizontalReduction {
         TrackedToOrig.push_back(ReducedVal);
       }
       bool ShuffledExtracts = false;
-      // Try to handle shuffled extractelements.
+      // Try to handle shuffled extractelements. Only pure extractelement
+      // groups can be merged: merged groups are skipped for external uses,
+      // and other values would be erased while still used by reduction ops.
       if (S && S.getOpcode() == Instruction::ExtractElement &&
-          !S.isAltShuffle() && I + 1 < E) {
+          !S.isAltShuffle() && I + 1 < E &&
+          all_of(ReducedVals[I + 1], [&](Value *RV) {
+            return isa<ExtractElementInst>(TrackedVals.at(RV));
+          })) {
         SmallVector<Value *> CommonCandidates(Candidates);
         for (Value *RV : ReducedVals[I + 1]) {
           Value *RdxVal = TrackedVals.at(RV);

diff  --git a/llvm/test/Transforms/SLPVectorizer/X86/reduced-val-vectorized-in-tree.ll b/llvm/test/Transforms/SLPVectorizer/X86/reduced-val-vectorized-in-tree.ll
new file mode 100644
index 0000000000000..c4e23e6e4fa29
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/reduced-val-vectorized-in-tree.ll
@@ -0,0 +1,120 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=slp-vectorizer -S -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
+
+define i64 @test(i64 %d, ptr %a) {
+; CHECK-LABEL: define i64 @test(
+; CHECK-SAME: i64 [[D:%.*]], ptr [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[A]], align 8
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i8, ptr [[TMP0]], i64 24
+; CHECK-NEXT:    [[ARRAYIDX_2:%.*]] = getelementptr i8, ptr [[TMP0]], i64 40
+; CHECK-NEXT:    [[TMP1:%.*]] = load <2 x i64>, ptr [[ARRAYIDX]], align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = insertelement <2 x i64> poison, i64 [[D]], i64 0
+; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <2 x i64> [[TMP2]], <2 x i64> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP4:%.*]] = or <2 x i64> [[TMP3]], <i64 0, i64 1>
+; CHECK-NEXT:    [[TMP5:%.*]] = xor <2 x i64> [[TMP1]], [[TMP4]]
+; CHECK-NEXT:    [[TMP6:%.*]] = or <2 x i64> [[TMP5]], splat (i64 1)
+; CHECK-NEXT:    [[TMP7:%.*]] = shufflevector <2 x i64> [[TMP3]], <2 x i64> <i64 undef, i64 0>, <4 x i32> <i32 0, i32 0, i32 0, i32 3>
+; CHECK-NEXT:    [[TMP8:%.*]] = or <4 x i64> <i64 0, i64 1, i64 1, i64 1>, [[TMP7]]
+; CHECK-NEXT:    [[TMP9:%.*]] = load <4 x i64>, ptr [[ARRAYIDX_2]], align 8
+; CHECK-NEXT:    [[TMP10:%.*]] = xor <4 x i64> [[TMP9]], [[TMP8]]
+; CHECK-NEXT:    [[TMP11:%.*]] = add <4 x i64> [[TMP10]], splat (i64 1)
+; CHECK-NEXT:    [[TMP12:%.*]] = shufflevector <2 x i64> [[TMP6]], <2 x i64> poison, <6 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP13:%.*]] = shufflevector <4 x i64> [[TMP11]], <4 x i64> poison, <6 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP14:%.*]] = shufflevector <6 x i64> [[TMP12]], <6 x i64> [[TMP13]], <6 x i32> <i32 0, i32 1, i32 6, i32 7, i32 8, i32 9>
+; CHECK-NEXT:    store <6 x i64> [[TMP14]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[ARRAYIDX_91:%.*]] = getelementptr i8, ptr [[TMP0]], i64 96
+; CHECK-NEXT:    [[ARRAYIDX_10:%.*]] = getelementptr i8, ptr [[TMP0]], i64 104
+; CHECK-NEXT:    [[TMP15:%.*]] = extractelement <4 x i64> [[TMP11]], i64 0
+; CHECK-NEXT:    [[TMP16:%.*]] = load <4 x i64>, ptr [[ARRAYIDX_91]], align 8
+; CHECK-NEXT:    [[TMP17:%.*]] = load i64, ptr [[ARRAYIDX_10]], align 8
+; CHECK-NEXT:    [[TMP18:%.*]] = shufflevector <2 x i64> [[TMP5]], <2 x i64> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP19:%.*]] = shufflevector <4 x i64> [[TMP11]], <4 x i64> [[TMP18]], <2 x i32> <i32 3, i32 5>
+; CHECK-NEXT:    [[TMP20:%.*]] = shufflevector <2 x i64> [[TMP19]], <2 x i64> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP21:%.*]] = shufflevector <4 x i64> [[TMP11]], <4 x i64> [[TMP20]], <4 x i32> <i32 1, i32 2, i32 4, i32 5>
+; CHECK-NEXT:    [[TMP22:%.*]] = shufflevector <4 x i64> [[TMP21]], <4 x i64> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP23:%.*]] = shufflevector <4 x i64> [[TMP16]], <4 x i64> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT:    [[TMP24:%.*]] = shufflevector <8 x i64> [[TMP22]], <8 x i64> [[TMP23]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11>
+; CHECK-NEXT:    [[TMP25:%.*]] = xor <8 x i64> [[TMP24]], <i64 0, i64 0, i64 0, i64 0, i64 1, i64 1, i64 1, i64 1>
+; CHECK-NEXT:    [[TMP26:%.*]] = add <8 x i64> [[TMP25]], <i64 0, i64 0, i64 0, i64 0, i64 1, i64 1, i64 1, i64 1>
+; CHECK-NEXT:    [[TMP27:%.*]] = extractelement <8 x i64> [[TMP26]], i64 4
+; CHECK-NEXT:    store i64 [[TMP27]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP28:%.*]] = extractelement <8 x i64> [[TMP26]], i64 5
+; CHECK-NEXT:    store i64 [[TMP28]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP29:%.*]] = extractelement <8 x i64> [[TMP26]], i64 6
+; CHECK-NEXT:    store i64 [[TMP29]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP30:%.*]] = extractelement <8 x i64> [[TMP26]], i64 7
+; CHECK-NEXT:    store i64 [[TMP30]], ptr [[A]], align 8
+; CHECK-NEXT:    [[TMP31:%.*]] = call i64 @llvm.vector.reduce.add.v8i64(<8 x i64> [[TMP26]])
+; CHECK-NEXT:    [[OP_RDX:%.*]] = add i64 [[TMP31]], [[TMP15]]
+; CHECK-NEXT:    [[OP_RDX1:%.*]] = add i64 [[OP_RDX]], [[TMP17]]
+; CHECK-NEXT:    ret i64 [[OP_RDX1]]
+;
+entry:
+  %0 = load ptr, ptr %a, align 8
+  %arrayidx = getelementptr i8, ptr %0, i64 24
+  %1 = load i64, ptr %arrayidx, align 8
+  %xor = xor i64 %1, %d
+  %add1 = or i64 %xor, 1
+  store i64 %add1, ptr %0, align 8
+  %arrayidx.1 = getelementptr i8, ptr %0, i64 32
+  %2 = load i64, ptr %arrayidx.1, align 8
+  %add.1 = or i64 %d, 1
+  %xor.1 = xor i64 %2, %add.1
+  %add1.1 = or i64 %xor.1, 1
+  %arrayidx3.1 = getelementptr i8, ptr %0, i64 8
+  store i64 %add1.1, ptr %arrayidx3.1, align 8
+  %arrayidx.2 = getelementptr i8, ptr %0, i64 40
+  %3 = load i64, ptr %arrayidx.2, align 8
+  %xor.2 = xor i64 %3, %d
+  %add1.2 = add i64 %xor.2, 1
+  %arrayidx3.2 = getelementptr i8, ptr %0, i64 16
+  store i64 %add1.2, ptr %arrayidx3.2, align 8
+  %arrayidx.3 = getelementptr i8, ptr %0, i64 48
+  %4 = load i64, ptr %arrayidx.3, align 8
+  %add.3 = or i64 %d, 1
+  %xor.3 = xor i64 %4, %add.3
+  %add1.3 = add i64 %xor.3, 1
+  store i64 %add1.3, ptr %arrayidx, align 8
+  %arrayidx.4 = getelementptr i8, ptr %0, i64 56
+  %5 = load i64, ptr %arrayidx.4, align 8
+  %add.4 = or i64 %d, 1
+  %xor.4 = xor i64 %5, %add.4
+  %add1.4 = add i64 %xor.4, 1
+  store i64 %add1.4, ptr %arrayidx.1, align 8
+  %arrayidx.5 = getelementptr i8, ptr %0, i64 64
+  %6 = load i64, ptr %arrayidx.5, align 8
+  %xor.5 = xor i64 %6, 1
+  %add1.5 = add i64 %xor.5, 1
+  store i64 %add1.5, ptr %arrayidx.2, align 8
+  %arrayidx.91 = getelementptr i8, ptr %0, i64 96
+  %7 = load i64, ptr %arrayidx.91, align 8
+  %xor.9 = xor i64 %7, 1
+  %add1.9 = add i64 %xor.9, 1
+  store i64 %add1.9, ptr %0, align 8
+  %arrayidx.10 = getelementptr i8, ptr %0, i64 104
+  %8 = load i64, ptr %arrayidx.10, align 8
+  %xor.10 = xor i64 %8, 1
+  %add1.10 = add i64 %xor.10, 1
+  store i64 %add1.10, ptr %0, align 8
+  %arrayidx.11 = getelementptr i8, ptr %0, i64 112
+  %9 = load i64, ptr %arrayidx.11, align 8
+  %xor.11 = xor i64 %9, 1
+  %add1.11 = add i64 %xor.11, 1
+  store i64 %add1.11, ptr %0, align 8
+  %arrayidx.12 = getelementptr i8, ptr %0, i64 120
+  %10 = load i64, ptr %arrayidx.12, align 8
+  %xor.12 = xor i64 %10, 1
+  %add1.12 = add i64 %xor.12, 1
+  store i64 %add1.12, ptr %a, align 8
+  %add12.2 = add i64 %xor.1, %add1.2
+  %add12.3 = add i64 %add12.2, %add1.3
+  %add12.4 = add i64 %add12.3, %add1.4
+  %add12.5 = add i64 %add12.4, %add1.5
+  %add12.9 = add i64 %add12.5, %add1.9
+  %add12.10 = add i64 %add12.9, %add1.10
+  %add12.11 = add i64 %add12.10, %add1.11
+  %add12.12 = add i64 %add12.11, %add1.12
+  %add12.13 = add i64 %add12.12, %8
+  ret i64 %add12.13
+}


        


More information about the llvm-commits mailing list