[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