[llvm] [InstCombine] Fold trunc nuw i1 to false when dominated by icmp. (PR #151961)

Andreas Jonson via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 4 06:30:36 PDT 2025


https://github.com/andjo403 created https://github.com/llvm/llvm-project/pull/151961

Proof: https://alive2.llvm.org/ce/z/4BOiFF

>From f13dc126f3d65c397fa41da151b4e5b234d00e8a Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Mon, 4 Aug 2025 15:19:35 +0200
Subject: [PATCH 1/2] [InstCombine] Add test for trunc with dominating icmp.

---
 llvm/test/Transforms/InstCombine/trunc.ll | 142 ++++++++++++++++++++++
 1 file changed, 142 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index dfe9d941f840c..faea50042c32f 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -1218,3 +1218,145 @@ define i2 @neg_trunc_nsw_i2_non_zero(i8 %1) {
   %ret = trunc nsw i8 %1 to i2
   ret i2 %ret
 }
+
+define i1 @trunc_nuw_i1_dominating_icmp_ne_1(i8 %x) {
+; CHECK-LABEL: @trunc_nuw_i1_dominating_icmp_ne_1(
+; CHECK-NEXT:    [[ICMP_NOT:%.*]] = icmp eq i8 [[X:%.*]], 1
+; CHECK-NEXT:    br i1 [[ICMP_NOT]], label [[BB2:%.*]], label [[BB1:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[RET1:%.*]] = trunc nuw i8 [[X]] to i1
+; CHECK-NEXT:    ret i1 [[RET1]]
+; CHECK:       bb2:
+; CHECK-NEXT:    ret i1 true
+;
+  %icmp = icmp ne i8 %x, 1
+  br i1 %icmp, label %bb1, label %bb2
+bb1:
+  %ret1 = trunc nuw i8 %x to i1
+  ret i1 %ret1
+bb2:
+  %ret2 = trunc nuw i8 %x to i1
+  ret i1 %ret2
+}
+
+define i1 @trunc_nuw_i1_dominating_icmp_eq_1(i8 %x) {
+; CHECK-LABEL: @trunc_nuw_i1_dominating_icmp_eq_1(
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[X:%.*]], 1
+; CHECK-NEXT:    br i1 [[ICMP]], label [[BB1:%.*]], label [[BB2:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    ret i1 true
+; CHECK:       bb2:
+; CHECK-NEXT:    [[RET2:%.*]] = trunc nuw i8 [[X]] to i1
+; CHECK-NEXT:    ret i1 [[RET2]]
+;
+  %icmp = icmp eq i8 %x, 1
+  br i1 %icmp, label %bb1, label %bb2
+bb1:
+  %ret1 = trunc nuw i8 %x to i1
+  ret i1 %ret1
+bb2:
+  %ret2 = trunc nuw i8 %x to i1
+  ret i1 %ret2
+}
+
+define i1 @trunc_nuw_i1_dominating_icmp_ne_0(i8 %x) {
+; CHECK-LABEL: @trunc_nuw_i1_dominating_icmp_ne_0(
+; CHECK-NEXT:    [[ICMP_NOT:%.*]] = icmp eq i8 [[X:%.*]], 0
+; CHECK-NEXT:    br i1 [[ICMP_NOT]], label [[BB2:%.*]], label [[BB1:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    ret i1 true
+; CHECK:       bb2:
+; CHECK-NEXT:    ret i1 false
+;
+  %icmp = icmp ne i8 %x, 0
+  br i1 %icmp, label %bb1, label %bb2
+bb1:
+  %ret1 = trunc nuw i8 %x to i1
+  ret i1 %ret1
+bb2:
+  %ret2 = trunc nuw i8 %x to i1
+  ret i1 %ret2
+}
+
+define i1 @trunc_nuw_i1_dominating_icmp_eq_0(i8 %x) {
+; CHECK-LABEL: @trunc_nuw_i1_dominating_icmp_eq_0(
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[X:%.*]], 0
+; CHECK-NEXT:    br i1 [[ICMP]], label [[BB1:%.*]], label [[BB2:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       bb2:
+; CHECK-NEXT:    ret i1 true
+;
+  %icmp = icmp eq i8 %x, 0
+  br i1 %icmp, label %bb1, label %bb2
+bb1:
+  %ret1 = trunc nuw i8 %x to i1
+  ret i1 %ret1
+bb2:
+  %ret2 = trunc nuw i8 %x to i1
+  ret i1 %ret2
+}
+
+define i1 @neg_trunc_i1_dominating_icmp_ne_1(i8 %x) {
+; CHECK-LABEL: @neg_trunc_i1_dominating_icmp_ne_1(
+; CHECK-NEXT:    [[ICMP_NOT:%.*]] = icmp eq i8 [[X:%.*]], 1
+; CHECK-NEXT:    br i1 [[ICMP_NOT]], label [[BB2:%.*]], label [[BB1:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[RET1:%.*]] = trunc i8 [[X]] to i1
+; CHECK-NEXT:    ret i1 [[RET1]]
+; CHECK:       bb2:
+; CHECK-NEXT:    ret i1 true
+;
+  %icmp = icmp ne i8 %x, 1
+  br i1 %icmp, label %bb1, label %bb2
+bb1:
+  %ret1 = trunc i8 %x to i1
+  ret i1 %ret1
+bb2:
+  %ret2 = trunc i8 %x to i1
+  ret i1 %ret2
+}
+
+define i2 @neg_trunc_nuw_i2_dominating_icmp_ne_1(i8 %x) {
+; CHECK-LABEL: @neg_trunc_nuw_i2_dominating_icmp_ne_1(
+; CHECK-NEXT:    [[ICMP_NOT:%.*]] = icmp eq i8 [[X:%.*]], 1
+; CHECK-NEXT:    br i1 [[ICMP_NOT]], label [[BB2:%.*]], label [[BB1:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[RET1:%.*]] = trunc nuw i8 [[X]] to i2
+; CHECK-NEXT:    ret i2 [[RET1]]
+; CHECK:       bb2:
+; CHECK-NEXT:    ret i2 1
+;
+  %icmp = icmp ne i8 %x, 1
+  br i1 %icmp, label %bb1, label %bb2
+bb1:
+  %ret1 = trunc nuw i8 %x to i2
+  ret i2 %ret1
+bb2:
+  %ret2 = trunc nuw i8 %x to i2
+  ret i2 %ret2
+}
+
+define i1 @neg_trunc_nuw_i1_not_dominating_icmp_ne_1(i8 %x, i1 %y) {
+; CHECK-LABEL: @neg_trunc_nuw_i1_not_dominating_icmp_ne_1(
+; CHECK-NEXT:    br i1 [[Y:%.*]], label [[BB1:%.*]], label [[BB0:%.*]]
+; CHECK:       bb0:
+; CHECK-NEXT:    [[ICMP_NOT:%.*]] = icmp eq i8 [[X:%.*]], 1
+; CHECK-NEXT:    br i1 [[ICMP_NOT]], label [[BB2:%.*]], label [[BB1]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[RET1:%.*]] = trunc nuw i8 [[X]] to i1
+; CHECK-NEXT:    ret i1 [[RET1]]
+; CHECK:       bb2:
+; CHECK-NEXT:    ret i1 true
+;
+  br i1 %y, label %bb1, label %bb0
+bb0:
+  %icmp = icmp ne i8 %x, 1
+  br i1 %icmp, label %bb1, label %bb2
+bb1:
+  %ret1 = trunc nuw i8 %x to i1
+  ret i1 %ret1
+bb2:
+  %ret2 = trunc nuw i8 %x to i1
+  ret i1 %ret2
+}

>From 424fe1ef7ae369b307abfac0634a978916a4ca09 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Mon, 4 Aug 2025 15:20:58 +0200
Subject: [PATCH 2/2] [InstCombine] Fold trunc nuw i1 to false when dominated
 by icmp.

---
 .../InstCombine/InstCombineCasts.cpp          | 32 +++++++++++++++++++
 llvm/test/Transforms/InstCombine/trunc.ll     |  6 ++--
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index a43a6ee1f58b0..8529d7b30b56d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -951,6 +951,38 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
     }
   }
 
+  // Fold Trunc nuw i1 With Dominating ICmp
+  if (DestWidth == 1 && Trunc.hasNoUnsignedWrap()) {
+    auto HandleDomCond = [&](ICmpInst::Predicate DomPred,
+                             const APInt *DomC) -> Instruction * {
+      ConstantRange DominatingCR =
+          ConstantRange::makeExactICmpRegion(DomPred, *DomC);
+      if (!DominatingCR.contains(APInt(SrcWidth, 1)))
+        return replaceInstUsesWith(Trunc, Builder.getFalse());
+      return nullptr;
+    };
+
+    for (BranchInst *BI : DC.conditionsFor(Src)) {
+      CmpPredicate DomPred;
+      const APInt *DomC;
+      if (!match(BI->getCondition(),
+                 m_ICmp(DomPred, m_Specific(Src), m_APInt(DomC))))
+        continue;
+
+      BasicBlockEdge Edge0(BI->getParent(), BI->getSuccessor(0));
+      if (DT.dominates(Edge0, Trunc.getParent())) {
+        if (auto *V = HandleDomCond(DomPred, DomC))
+          return V;
+      } else {
+        BasicBlockEdge Edge1(BI->getParent(), BI->getSuccessor(1));
+        if (DT.dominates(Edge1, Trunc.getParent()))
+          if (auto *V =
+                  HandleDomCond(CmpInst::getInversePredicate(DomPred), DomC))
+            return V;
+      }
+    }
+  }
+
   if (DestWidth == 1 &&
       (Trunc.hasNoUnsignedWrap() || Trunc.hasNoSignedWrap()) &&
       isKnownNonZero(Src, SQ.getWithInstruction(&Trunc)))
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index faea50042c32f..a03aa88063247 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -1224,8 +1224,7 @@ define i1 @trunc_nuw_i1_dominating_icmp_ne_1(i8 %x) {
 ; CHECK-NEXT:    [[ICMP_NOT:%.*]] = icmp eq i8 [[X:%.*]], 1
 ; CHECK-NEXT:    br i1 [[ICMP_NOT]], label [[BB2:%.*]], label [[BB1:%.*]]
 ; CHECK:       bb1:
-; CHECK-NEXT:    [[RET1:%.*]] = trunc nuw i8 [[X]] to i1
-; CHECK-NEXT:    ret i1 [[RET1]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       bb2:
 ; CHECK-NEXT:    ret i1 true
 ;
@@ -1246,8 +1245,7 @@ define i1 @trunc_nuw_i1_dominating_icmp_eq_1(i8 %x) {
 ; CHECK:       bb1:
 ; CHECK-NEXT:    ret i1 true
 ; CHECK:       bb2:
-; CHECK-NEXT:    [[RET2:%.*]] = trunc nuw i8 [[X]] to i1
-; CHECK-NEXT:    ret i1 [[RET2]]
+; CHECK-NEXT:    ret i1 false
 ;
   %icmp = icmp eq i8 %x, 1
   br i1 %icmp, label %bb1, label %bb2



More information about the llvm-commits mailing list