From 8133b5aefaa59635967006876a2c9b94c2a67ab3 Mon Sep 17 00:00:00 2001 From: YLChenZ 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(Op1)) { + if (Z->getSrcTy()->isIntegerTy(1)) { + if (auto *Inner = dyn_cast(Z->getOperand(0))) { + if (Inner->getPredicate() == ICmpInst::ICMP_ULE && + Inner->getOperand(0) == Op0 && + Inner->hasOneUse()) { + Value *Bnd = Inner->getOperand(1); + bool IsBoolExt = isa(Bnd) && + cast(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 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(Op1)) { - if (Z->getSrcTy()->isIntegerTy(1)) { - if (auto *Inner = dyn_cast(Z->getOperand(0))) { + if (auto *Z = dyn_cast(Op1)) { + if (Z->getSrcTy()->isIntegerTy(1)) { + if (auto *Inner = dyn_cast(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(Bnd) && - cast(Bnd)->getSrcTy()->isIntegerTy(1); + cast(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);