[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