[llvm] [VectorCombine] Fold reduction chains with equivalent bitcast sources (PR #212084)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 10 02:40:28 PDT 2026


https://github.com/RKSimon updated https://github.com/llvm/llvm-project/pull/212084

>From 3d198528021815ff6297739b6a6fd33d8479fac5 Mon Sep 17 00:00:00 2001
From: jpwang <jpwang at smail.nju.edu.cn>
Date: Sun, 26 Jul 2026 03:45:44 +0000
Subject: [PATCH 1/5] [VectorCombine] Recognize reduction chains with
 equivalent bitcast sources

---
 .../Transforms/Vectorize/VectorCombine.cpp    |  22 +++-
 .../fold-shuffle-chains-to-reduce.ll          | 107 ++++++++++++++++++
 2 files changed, 127 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index b5f5cd96f4aa5..9b79c7b98a357 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -4263,15 +4263,33 @@ bool VectorCombine::foldShuffleChainsToReduce(Instruction &I) {
     APInt Elts;
   };
   std::optional<ReductionCut> Cut;
+  auto AreEquivalentBitcastSources = [](Value *V1, Value *V2) {
+    auto *C1 = dyn_cast<BitCastInst>(V1);
+    auto *C2 = dyn_cast<BitCastInst>(V2);
+    return C1 && C2 && C1->getType() == C2->getType() &&
+           C1->getOperand(0) == C2->getOperand(0);
+  };
   for (Value *S : Sources) {
     auto It = Demands.find(S);
     if (It == Demands.end() || It->second.Lanes.isZero())
       continue;
-    if (Cut || (!IsIdempotent && !It->second.Duplicates.isZero())) {
+    if (!IsIdempotent && !It->second.Duplicates.isZero()) {
+      Cut.reset();
+      break;
+    }
+    if (!Cut) {
+      Cut = ReductionCut{S, It->second.Lanes};
+      continue;
+    }
+    if (!AreEquivalentBitcastSources(Cut->Src, S)) {
+      Cut.reset();
+      break;
+    }
+    if (!IsIdempotent && !(Cut->Elts & It->second.Lanes).isZero()) {
       Cut.reset();
       break;
     }
-    Cut = ReductionCut{S, It->second.Lanes};
+    Cut->Elts |= It->second.Lanes;
   }
   if (!Cut) {
     for (Value *V : Nodes) {
diff --git a/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll b/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll
index f00ce63159d17..eb23fecab6102 100644
--- a/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll
+++ b/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll
@@ -435,3 +435,110 @@ define i32 @test_reduce_reconvergent_intermediate_v4i32(<4 x i32> %a) {
   %e = extractelement <2 x i32> %c, i64 0
   ret i32 %e
 }
+
+; Equivalent bitcast sources with disjoint demanded lanes can be merged into
+; one complete reduction.
+define i32 @test_reduce_equivalent_bitcast_sources(<2 x i64> %a) {
+; CHECK-LABEL: define i32 @test_reduce_equivalent_bitcast_sources(
+; CHECK-SAME: <2 x i64> [[A:%.*]]) {
+; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[BC0]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %bc0 = bitcast <2 x i64> %a to <4 x i32>
+  %hi = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 2, i32 3, i32 2, i32 3>
+
+  %bc1 = bitcast <2 x i64> %a to <4 x i32>
+  %sum0 = add <4 x i32> %hi, %bc1
+
+  %sh = shufflevector <4 x i32> %sum0, <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
+  %sum1 = add <4 x i32> %sum0, %sh
+  %r = extractelement <4 x i32> %sum1, i64 0
+  ret i32 %r
+}
+
+; Equivalent sources demand lane 0 through two different paths. Add is not
+; idempotent, so merging the lane sets would lose one contribution.
+define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(
+    <2 x i64> %a) {
+; CHECK-LABEL: define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(
+; CHECK-NOT: @llvm.vector.reduce.add
+; CHECK: ret i32
+;
+  %bc0 = bitcast <2 x i64> %a to <4 x i32>
+  %lhs = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+
+  %bc1 = bitcast <2 x i64> %a to <4 x i32>
+  %rhs = shufflevector <4 x i32> %bc1, <4 x i32> poison, <4 x i32> <i32 0, i32 2, i32 poison, i32 poison>
+
+  %sum0 = add <4 x i32> %lhs, %rhs
+  %sh = shufflevector <4 x i32> %sum0, <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
+  %sum1 = add <4 x i32> %sum0, %sh
+  %r = extractelement <4 x i32> %sum1, i64 0
+  ret i32 %r
+}
+
+; The second equivalent source has an internally duplicated demanded lane.
+; Its lane set does not overlap the first source, so this specifically checks
+; the per-source Duplicates field rather than cross-source overlap.
+define i32 @test_no_reduce_later_equivalent_source_has_duplicates(
+    <2 x i64> %a) {
+; CHECK-LABEL: define i32 @test_no_reduce_later_equivalent_source_has_duplicates(
+; CHECK-NOT: @llvm.vector.reduce.add
+; CHECK: ret i32
+;
+  %bc0 = bitcast <2 x i64> %a to <4 x i32>
+  %lhs = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+
+  %bc1 = bitcast <2 x i64> %a to <4 x i32>
+  %rhs = shufflevector <4 x i32> %bc1, <4 x i32> poison, <4 x i32> <i32 2, i32 2, i32 poison, i32 poison>
+
+  %sum0 = add <4 x i32> %lhs, %rhs
+  %sh = shufflevector <4 x i32> %sum0, <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
+  %sum1 = add <4 x i32> %sum0, %sh
+  %r = extractelement <4 x i32> %sum1, i64 0
+  ret i32 %r
+}
+
+; Bitcasts with the same result type but different underlying values are
+; different logical sources and cannot be merged.
+define i32 @test_no_reduce_different_bitcast_sources(
+    <2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: define i32 @test_no_reduce_different_bitcast_sources(
+; CHECK-NOT: @llvm.vector.reduce.add
+; CHECK: ret i32
+;
+  %bc0 = bitcast <2 x i64> %a to <4 x i32>
+  %hi = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 2, i32 3, i32 2, i32 3>
+
+  %bc1 = bitcast <2 x i64> %b to <4 x i32>
+  %sum0 = add <4 x i32> %hi, %bc1
+
+  %sh = shufflevector <4 x i32> %sum0, <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
+  %sum1 = add <4 x i32> %sum0, %sh
+  %r = extractelement <4 x i32> %sum1, i64 0
+  ret i32 %r
+}
+
+; Overlapping lanes are safe for an idempotent operation.
+define i32 @test_reduce_idempotent_equivalent_bitcast_sources_overlap(
+    <2 x i64> %a) {
+; CHECK-LABEL: define i32 @test_reduce_idempotent_equivalent_bitcast_sources_overlap(
+; CHECK-SAME: <2 x i64> [[A:%.*]]) {
+; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[PARTIAL:%.*]] = shufflevector <4 x i32> [[BC0]], <4 x i32> poison, <3 x i32> <i32 0, i32 1, i32 2>
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.vector.reduce.or.v3i32(<3 x i32> [[PARTIAL]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %bc0 = bitcast <2 x i64> %a to <4 x i32>
+  %lhs = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+
+  %bc1 = bitcast <2 x i64> %a to <4 x i32>
+  %rhs = shufflevector <4 x i32> %bc1, <4 x i32> poison, <4 x i32> <i32 0, i32 2, i32 poison, i32 poison>
+
+  %or0 = or <4 x i32> %lhs, %rhs
+  %sh = shufflevector <4 x i32> %or0, <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
+  %or1 = or <4 x i32> %or0, %sh
+  %r = extractelement <4 x i32> %or1, i64 0
+  ret i32 %r
+}

>From f78fa2b175f4baf1f598aca3effaed131f736676 Mon Sep 17 00:00:00 2001
From: jpwang <jpwang at smail.nju.edu.cn>
Date: Mon, 3 Aug 2026 22:58:57 +0800
Subject: [PATCH 2/5] Update tests

---
 .../fold-shuffle-chains-to-reduce.ll          | 43 ++++++++++++++-----
 1 file changed, 33 insertions(+), 10 deletions(-)

diff --git a/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll b/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll
index eb23fecab6102..d401f5e452f2a 100644
--- a/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll
+++ b/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll
@@ -460,11 +460,19 @@ define i32 @test_reduce_equivalent_bitcast_sources(<2 x i64> %a) {
 ; Equivalent sources demand lane 0 through two different paths. Add is not
 ; idempotent, so merging the lane sets would lose one contribution.
 define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(
-    <2 x i64> %a) {
 ; CHECK-LABEL: define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(
-; CHECK-NOT: @llvm.vector.reduce.add
-; CHECK: ret i32
+; CHECK-SAME: <2 x i64> [[A:%.*]]) {
+; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[LHS:%.*]] = shufflevector <4 x i32> [[BC0]], <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[RHS:%.*]] = shufflevector <4 x i32> [[BC1]], <4 x i32> poison, <4 x i32> <i32 0, i32 2, i32 poison, i32 poison>
+; CHECK-NEXT:    [[SUM0:%.*]] = add <4 x i32> [[LHS]], [[RHS]]
+; CHECK-NEXT:    [[SH:%.*]] = shufflevector <4 x i32> [[SUM0]], <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT:    [[SUM1:%.*]] = add <4 x i32> [[SUM0]], [[SH]]
+; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[SUM1]], i64 0
+; CHECK-NEXT:    ret i32 [[R]]
 ;
+  <2 x i64> %a) {
   %bc0 = bitcast <2 x i64> %a to <4 x i32>
   %lhs = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
 
@@ -482,11 +490,19 @@ define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(
 ; Its lane set does not overlap the first source, so this specifically checks
 ; the per-source Duplicates field rather than cross-source overlap.
 define i32 @test_no_reduce_later_equivalent_source_has_duplicates(
-    <2 x i64> %a) {
 ; CHECK-LABEL: define i32 @test_no_reduce_later_equivalent_source_has_duplicates(
-; CHECK-NOT: @llvm.vector.reduce.add
-; CHECK: ret i32
+; CHECK-SAME: <2 x i64> [[A:%.*]]) {
+; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[LHS:%.*]] = shufflevector <4 x i32> [[BC0]], <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[RHS:%.*]] = shufflevector <4 x i32> [[BC1]], <4 x i32> poison, <4 x i32> <i32 2, i32 2, i32 poison, i32 poison>
+; CHECK-NEXT:    [[SUM0:%.*]] = add <4 x i32> [[LHS]], [[RHS]]
+; CHECK-NEXT:    [[SH:%.*]] = shufflevector <4 x i32> [[SUM0]], <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT:    [[SUM1:%.*]] = add <4 x i32> [[SUM0]], [[SH]]
+; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[SUM1]], i64 0
+; CHECK-NEXT:    ret i32 [[R]]
 ;
+  <2 x i64> %a) {
   %bc0 = bitcast <2 x i64> %a to <4 x i32>
   %lhs = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
 
@@ -503,11 +519,18 @@ define i32 @test_no_reduce_later_equivalent_source_has_duplicates(
 ; Bitcasts with the same result type but different underlying values are
 ; different logical sources and cannot be merged.
 define i32 @test_no_reduce_different_bitcast_sources(
-    <2 x i64> %a, <2 x i64> %b) {
 ; CHECK-LABEL: define i32 @test_no_reduce_different_bitcast_sources(
-; CHECK-NOT: @llvm.vector.reduce.add
-; CHECK: ret i32
+; CHECK-SAME: <2 x i64> [[A:%.*]], <2 x i64> [[B:%.*]]) {
+; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
+; CHECK-NEXT:    [[HI:%.*]] = shufflevector <4 x i32> [[BC0]], <4 x i32> poison, <4 x i32> <i32 2, i32 3, i32 2, i32 3>
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast <2 x i64> [[B]] to <4 x i32>
+; CHECK-NEXT:    [[SUM0:%.*]] = add <4 x i32> [[HI]], [[BC1]]
+; CHECK-NEXT:    [[SH:%.*]] = shufflevector <4 x i32> [[SUM0]], <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 poison, i32 poison>
+; CHECK-NEXT:    [[SUM1:%.*]] = add <4 x i32> [[SUM0]], [[SH]]
+; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[SUM1]], i64 0
+; CHECK-NEXT:    ret i32 [[R]]
 ;
+  <2 x i64> %a, <2 x i64> %b) {
   %bc0 = bitcast <2 x i64> %a to <4 x i32>
   %hi = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 2, i32 3, i32 2, i32 3>
 
@@ -522,7 +545,6 @@ define i32 @test_no_reduce_different_bitcast_sources(
 
 ; Overlapping lanes are safe for an idempotent operation.
 define i32 @test_reduce_idempotent_equivalent_bitcast_sources_overlap(
-    <2 x i64> %a) {
 ; CHECK-LABEL: define i32 @test_reduce_idempotent_equivalent_bitcast_sources_overlap(
 ; CHECK-SAME: <2 x i64> [[A:%.*]]) {
 ; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
@@ -530,6 +552,7 @@ define i32 @test_reduce_idempotent_equivalent_bitcast_sources_overlap(
 ; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.vector.reduce.or.v3i32(<3 x i32> [[PARTIAL]])
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
+  <2 x i64> %a) {
   %bc0 = bitcast <2 x i64> %a to <4 x i32>
   %lhs = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
 

>From 468fa75268e3d92a66527e082d6172b484c8d0ef Mon Sep 17 00:00:00 2001
From: jpwang <jpwang at smail.nju.edu.cn>
Date: Mon, 3 Aug 2026 23:03:22 +0800
Subject: [PATCH 3/5] Update tests

---
 .../VectorCombine/fold-shuffle-chains-to-reduce.ll   | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll b/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll
index d401f5e452f2a..d38d5bef6dd18 100644
--- a/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll
+++ b/llvm/test/Transforms/VectorCombine/fold-shuffle-chains-to-reduce.ll
@@ -459,7 +459,7 @@ define i32 @test_reduce_equivalent_bitcast_sources(<2 x i64> %a) {
 
 ; Equivalent sources demand lane 0 through two different paths. Add is not
 ; idempotent, so merging the lane sets would lose one contribution.
-define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(
+define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(<2 x i64> %a) {
 ; CHECK-LABEL: define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(
 ; CHECK-SAME: <2 x i64> [[A:%.*]]) {
 ; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
@@ -472,7 +472,6 @@ define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(
 ; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[SUM1]], i64 0
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
-  <2 x i64> %a) {
   %bc0 = bitcast <2 x i64> %a to <4 x i32>
   %lhs = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
 
@@ -489,7 +488,7 @@ define i32 @test_no_reduce_equivalent_bitcast_sources_overlap(
 ; The second equivalent source has an internally duplicated demanded lane.
 ; Its lane set does not overlap the first source, so this specifically checks
 ; the per-source Duplicates field rather than cross-source overlap.
-define i32 @test_no_reduce_later_equivalent_source_has_duplicates(
+define i32 @test_no_reduce_later_equivalent_source_has_duplicates(<2 x i64> %a) {
 ; CHECK-LABEL: define i32 @test_no_reduce_later_equivalent_source_has_duplicates(
 ; CHECK-SAME: <2 x i64> [[A:%.*]]) {
 ; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
@@ -502,7 +501,6 @@ define i32 @test_no_reduce_later_equivalent_source_has_duplicates(
 ; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[SUM1]], i64 0
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
-  <2 x i64> %a) {
   %bc0 = bitcast <2 x i64> %a to <4 x i32>
   %lhs = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
 
@@ -518,7 +516,7 @@ define i32 @test_no_reduce_later_equivalent_source_has_duplicates(
 
 ; Bitcasts with the same result type but different underlying values are
 ; different logical sources and cannot be merged.
-define i32 @test_no_reduce_different_bitcast_sources(
+define i32 @test_no_reduce_different_bitcast_sources(<2 x i64> %a, <2 x i64> %b) {
 ; CHECK-LABEL: define i32 @test_no_reduce_different_bitcast_sources(
 ; CHECK-SAME: <2 x i64> [[A:%.*]], <2 x i64> [[B:%.*]]) {
 ; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
@@ -530,7 +528,6 @@ define i32 @test_no_reduce_different_bitcast_sources(
 ; CHECK-NEXT:    [[R:%.*]] = extractelement <4 x i32> [[SUM1]], i64 0
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
-  <2 x i64> %a, <2 x i64> %b) {
   %bc0 = bitcast <2 x i64> %a to <4 x i32>
   %hi = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 2, i32 3, i32 2, i32 3>
 
@@ -544,7 +541,7 @@ define i32 @test_no_reduce_different_bitcast_sources(
 }
 
 ; Overlapping lanes are safe for an idempotent operation.
-define i32 @test_reduce_idempotent_equivalent_bitcast_sources_overlap(
+define i32 @test_reduce_idempotent_equivalent_bitcast_sources_overlap(<2 x i64> %a) {
 ; CHECK-LABEL: define i32 @test_reduce_idempotent_equivalent_bitcast_sources_overlap(
 ; CHECK-SAME: <2 x i64> [[A:%.*]]) {
 ; CHECK-NEXT:    [[BC0:%.*]] = bitcast <2 x i64> [[A]] to <4 x i32>
@@ -552,7 +549,6 @@ define i32 @test_reduce_idempotent_equivalent_bitcast_sources_overlap(
 ; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.vector.reduce.or.v3i32(<3 x i32> [[PARTIAL]])
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
-  <2 x i64> %a) {
   %bc0 = bitcast <2 x i64> %a to <4 x i32>
   %lhs = shufflevector <4 x i32> %bc0, <4 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
 

>From 826b2ae9c046a3655882b75c83215e835d3e242a Mon Sep 17 00:00:00 2001
From: jpwang <jpwang at smail.nju.edu.cn>
Date: Fri, 7 Aug 2026 00:17:58 +0800
Subject: [PATCH 4/5] Use peekThroughBitcasts for generality

---
 .../Transforms/Vectorize/VectorCombine.cpp    | 24 +++++++------------
 1 file changed, 9 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 9b79c7b98a357..c596b789a21ca 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -219,6 +219,12 @@ static Value *peekThroughBitcasts(Value *V) {
   return V;
 }
 
+/// Helper to peek through bitcasts to the same value.
+static bool isEquivBitcast(Value *X, Value *Y) {
+  return X->getType() == Y->getType() &&
+          peekThroughBitcasts(X) == peekThroughBitcasts(Y);
+}
+
 static bool canWidenLoad(LoadInst *Load, const TargetTransformInfo &TTI) {
   // Do not widen load if atomic/volatile or under asan/hwasan/memtag/tsan.
   // The widened load may load data from dirty regions or create data races
@@ -3740,19 +3746,13 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
     if (!FrontV)
       return false;
 
-    // Helper to peek through bitcasts to the same value.
-    auto IsEquiv = [&](Value *X, Value *Y) {
-      return X->getType() == Y->getType() &&
-             peekThroughBitcasts(X) == peekThroughBitcasts(Y);
-    };
-
     // Look for an identity value.
     if (FrontLane == 0 &&
         cast<FixedVectorType>(FrontV->getType())->getNumElements() ==
             Item.size() &&
-        all_of(drop_begin(enumerate(Item)), [IsEquiv, Item](const auto &E) {
+        all_of(drop_begin(enumerate(Item)), [Item](const auto &E) {
           Value *FrontV = Item.front().first;
-          return !E.value().first || (IsEquiv(E.value().first, FrontV) &&
+          return !E.value().first || (isEquivBitcast(E.value().first, FrontV) &&
                                       E.value().second == (int)E.index());
         })) {
       IdentityLeafs.insert(std::make_pair(FrontV, From));
@@ -4263,12 +4263,6 @@ bool VectorCombine::foldShuffleChainsToReduce(Instruction &I) {
     APInt Elts;
   };
   std::optional<ReductionCut> Cut;
-  auto AreEquivalentBitcastSources = [](Value *V1, Value *V2) {
-    auto *C1 = dyn_cast<BitCastInst>(V1);
-    auto *C2 = dyn_cast<BitCastInst>(V2);
-    return C1 && C2 && C1->getType() == C2->getType() &&
-           C1->getOperand(0) == C2->getOperand(0);
-  };
   for (Value *S : Sources) {
     auto It = Demands.find(S);
     if (It == Demands.end() || It->second.Lanes.isZero())
@@ -4281,7 +4275,7 @@ bool VectorCombine::foldShuffleChainsToReduce(Instruction &I) {
       Cut = ReductionCut{S, It->second.Lanes};
       continue;
     }
-    if (!AreEquivalentBitcastSources(Cut->Src, S)) {
+    if (!isEquivBitcast(Cut->Src, S)) {
       Cut.reset();
       break;
     }

>From 4fee22e998f6a26f938548cfc959cd4ca26877dd Mon Sep 17 00:00:00 2001
From: jpwang <jpwang at smail.nju.edu.cn>
Date: Mon, 10 Aug 2026 17:33:05 +0800
Subject: [PATCH 5/5] fix style issue

---
 llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index c792badb03d96..b88472f69c548 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -222,7 +222,7 @@ static Value *peekThroughBitcasts(Value *V) {
 /// Helper to peek through bitcasts to the same value.
 static bool isEquivBitcast(Value *X, Value *Y) {
   return X->getType() == Y->getType() &&
-          peekThroughBitcasts(X) == peekThroughBitcasts(Y);
+         peekThroughBitcasts(X) == peekThroughBitcasts(Y);
 }
 
 static bool canWidenLoad(LoadInst *Load, const TargetTransformInfo &TTI) {



More information about the llvm-commits mailing list