[llvm] [ValueTracking] An or recurrence with a non-zero start value is non-zero (PR #226155)

Konstantin Bogdanov via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 06:08:58 PDT 2026


https://github.com/thevar1able created https://github.com/llvm/llvm-project/pull/226155

Or-ing anything into a non-zero value keeps it non-zero, so `isNonZeroRecurrence` can accept a simple `%iv = or %iv, %step` recurrence with a non-zero constant start value, regardless of the step.

The first commit precommits the tests in `phi-known-nonzero.ll`.

This is split out of #222334. Together with a follow-up that stops limiting the recursion depth for single-incoming (LCSSA) phis in `isKnownNonZero`, it lets LoopIdiomRecognize (#222373) form `llvm.ctlz` for the clz loop in ffmpeg's `sbc_calc_scalefactors`.


>From e124c4a826d17d00f2ccc27cce41b2dde3e9e532 Mon Sep 17 00:00:00 2001
From: Konstantin Bogdanov <konstantin at clickhouse.com>
Date: Thu, 24 Sep 2026 13:23:57 +0200
Subject: [PATCH 1/2] [ValueTracking] Precommit tests for non-zero or
 recurrences (NFC)

---
 .../ValueTracking/phi-known-nonzero.ll        | 74 +++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/llvm/test/Analysis/ValueTracking/phi-known-nonzero.ll b/llvm/test/Analysis/ValueTracking/phi-known-nonzero.ll
index d80d1704c73d1d..ed77b9d3586529 100644
--- a/llvm/test/Analysis/ValueTracking/phi-known-nonzero.ll
+++ b/llvm/test/Analysis/ValueTracking/phi-known-nonzero.ll
@@ -262,3 +262,77 @@ T:
 F:
   br label %T
 }
+
+; An or recurrence with a non-zero start value is never zero.
+define i1 @or_recurrence_nonzero_start(ptr %p, i64 %n) {
+;
+; CHECK-LABEL: @or_recurrence_nonzero_start(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[ACC:%.*]] = phi i32 [ 32768, [[ENTRY]] ], [ [[ACC_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[X:%.*]] = load i32, ptr [[GEP]], align 4
+; CHECK-NEXT:    [[ACC_NEXT]] = or i32 [[X]], [[ACC]]
+; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[ACC_NEXT]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+  %acc = phi i32 [ 32768, %entry ], [ %acc.next, %loop ]
+  %gep = getelementptr i32, ptr %p, i64 %iv
+  %x = load i32, ptr %gep
+  %acc.next = or i32 %x, %acc
+  %iv.next = add i64 %iv, 1
+  %ec = icmp eq i64 %iv.next, %n
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  %cmp = icmp eq i32 %acc.next, 0
+  ret i1 %cmp
+}
+
+; Negative test: the start value is zero.
+define i1 @or_recurrence_zero_start(ptr %p, i64 %n) {
+;
+; CHECK-LABEL: @or_recurrence_zero_start(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[ACC:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[ACC_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[IV]]
+; CHECK-NEXT:    [[X:%.*]] = load i32, ptr [[GEP]], align 4
+; CHECK-NEXT:    [[ACC_NEXT]] = or i32 [[X]], [[ACC]]
+; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 1
+; CHECK-NEXT:    [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[ACC_NEXT]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+entry:
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+  %acc = phi i32 [ 0, %entry ], [ %acc.next, %loop ]
+  %gep = getelementptr i32, ptr %p, i64 %iv
+  %x = load i32, ptr %gep
+  %acc.next = or i32 %x, %acc
+  %iv.next = add i64 %iv, 1
+  %ec = icmp eq i64 %iv.next, %n
+  br i1 %ec, label %exit, label %loop
+
+exit:
+  %cmp = icmp eq i32 %acc.next, 0
+  ret i1 %cmp
+}

>From cb8ec8e24de65013a4fead6b90469a70e1324d48 Mon Sep 17 00:00:00 2001
From: Konstantin Bogdanov <konstantin at clickhouse.com>
Date: Thu, 24 Sep 2026 15:07:05 +0200
Subject: [PATCH 2/2] [ValueTracking] An or recurrence with a non-zero start
 value is non-zero

Or-ing anything into a non-zero value keeps it non-zero, so a simple
`%iv = or %iv, %step` recurrence with a non-zero constant start value is
never zero.
---
 llvm/lib/Analysis/ValueTracking.cpp                   | 2 ++
 llvm/test/Analysis/ValueTracking/phi-known-nonzero.ll | 3 +--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index ed1e2f7467e197..6a54ec8ecc5d69 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3182,6 +3182,8 @@ static bool isNonZeroRecurrence(const PHINode *PN) {
   case Instruction::AShr:
   case Instruction::LShr:
     return BO->isExact();
+  case Instruction::Or:
+    return true;
   default:
     return false;
   }
diff --git a/llvm/test/Analysis/ValueTracking/phi-known-nonzero.ll b/llvm/test/Analysis/ValueTracking/phi-known-nonzero.ll
index ed77b9d3586529..a93f149e9c200d 100644
--- a/llvm/test/Analysis/ValueTracking/phi-known-nonzero.ll
+++ b/llvm/test/Analysis/ValueTracking/phi-known-nonzero.ll
@@ -279,8 +279,7 @@ define i1 @or_recurrence_nonzero_start(ptr %p, i64 %n) {
 ; CHECK-NEXT:    [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N:%.*]]
 ; CHECK-NEXT:    br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP]]
 ; CHECK:       exit:
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[ACC_NEXT]], 0
-; CHECK-NEXT:    ret i1 [[CMP]]
+; CHECK-NEXT:    ret i1 false
 ;
 entry:
   br label %loop



More information about the llvm-commits mailing list