Skip to content

Conversation

@YLChenZ
Copy link
Contributor

@YLChenZ YLChenZ commented Apr 22, 2025

@YLChenZ YLChenZ requested a review from nikic as a code owner April 22, 2025 05:46
@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms labels Apr 22, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 22, 2025

@llvm/pr-subscribers-llvm-transforms

Author: None (YLChenZ)

Changes

Closes #132508.
Proof: https://alive2.llvm.org/ce/z/AjmXuN.


Full diff: https://github.com/llvm/llvm-project/pull/136654.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+25)
  • (modified) llvm/test/Transforms/InstCombine/icmp.ll (+35)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 55afe1258159a..23e9153ffa51b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7435,6 +7435,31 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   if (Value *V = simplifyICmpInst(I.getCmpPredicate(), Op0, Op1, Q))
     return replaceInstUsesWith(I, V);
 
+  // Try to fold pattern: u <= (u <= b), b is boolean-like.
+  //  This fold handles cases where Clang produces code like:
+  //    %cmp1 = icmp ule i32 %u, zext i1 %b to i32
+  //    %zext = zext i1 %cmp1 to i32
+  //    %cmp2 = icmp ule i32 %u, %zext
+  //  fold the comparison into: u <= b
+  if (I.getPredicate() == ICmpInst::ICMP_ULE) {
+    if (auto *Z = dyn_cast<ZExtInst>(Op1)) {
+      if (Z->getSrcTy()->isIntegerTy(1)) {
+        if (auto *Inner = dyn_cast<ICmpInst>(Z->getOperand(0))) {
+          if (Inner->getPredicate() == ICmpInst::ICMP_ULE &&
+              Inner->getOperand(0) == Op0 && Inner->hasOneUse()) {
+            Value *Bnd = Inner->getOperand(1);
+            bool IsBoolExt = isa<ZExtInst>(Bnd) &&
+                             cast<ZExtInst>(Bnd)->getSrcTy()->isIntegerTy(1);
+            if (match(Bnd, m_ZeroInt()) || match(Bnd, m_One()) || IsBoolExt) {
+              Value *NewCmp = Builder.CreateICmpULE(Op0, Bnd, I.getName());
+              return replaceInstUsesWith(I, NewCmp);
+            }
+          }
+        }
+      }
+    }
+  }
+
   // Comparing -val or val with non-zero is the same as just comparing val
   // ie, abs(val) != 0 -> val != 0
   if (I.getPredicate() == ICmpInst::ICMP_NE && match(Op1, m_Zero())) {
diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index 6e1486660b24d..81357300b8063 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -5400,3 +5400,38 @@ define i1 @icmp_samesign_logical_or(i32 %In) {
   %V = select i1 %c1, i1 true, i1 %c2
   ret i1 %V
 }
+
+;===----------------------------------------------------------------------===;
+; Test folding of nested `icmp ule` when inner RHS is boolean-like
+;===----------------------------------------------------------------------===;
+
+define i32 @fold_nested_ule_bool(i32 %u, i1 %b) {
+; CHECK-LABEL: @fold_nested_ule_bool(
+; CHECK-NEXT:  [[CONV:%.*]] = zext i1 [[B:%.*]] to i32
+; CHECK-NEXT:  [[CMP:%.*]] = icmp ule i32 [[U:%.*]], [[CONV]]
+; CHECK-NEXT:  [[CONV1:%.*]] = zext i1 [[CMP]] to i32
+; CHECK-NEXT:  ret i32 [[CONV1]]
+;
+  %conv = zext i1 %b to i32
+  %cmp = icmp ule i32 %u, %conv
+  %conv1 = zext i1 %cmp to i32
+  %cmp2 = icmp ule i32 %u, %conv1
+  %conv3 = zext i1 %cmp2 to i32
+  ret i32 %conv3
+}
+
+define i32 @no_fold_nested_ule(i32 %u, i32 %b) {
+; CHECK-LABEL: @no_fold_nested_ule(
+; CHECK-NEXT:  [[CMP1:%.*]] = icmp ule i32 [[U:%.*]], [[B:%.*]]
+; CHECK-NEXT:  [[Z1:%.*]] = zext i1 [[CMP1]] to i32
+; CHECK-NEXT:  [[CMP2:%.*]] = icmp ule i32 [[U]], [[Z1]]
+; CHECK-NEXT:  [[CONV:%.*]] = zext i1 [[CMP2]] to i32
+; CHECK-NEXT:  ret i32 [[CONV]]
+;
+  %cmp1 = icmp ule i32 %u, %b
+  %z1   = zext i1 %cmp1 to i32
+  %cmp2 = icmp ule i32 %u, %z1
+  %conv = zext i1 %cmp2 to i32
+  ret i32 %conv
+}
+

@dtcxzyw
Copy link
Member

dtcxzyw commented Apr 22, 2025

I cannot provide evidence for the real-world usefulness of this patch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

u <= (u <= (unsigned)b) can be folded into (u <= (unsigned)b)

3 participants