[llvm] [InstCombine] fold u <= (u <= (unsigned)b) into (u <= (unsigned)b). (PR #136654)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 21 22:47:05 PDT 2025
https://github.com/YLChenZ created https://github.com/llvm/llvm-project/pull/136654
Closes #132508.
Proof: https://alive2.llvm.org/ce/z/AjmXuN.
>From 8133b5aefaa59635967006876a2c9b94c2a67ab3 Mon Sep 17 00:00:00 2001
From: YLChenZ <chentongyongcz at gmail.com>
Date: Tue, 22 Apr 2025 13:39:01 +0800
Subject: [PATCH 1/2] [InstCombine] fold u <= (u <= (unsigned)b) into (u <=
(unsigned)b).
---
.../InstCombine/InstCombineCompares.cpp | 26 ++++++++++++++
llvm/test/Transforms/InstCombine/icmp.ll | 35 +++++++++++++++++++
2 files changed, 61 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 55afe1258159a..2556c28be93ab 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7435,6 +7435,32 @@ 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
+}
+
>From 5e5be45506220d58f1e8c432cef3ee55a2ff2a65 Mon Sep 17 00:00:00 2001
From: YLChenZ <chentongyongcz at gmail.com>
Date: Tue, 22 Apr 2025 13:40:26 +0800
Subject: [PATCH 2/2] [InstCombine] fold u <= (u <= (unsigned)b) into (u <=
(unsigned)b).
---
.../InstCombine/InstCombineCompares.cpp | 23 +++++++++----------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 2556c28be93ab..23e9153ffa51b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7435,22 +7435,21 @@ 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
+ // 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 (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()) {
+ Inner->getOperand(0) == Op0 && Inner->hasOneUse()) {
Value *Bnd = Inner->getOperand(1);
bool IsBoolExt = isa<ZExtInst>(Bnd) &&
- cast<ZExtInst>(Bnd)->getSrcTy()->isIntegerTy(1);
+ 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);
More information about the llvm-commits
mailing list