[llvm] [InstCombine] Fold icmp in select to smin (PR #196823)
via llvm-commits
llvm-commits at lists.llvm.org
Sun May 10 10:59:05 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Krishna Narayanan (Krishna-13-cyber)
<details>
<summary>Changes</summary>
This PR is in continuation to the PR #<!-- -->87157 which remains stale for quite some time, https://github.com/llvm/llvm-project/pull/87157. This PR intends to solve this issue https://github.com/llvm/llvm-project/issues/85844.
---
Full diff: https://github.com/llvm/llvm-project/pull/196823.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp (+47)
- (modified) llvm/test/Transforms/InstCombine/icmp-select.ll (+111)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 82954ee6f2457..d36c839b18b49 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2100,6 +2100,50 @@ static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI,
return nullptr;
}
+// a > -1 ? 1 : ( a | (+ve)value) --> smin(1, a | (+ve)value)
+// a < -1 ? ( a | (+ve)value) : 1 --> smin(1, a | (+ve)value)
+static Value *foldSelectInstWithICmpOr(SelectInst &SI, ICmpInst *ICI,
+ InstCombiner::BuilderTy &Builder,
+ const SimplifyQuery &SQ) {
+ Value *A = ICI->getOperand(0);
+ Value *B = ICI->getOperand(1);
+ Value *TVal = SI.getTrueValue();
+ Value *FVal = SI.getFalseValue();
+ ICmpInst::Predicate Pred = ICI->getPredicate();
+
+ if (!((Pred == ICmpInst::ICMP_SLT && match(B, m_Zero())) ||
+ (Pred == ICmpInst::ICMP_SLE && match(B, m_AllOnes())) ||
+ (Pred == ICmpInst::ICMP_SGT && match(B, m_AllOnes())) ||
+ (Pred == ICmpInst::ICMP_SGE && match(B, m_Zero()))))
+ return nullptr;
+
+
+ Value *OrVal, *ConstVal;
+ if ((Pred == ICmpInst::ICMP_SLT && match(B, m_Zero())) ||
+ (Pred == ICmpInst::ICMP_SLE && match(B, m_AllOnes()))) {
+ OrVal = TVal;
+ ConstVal = FVal;
+ } else {
+ OrVal = FVal;
+ ConstVal = TVal;
+ }
+
+ if (!match(ConstVal, m_Zero()) && !match(ConstVal, m_One()))
+ return nullptr;
+
+ Value *X, *Mask;
+ if (!match(OrVal, m_Or(m_Value(X), m_Value(Mask))))
+ return nullptr;
+
+ if (X != A)
+ return nullptr;
+
+ if (!isKnownNonNegative(Mask, SQ))
+ return nullptr;
+
+ return Builder.CreateBinaryIntrinsic(Intrinsic::smin, OrVal, ConstVal);
+}
+
/// `A == MIN_INT ? B != MIN_INT : A < B` --> `A < B`
/// `A == MAX_INT ? B != MAX_INT : A > B` --> `A > B`
static Instruction *foldSelectWithExtremeEqCond(Value *CmpLHS, Value *CmpRHS,
@@ -2321,6 +2365,9 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
if (Value *V = foldSelectInstWithICmpConst(SI, ICI, Builder))
return replaceInstUsesWith(SI, V);
+ if (Value *V = foldSelectInstWithICmpOr(SI, ICI, Builder, SQ))
+ return replaceInstUsesWith(SI, V);
+
if (Value *V = canonicalizeClampLike(SI, *ICI, Builder, *this))
return replaceInstUsesWith(SI, V);
diff --git a/llvm/test/Transforms/InstCombine/icmp-select.ll b/llvm/test/Transforms/InstCombine/icmp-select.ll
index 4b24f423841f0..25d8da72d1b1c 100644
--- a/llvm/test/Transforms/InstCombine/icmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-select.ll
@@ -959,6 +959,117 @@ end:
!0 = !{!"function_entry_count", i64 1000}
!1 = !{!"branch_weights", i32 2, i32 3}
!2 = !{!"branch_weights", i32 5, i32 7}
+
+
+define i8 @icmp_pos_sgt_select_or(i8 %inl, i8 %y) {
+; CHECK-LABEL: @icmp_pos_sgt_select_or(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 8
+; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[OR]], i8 1)
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 %inl, 8
+ %cmp = icmp sgt i8 %inl, -1
+ %s = select i1 %cmp, i8 1, i8 %or
+ ret i8 %s
+}
+
+define i8 @icmp_pos_sgt_select_or1(i8 %inl, i8 %y) {
+; CHECK-LABEL: @icmp_pos_sgt_select_or1(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 25
+; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[OR]], i8 0)
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 %inl, 25
+ %cmp = icmp sgt i8 %inl, -1
+ %s = select i1 %cmp, i8 0, i8 %or
+ ret i8 %s
+}
+
+define i8 @icmp_pos_sge_select_or(i8 %inl, i8 %y) {
+; CHECK-LABEL: @icmp_pos_sge_select_or(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 2
+; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[OR]], i8 1)
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 %inl, 2
+ %cmp = icmp sge i8 %inl, 0
+ %s = select i1 %cmp, i8 1, i8 %or
+ ret i8 %s
+}
+
+define i8 @icmp_pos_sgt_select_or_commuted_op(i8 %inl, i8 %y) {
+; CHECK-LABEL: @icmp_pos_sgt_select_or_commuted_op(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 8
+; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[OR]], i8 1)
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 8, %inl
+ %cmp = icmp sgt i8 %inl, -1
+ %s = select i1 %cmp, i8 1, i8 %or
+ ret i8 %s
+}
+
+define i8 @icmp_pos_sgt_select_or_commuted_select(i8 %inl, i8 %y) {
+; CHECK-LABEL: @icmp_pos_sgt_select_or_commuted_select(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 8
+; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[OR]], i8 1)
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 %inl, 8
+ %cmp = icmp sle i8 %inl, -1
+ %s = select i1 %cmp, i8 %or, i8 1
+ ret i8 %s
+}
+
+define i8 @icmp_slt_select_or(i8 %inl) {
+; CHECK-LABEL: @icmp_slt_select_or(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 8
+; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[OR]], i8 1)
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 %inl, 8
+ %cmp = icmp slt i8 %inl, 0
+ %s = select i1 %cmp, i8 %or, i8 1
+ ret i8 %s
+}
+
+define i8 @icmp_sle_select_or(i8 %inl) {
+; CHECK-LABEL: @icmp_sle_select_or(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 15
+; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[OR]], i8 0)
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 %inl, 15
+ %cmp = icmp sle i8 %inl, -1
+ %s = select i1 %cmp, i8 %or, i8 0
+ ret i8 %s
+}
+
+define i8 @icmp_neg_slt_select_or(i8 %inl, i8 %y) {
+; CHECK-LABEL: @icmp_neg_slt_select_or(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 8
+; CHECK-NEXT: [[S:%.*]] = call i8 @llvm.smin.i8(i8 [[OR]], i8 1)
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 %inl, 8
+ %cmp = icmp slt i8 %inl, 0
+ %s = select i1 %cmp, i8 %or, i8 1
+ ret i8 %s
+}
+
+define i8 @icmp_pos_sgt_diff_const(i8 %inl, i8 %y) {
+; CHECK-LABEL: @icmp_pos_sgt_diff_const(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 8
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[INL]], 1
+; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 1, i8 [[OR]]
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 %inl, 8
+ %cmp = icmp sgt i8 %inl, 1
+ %s = select i1 %cmp, i8 1, i8 %or
+ ret i8 %s
+}
+
;.
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nocreateundeforpoison nofree nosync nounwind speculatable willreturn memory(none) }
;.
``````````
</details>
https://github.com/llvm/llvm-project/pull/196823
More information about the llvm-commits
mailing list