[llvm] [InstCombine] Fold `(x < 2^32) & (trunc(x to i32) == 0)` into `x == 0` (PR #171195)

Tirthankar Mazumder via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 11 10:53:30 PST 2025


https://github.com/wermos updated https://github.com/llvm/llvm-project/pull/171195

>From 16b12d3fcfbcef7f15c984d9260b4ff4aa473b9e Mon Sep 17 00:00:00 2001
From: Tirthankar Mazumder <tmazumder.github at gmail.com>
Date: Fri, 12 Dec 2025 00:21:49 +0530
Subject: [PATCH 1/2] Pre-commit tests

---
 .../InstCombine/InstCombineCompares.cpp          |  2 +-
 llvm/test/Transforms/InstCombine/and-or-icmps.ll | 16 ++++++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 616cb04be9dbc..911bc95ac7700 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6291,7 +6291,7 @@ Instruction *InstCombinerImpl::foldICmpWithTrunc(ICmpInst &ICmp) {
   // This matches patterns corresponding to tests of the signbit as well as:
   // (trunc X) pred C2 --> (X & Mask) == C
   if (auto Res = decomposeBitTestICmp(Op0, Op1, Pred, /*LookThroughTrunc=*/true,
-                                      /*AllowNonZeroC=*/true)) {
+                                      /*AllowNonZeroC=*/true, /*DecomposeAnd=*/true)) {
     Value *And = Builder.CreateAnd(Res->X, Res->Mask);
     Constant *C = ConstantInt::get(Res->X->getType(), Res->C);
     return new ICmpInst(Res->Pred, And, C);
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index 290e344acb980..bd62e7726b629 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -3721,3 +3721,19 @@ define i1 @merge_range_check_or(i8 %a) {
   %and = or i1 %cmp1, %cmp2
   ret i1 %and
 }
+
+; Just a very complicated way of checking if v1 == 0.
+define i1 @complicated_zero_equality_test(i64 %v1) {
+; CHECK-LABEL: @complicated_zero_equality_test(
+; CHECK-NEXT:    [[V2:%.*]] = trunc i64 [[V1:%.*]] to i32
+; CHECK-NEXT:    [[V3:%.*]] = icmp eq i32 [[V2]], 0
+; CHECK-NEXT:    [[V4:%.*]] = icmp ult i64 [[V1]], 4294967296
+; CHECK-NEXT:    [[V5:%.*]] = and i1 [[V4]], [[V3]]
+; CHECK-NEXT:    ret i1 [[V5]]
+;
+  %v2 = trunc i64 %v1 to i32
+  %v3 = icmp eq i32 %v2, 0
+  %v4 = icmp ult i64 %v1, 4294967296 ; 2 ^ 32
+  %v5 = and i1 %v4, %v3
+  ret i1 %v5
+}

>From 566242fddb79458e07a91f3847adcafee4ff3c35 Mon Sep 17 00:00:00 2001
From: Tirthankar Mazumder <tmazumder.github at gmail.com>
Date: Fri, 12 Dec 2025 00:22:47 +0530
Subject: [PATCH 2/2] Implement missing optimization in `decompostBitTestICmp`.

---
 llvm/lib/Analysis/CmpInstAnalysis.cpp | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/CmpInstAnalysis.cpp b/llvm/lib/Analysis/CmpInstAnalysis.cpp
index a6d0d3ff4fcd4..c6bd538a9fe7a 100644
--- a/llvm/lib/Analysis/CmpInstAnalysis.cpp
+++ b/llvm/lib/Analysis/CmpInstAnalysis.cpp
@@ -153,15 +153,26 @@ llvm::decomposeBitTestICmp(Value *LHS, Value *RHS, CmpInst::Predicate Pred,
   case ICmpInst::ICMP_NE: {
     assert(DecomposeAnd);
     const APInt *AndC;
-    Value *AndVal;
-    if (match(LHS, m_And(m_Value(AndVal), m_APIntAllowPoison(AndC)))) {
-      LHS = AndVal;
+    Value *X;
+
+    if (match(LHS, m_And(m_Value(X), m_APIntAllowPoison(AndC)))) {
+      LHS = X;
       Result.Mask = *AndC;
       Result.C = C;
       Result.Pred = Pred;
       break;
     }
 
+    // Try to convert (trunc X) eq/ne C into (X & Mask) eq/ne C
+    if (LookThroughTrunc && match(LHS, m_Trunc(m_Value(X)))) {
+      Result.X = X;
+      Result.Pred = Pred;
+      unsigned BitWidth = X->getType()->getScalarSizeInBits();
+      Result.Mask = APInt::getLowBitsSet(BitWidth, C.getBitWidth());
+      Result.C = C.zext(BitWidth);
+      break;
+    }
+
     return std::nullopt;
   }
   }



More information about the llvm-commits mailing list