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

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 4 06:31:04 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Andreas Jonson (andjo403)

<details>
<summary>Changes</summary>

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

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


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp (+32) 
- (modified) llvm/test/Transforms/InstCombine/trunc.ll (+140) 


``````````diff
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 dfe9d941f840c..a03aa88063247 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -1218,3 +1218,143 @@ 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:    ret i1 false
+; 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:    ret i1 false
+;
+  %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
+}

``````````

</details>


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


More information about the llvm-commits mailing list