[llvm] Infer nonzero on false OR edges (PR #230822)

via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 11 03:12:35 PDT 2026


https://github.com/CosmicalBit updated https://github.com/llvm/llvm-project/pull/230822

>From 9b5ae34ce5967305e755880fe3cef727544ce32d Mon Sep 17 00:00:00 2001
From: CosmicalBit <326617346+CosmicalBit at users.noreply.github.com>
Date: Thu, 8 Oct 2026 18:06:08 +0100
Subject: [PATCH] [ValueTracking] Infer nonzero on false OR edges

---
 llvm/lib/Analysis/ValueTracking.cpp           | 22 +++----
 .../ValueTracking/nonzero-or-condition.ll     | 58 +++++++++++++++++++
 2 files changed, 69 insertions(+), 11 deletions(-)
 create mode 100644 llvm/test/Analysis/ValueTracking/nonzero-or-condition.ll

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 7bbb2eb8e8313..bc53565966846 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3137,17 +3137,17 @@ static bool isKnownNonNullFromDominatingCondition(const Value *V,
       while (!WorkList.empty()) {
         auto *Curr = WorkList.pop_back_val();
 
-        // If a user is an AND, add all its users to the work list. We only
-        // propagate "pred != null" condition through AND because it is only
-        // correct to assume that all conditions of AND are met in true branch.
-        // TODO: Support similar logic of OR and EQ predicate?
-        if (NonNullIfTrue)
-          if (match(Curr, m_LogicalAnd(m_Value(), m_Value()))) {
-            for (const auto *CurrU : Curr->users())
-              if (Visited.insert(CurrU).second)
-                WorkList.push_back(CurrU);
-            continue;
-          }
+        // All operands of a true AND or a false OR must have the corresponding
+        // value. Follow their users to find a branch that establishes this.
+        if ((NonNullIfTrue &&
+             match(Curr, m_LogicalAnd(m_Value(), m_Value()))) ||
+            (!NonNullIfTrue &&
+             match(Curr, m_LogicalOr(m_Value(), m_Value())))) {
+          for (const auto *CurrU : Curr->users())
+            if (Visited.insert(CurrU).second)
+              WorkList.push_back(CurrU);
+          continue;
+        }
 
         if (const CondBrInst *BI = dyn_cast<CondBrInst>(Curr)) {
           BasicBlock *NonNullSuccessor =
diff --git a/llvm/test/Analysis/ValueTracking/nonzero-or-condition.ll b/llvm/test/Analysis/ValueTracking/nonzero-or-condition.ll
new file mode 100644
index 0000000000000..f0c5a53981e19
--- /dev/null
+++ b/llvm/test/Analysis/ValueTracking/nonzero-or-condition.ll
@@ -0,0 +1,58 @@
+; RUN: opt -passes=instsimplify -S %s | FileCheck %s
+
+; The false edge of (x == 0 || other) proves x is nonzero.
+define i1 @or_false(i64 %x, i1 %other) {
+; CHECK-LABEL: define i1 @or_false(
+; CHECK: known:
+; CHECK-NEXT: ret i1 false
+entry:
+  %iszero = icmp eq i64 %x, 0
+  %either = or i1 %iszero, %other
+  br i1 %either, label %maybe, label %known
+
+known:
+  %neg = sub i64 0, %x
+  %result = icmp eq i64 %neg, 0
+  ret i1 %result
+
+maybe:
+  ret i1 false
+}
+
+; A select can represent the same logical OR.
+define i1 @select_false(i64 %x, i1 %other) {
+; CHECK-LABEL: define i1 @select_false(
+; CHECK: known:
+; CHECK-NEXT: ret i1 false
+entry:
+  %iszero = icmp eq i64 %x, 0
+  %either = select i1 %iszero, i1 true, i1 %other
+  br i1 %either, label %maybe, label %known
+
+known:
+  %neg = sub i64 0, %x
+  %result = icmp eq i64 %neg, 0
+  ret i1 %result
+
+maybe:
+  ret i1 false
+}
+
+; The true edge of the OR does not establish that x is nonzero.
+define i1 @or_true(i64 %x, i1 %other) {
+; CHECK-LABEL: define i1 @or_true(
+; CHECK: maybe:
+; CHECK: %result = icmp eq i64 %neg, 0
+entry:
+  %iszero = icmp eq i64 %x, 0
+  %either = or i1 %iszero, %other
+  br i1 %either, label %maybe, label %known
+
+known:
+  ret i1 false
+
+maybe:
+  %neg = sub i64 0, %x
+  %result = icmp eq i64 %neg, 0
+  ret i1 %result
+}



More information about the llvm-commits mailing list