[llvm] [InstCombine] Fold select chain to frozen bool reduction (PR #217482)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 19 17:01:25 PDT 2026
https://github.com/user1342234 updated https://github.com/llvm/llvm-project/pull/217482
>From ffcd4f7397b9f090e35bdeb3564784f7fdcaa64f Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Wed, 19 Aug 2026 15:23:56 -0700
Subject: [PATCH 1/3] Precommit tests
---
llvm/test/Transforms/InstCombine/select.ll | 103 +++++++++++++++++++++
1 file changed, 103 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index a1e84fad9a827..31e0d09eef874 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -5800,3 +5800,106 @@ entry:
call void @use_v2i64(<2 x i64> %neg)
ret <2 x i64> %r
}
+
+define i1 @select_chain_reduce_bitcast_icmp(<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: define i1 @select_chain_reduce_bitcast_icmp(
+; CHECK-SAME: <2 x i4> [[X:%.*]], <2 x i4> [[Y:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i4> [[X]], [[Y]]
+; CHECK-NEXT: [[B0:%.*]] = extractelement <2 x i1> [[CMP]], i64 0
+; CHECK-NEXT: [[B1:%.*]] = extractelement <2 x i1> [[CMP]], i64 1
+; CHECK-NEXT: [[B:%.*]] = select i1 [[B0]], i1 [[B1]], i1 false
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %cmp = icmp sgt <2 x i4> %x, %y
+ %b0 = extractelement <2 x i1> %cmp, i64 0
+ %b1 = extractelement <2 x i1> %cmp, i64 1
+ %b = select i1 %b0, i1 %b1, i1 0
+ ret i1 %b
+}
+
+define i1 @select_chain_missing_lane(<4 x i4> %x, <4 x i4> %y) {
+; CHECK-LABEL: define i1 @select_chain_missing_lane(
+; CHECK-SAME: <4 x i4> [[X:%.*]], <4 x i4> [[Y:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <4 x i4> [[X]], [[Y]]
+; CHECK-NEXT: [[B0:%.*]] = extractelement <4 x i1> [[CMP]], i64 0
+; CHECK-NEXT: [[B2:%.*]] = extractelement <4 x i1> [[CMP]], i64 2
+; CHECK-NEXT: [[B:%.*]] = select i1 [[B0]], i1 [[B2]], i1 false
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %cmp = icmp sgt <4 x i4> %x, %y
+ %b0 = extractelement <4 x i1> %cmp, i64 0
+ %b2 = extractelement <4 x i1> %cmp, i64 2
+ %b = select i1 %b0, i1 %b2, i1 false ; only 2 of 4 lanes covered
+ ret i1 %b
+}
+
+; Negative test
+define i1 @select_chain_wrong_false_val(<2 x i4> %x, <2 x i4> %y, i1 %z) {
+; CHECK-LABEL: define i1 @select_chain_wrong_false_val(
+; CHECK-SAME: <2 x i4> [[X:%.*]], <2 x i4> [[Y:%.*]], i1 [[Z:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i4> [[X]], [[Y]]
+; CHECK-NEXT: [[B0:%.*]] = extractelement <2 x i1> [[CMP]], i64 0
+; CHECK-NEXT: [[B1:%.*]] = extractelement <2 x i1> [[CMP]], i64 1
+; CHECK-NEXT: [[B:%.*]] = select i1 [[B0]], i1 [[B1]], i1 [[Z]]
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %cmp = icmp sgt <2 x i4> %x, %y
+ %b0 = extractelement <2 x i1> %cmp, i64 0
+ %b1 = extractelement <2 x i1> %cmp, i64 1
+ %b = select i1 %b0, i1 %b1, i1 %z
+ ret i1 %b
+}
+; Negative test
+define i1 @select_chain_different_vectors(<2 x i4> %x, <2 x i4> %y, <2 x i4> %z, <2 x i4> %w) {
+; CHECK-LABEL: define i1 @select_chain_different_vectors(
+; CHECK-SAME: <2 x i4> [[X:%.*]], <2 x i4> [[Y:%.*]], <2 x i4> [[Z:%.*]], <2 x i4> [[W:%.*]]) {
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt <2 x i4> [[X]], [[Y]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt <2 x i4> [[Z]], [[W]]
+; CHECK-NEXT: [[B0:%.*]] = extractelement <2 x i1> [[CMP0]], i64 0
+; CHECK-NEXT: [[B1:%.*]] = extractelement <2 x i1> [[CMP1]], i64 1
+; CHECK-NEXT: [[B:%.*]] = select i1 [[B0]], i1 [[B1]], i1 false
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %cmp0 = icmp sgt <2 x i4> %x, %y
+ %cmp1 = icmp sgt <2 x i4> %z, %w
+ %b0 = extractelement <2 x i1> %cmp0, i64 0
+ %b1 = extractelement <2 x i1> %cmp1, i64 1
+ %b = select i1 %b0, i1 %b1, i1 false
+ ret i1 %b
+}
+
+; Negative test
+define i1 @select_chain_duplicate_lane(<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: define i1 @select_chain_duplicate_lane(
+; CHECK-SAME: <2 x i4> [[X:%.*]], <2 x i4> [[Y:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i4> [[X]], [[Y]]
+; CHECK-NEXT: [[B0A:%.*]] = extractelement <2 x i1> [[CMP]], i64 0
+; CHECK-NEXT: [[B0B:%.*]] = extractelement <2 x i1> [[CMP]], i64 0
+; CHECK-NEXT: [[B:%.*]] = select i1 [[B0A]], i1 [[B0B]], i1 false
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %cmp = icmp sgt <2 x i4> %x, %y
+ %b0a = extractelement <2 x i1> %cmp, i64 0
+ %b0b = extractelement <2 x i1> %cmp, i64 0
+ %b = select i1 %b0a, i1 %b0b, i1 false ; index 0 used twice
+ ret i1 %b
+}
+
+; Negative test
+define i1 @select_chain_scalable_vector(<vscale x 2 x i4> %x, <vscale x 2 x i4> %y) {
+; CHECK-LABEL: define i1 @select_chain_scalable_vector(
+; CHECK-SAME: <vscale x 2 x i4> [[X:%.*]], <vscale x 2 x i4> [[Y:%.*]]) {
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <vscale x 2 x i4> [[X]], [[Y]]
+; CHECK-NEXT: [[B0:%.*]] = extractelement <vscale x 2 x i1> [[CMP]], i64 0
+; CHECK-NEXT: [[B1:%.*]] = extractelement <vscale x 2 x i1> [[CMP]], i64 1
+; CHECK-NEXT: [[B:%.*]] = select i1 [[B0]], i1 [[B1]], i1 false
+; CHECK-NEXT: ret i1 [[B]]
+;
+ %cmp = icmp sgt <vscale x 2 x i4> %x, %y
+ %b0 = extractelement <vscale x 2 x i1> %cmp, i64 0
+ %b1 = extractelement <vscale x 2 x i1> %cmp, i64 1
+ %b = select i1 %b0, i1 %b1, i1 false
+ ret i1 %b
+}
+
+
>From 64df0275e87bb6e2b60de1d8578d1423e5b0bc27 Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Wed, 19 Aug 2026 15:30:56 -0700
Subject: [PATCH 2/3] fold select chain to bitcast+icmp
---
.../InstCombine/InstCombineSelect.cpp | 60 +++++++++++++++++++
llvm/test/Transforms/InstCombine/select.ll | 13 ++--
2 files changed, 67 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 090abfaea28ec..2d8e4f6bd5426 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -4582,6 +4582,63 @@ static bool isSelectZeroSignInsignificant(SelectInst &SI) {
return true;
}
+static Instruction *foldSelectExtractEl(SelectInst &SI,
+ InstCombiner::BuilderTy &Builder) {
+ // select (extractelement (icmp Pred X, Y), C1)
+ // (extractelement (icmp Pred X, Y) C2), 0
+ // ->
+ // icmp eq (bitcast (freeze (icmp Pred X, Y)) to iN), C3
+ Value *X;
+ Value *Y;
+ CmpPredicate Pred1, Pred2;
+ const APInt *C1, *C2;
+ if (match(&SI,
+ m_Select(m_ExtractElt(m_ICmp(Pred1, m_Value(X), m_Value(Y)),
+ m_APInt(C1)),
+ m_ExtractElt(m_ICmp(Pred2, m_Deferred(X), m_Deferred(Y)),
+ m_APInt(C2)),
+ m_Zero()))
+
+ ) {
+ // Make sure we're operating on the same comparison
+ auto MatchedPred = CmpPredicate::getMatching(Pred1, Pred2);
+ if (!MatchedPred)
+ return nullptr;
+
+ // Extract values and check if we're operating on the same predicate
+ auto *Ext0 = cast<ExtractElementInst>(SI.getCondition());
+ auto *Ext1 = cast<ExtractElementInst>(SI.getTrueValue());
+ Value *Cmp = Ext0->getVectorOperand();
+ if (Ext1->getVectorOperand() != Cmp)
+ return nullptr;
+
+ auto *VecTy = dyn_cast_or_null<FixedVectorType>(Cmp->getType());
+ if (!VecTy)
+ return nullptr;
+ unsigned NumElts = VecTy->getNumElements();
+
+ // Check range bounds and redundant case where indices are equal
+ uint64_t Idx1 = C1->getZExtValue();
+ uint64_t Idx2 = C2->getZExtValue();
+ if (Idx1 == Idx2 || Idx1 >= NumElts || Idx2 >= NumElts)
+ return nullptr;
+
+ // Build a mask (C3) with only tested lanes set
+ APInt C3 = APInt::getZero(NumElts);
+ C3.setBit(Idx1);
+ C3.setBit(Idx2);
+
+ Value *Frozen = Builder.CreateFreeze(Cmp);
+ Value *BC = Builder.CreateBitCast(Frozen, Builder.getIntNTy(NumElts));
+ Value *Masked = Builder.CreateAnd(BC, ConstantInt::get(BC->getType(), C3));
+
+ return new ICmpInst(ICmpInst::ICMP_EQ, Masked,
+ ConstantInt::get(BC->getType(), C3));
+ }
+
+ return nullptr;
+}
+
Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
Value *CondVal = SI.getCondition();
Value *TrueVal = SI.getTrueValue();
@@ -4638,6 +4695,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
if (Instruction *R = foldSelectOfBools(SI))
return R;
+ if (Instruction *R = foldSelectExtractEl(SI, Builder))
+ return R;
+
// Selecting between two integer or vector splat integer constants?
//
// Note that we don't handle a scalar select of vectors:
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 31e0d09eef874..24404e177d52c 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -5805,9 +5805,9 @@ define i1 @select_chain_reduce_bitcast_icmp(<2 x i4> %x, <2 x i4> %y) {
; CHECK-LABEL: define i1 @select_chain_reduce_bitcast_icmp(
; CHECK-SAME: <2 x i4> [[X:%.*]], <2 x i4> [[Y:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i4> [[X]], [[Y]]
-; CHECK-NEXT: [[B0:%.*]] = extractelement <2 x i1> [[CMP]], i64 0
-; CHECK-NEXT: [[B1:%.*]] = extractelement <2 x i1> [[CMP]], i64 1
-; CHECK-NEXT: [[B:%.*]] = select i1 [[B0]], i1 [[B1]], i1 false
+; CHECK-NEXT: [[TMP1:%.*]] = freeze <2 x i1> [[CMP]]
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i1> [[TMP1]] to i2
+; CHECK-NEXT: [[B:%.*]] = icmp eq i2 [[TMP2]], -1
; CHECK-NEXT: ret i1 [[B]]
;
%cmp = icmp sgt <2 x i4> %x, %y
@@ -5821,9 +5821,10 @@ define i1 @select_chain_missing_lane(<4 x i4> %x, <4 x i4> %y) {
; CHECK-LABEL: define i1 @select_chain_missing_lane(
; CHECK-SAME: <4 x i4> [[X:%.*]], <4 x i4> [[Y:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <4 x i4> [[X]], [[Y]]
-; CHECK-NEXT: [[B0:%.*]] = extractelement <4 x i1> [[CMP]], i64 0
-; CHECK-NEXT: [[B2:%.*]] = extractelement <4 x i1> [[CMP]], i64 2
-; CHECK-NEXT: [[B:%.*]] = select i1 [[B0]], i1 [[B2]], i1 false
+; CHECK-NEXT: [[TMP1:%.*]] = freeze <4 x i1> [[CMP]]
+; CHECK-NEXT: [[TMP2:%.*]] = bitcast <4 x i1> [[TMP1]] to i4
+; CHECK-NEXT: [[TMP3:%.*]] = and i4 [[TMP2]], 5
+; CHECK-NEXT: [[B:%.*]] = icmp eq i4 [[TMP3]], 5
; CHECK-NEXT: ret i1 [[B]]
;
%cmp = icmp sgt <4 x i4> %x, %y
>From 681d7f9282ac54951f69ef18f449d3018f3e0804 Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Wed, 19 Aug 2026 17:00:40 -0700
Subject: [PATCH 3/3] Fixed correctness issue and added a test
---
.../InstCombine/InstCombineSelect.cpp | 2 ++
llvm/test/Transforms/InstCombine/select.ll | 19 ++++++++++++++++++-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 2d8e4f6bd5426..0dae8e8b12cc5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -4616,6 +4616,8 @@ static Instruction *foldSelectExtractEl(SelectInst &SI,
if (!VecTy)
return nullptr;
unsigned NumElts = VecTy->getNumElements();
+ if (NumElts > IntegerType::MAX_INT_BITS)
+ return nullptr;
// Check range bounds and redundant case where indices are equal
uint64_t Idx1 = C1->getZExtValue();
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 24404e177d52c..0785093d8f2d9 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -5903,4 +5903,21 @@ define i1 @select_chain_scalable_vector(<vscale x 2 x i4> %x, <vscale x 2 x i4>
ret i1 %b
}
-
+; Negative test
+define i1 @select_chain_large_vec(<8388609 x i4> %x, <8388609 x i4> %y) {
+; CHECK-LABEL: define i1 @select_chain_large_vec(
+; CHECK-SAME: <8388609 x i4> [[X:%.*]], <8388609 x i4> [[Y:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <8388609 x i4> [[X]], [[Y]]
+; CHECK-NEXT: [[B0:%.*]] = extractelement <8388609 x i1> [[CMP]], i64 0
+; CHECK-NEXT: [[B1:%.*]] = extractelement <8388609 x i1> [[CMP]], i64 1
+; CHECK-NEXT: [[B:%.*]] = select i1 [[B0]], i1 [[B1]], i1 false
+; CHECK-NEXT: ret i1 [[B]]
+;
+entry:
+ %cmp = icmp sgt <8388609 x i4> %x, %y
+ %b0 = extractelement <8388609 x i1> %cmp, i64 0
+ %b1 = extractelement <8388609 x i1> %cmp, i64 1
+ %b = select i1 %b0, i1 %b1, i1 false
+ ret i1 %b
+}
More information about the llvm-commits
mailing list