[llvm] [ValueTracking] Improve `and` and `or` recurrence handling (PR #225775)
Ömer Sinan Ağacan via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 23 06:51:44 PDT 2026
https://github.com/osa1 created https://github.com/llvm/llvm-project/pull/225775
None
>From f0227dd126d3dff2850dba1b1669d32a2fd5e504 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= <omer at osa1.net>
Date: Wed, 23 Sep 2026 14:27:06 +0100
Subject: [PATCH 1/3] Add tests
---
.../test/Transforms/InstCombine/recurrence.ll | 118 ++++++++++++++++++
1 file changed, 118 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/recurrence.ll b/llvm/test/Transforms/InstCombine/recurrence.ll
index 090e22c803b76..5c2b5b56f438c 100644
--- a/llvm/test/Transforms/InstCombine/recurrence.ll
+++ b/llvm/test/Transforms/InstCombine/recurrence.ll
@@ -81,6 +81,64 @@ loop: ; preds = %loop, %entry
br label %loop
}
+; The mask should be removed based on Start's ones.
+define i64 @test_or_start_known_ones(i32 %s, ptr %p) {
+; CHECK-LABEL: @test_or_start_known_ones(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[S_EXT:%.*]] = zext i32 [[S:%.*]] to i64
+; CHECK-NEXT: [[START:%.*]] = or disjoint i64 [[S_EXT]], -4294967296
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[STEP:%.*]] = load volatile i64, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[IV_NEXT]] = or i64 [[IV]], [[STEP]]
+; CHECK-NEXT: [[IV_NEXT_MASKED:%.*]] = or i64 [[IV_NEXT]], -4294967296
+; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT_MASKED]])
+; CHECK-NEXT: br label [[LOOP]]
+;
+entry:
+ %s.ext = zext i32 %s to i64
+ %start = or i64 %s.ext, u0xFFFFFFFF00000000
+ br label %loop
+
+loop:
+ %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
+ %step = load volatile i64, ptr %p
+ %iv.next = or i64 %iv, %step
+ %iv.next.masked = or i64 %iv.next, u0xFFFFFFFF00000000
+ tail call void @use(i64 %iv.next.masked)
+ br label %loop
+}
+
+; The mask should be removed based on the known zeros of Start and Step.
+define i64 @test_or_step_known_zeros(i32 %s, ptr %p) {
+; CHECK-LABEL: @test_or_step_known_zeros(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[START:%.*]] = zext i32 [[S:%.*]] to i64
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[STEP_I32:%.*]] = load volatile i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[STEP:%.*]] = zext i32 [[STEP_I32]] to i64
+; CHECK-NEXT: [[IV_NEXT]] = or i64 [[IV]], [[STEP]]
+; CHECK-NEXT: [[IV_NEXT_MASKED:%.*]] = and i64 [[IV]], -4294967296
+; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT_MASKED]])
+; CHECK-NEXT: br label [[LOOP]]
+;
+entry:
+ %start = zext i32 %s to i64
+ br label %loop
+
+loop:
+ %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
+ %step.i32 = load volatile i32, ptr %p
+ %step = zext i32 %step.i32 to i64
+ %iv.next = or i64 %iv, %step
+ %iv.next.masked = and i64 %iv.next, u0xFFFFFFFF00000000
+ tail call void @use(i64 %iv.next.masked)
+ br label %loop
+}
+
define i64 @test_and(i64 %a) {
; CHECK-LABEL: @test_and(
; CHECK-NEXT: entry:
@@ -162,6 +220,66 @@ loop: ; preds = %loop, %entry
br label %loop
}
+; The mask should be removed based on Start's zeros.
+define i64 @test_and_start_known_zeros(i32 %s, ptr %p) {
+; CHECK-LABEL: @test_and_start_known_zeros(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[START:%.*]] = zext i32 [[S:%.*]] to i64
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[STEP:%.*]] = load volatile i64, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[IV_NEXT]] = and i64 [[IV]], [[STEP]]
+; CHECK-NEXT: [[IV_NEXT_MASKED:%.*]] = and i64 [[IV_NEXT]], 4294967295
+; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT_MASKED]])
+; CHECK-NEXT: br label [[LOOP]]
+;
+entry:
+ %start = zext i32 %s to i64
+ br label %loop
+
+loop:
+ %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
+ %step = load volatile i64, ptr %p
+ %iv.next = and i64 %iv, %step
+ %iv.next.masked = and i64 %iv.next, u0x00000000FFFFFFFF
+ tail call void @use(i64 %iv.next.masked)
+ br label %loop
+}
+
+; The mask should be removed based on the known ones of Start and Step.
+define i64 @test_and_step_known_ones(i32 %s, ptr %p) {
+; CHECK-LABEL: @test_and_step_known_ones(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[START_ZEXT:%.*]] = zext i32 [[S:%.*]] to i64
+; CHECK-NEXT: [[START:%.*]] = or disjoint i64 [[START_ZEXT]], -4294967296
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[STEP_I32:%.*]] = load volatile i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[STEP_ZEXT:%.*]] = zext i32 [[STEP_I32]] to i64
+; CHECK-NEXT: [[STEP:%.*]] = or disjoint i64 [[STEP_ZEXT]], -4294967296
+; CHECK-NEXT: [[IV_NEXT]] = and i64 [[IV]], [[STEP]]
+; CHECK-NEXT: [[IV_NEXT_MASKED:%.*]] = or i64 [[IV_NEXT]], -4294967296
+; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT_MASKED]])
+; CHECK-NEXT: br label [[LOOP]]
+;
+entry:
+ %start.zext = zext i32 %s to i64
+ %start = or i64 %start.zext, u0xFFFFFFFF00000000
+ br label %loop
+
+loop:
+ %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
+ %step.i32 = load volatile i32, ptr %p
+ %step.zext = zext i32 %step.i32 to i64
+ %step = or i64 %step.zext, u0xFFFFFFFF00000000
+ %iv.next = and i64 %iv, %step
+ %iv.next.masked = or i64 %iv.next, u0xFFFFFFFF00000000
+ tail call void @use(i64 %iv.next.masked)
+ br label %loop
+}
+
declare i32 @get_step()
define i1 @test_loop_variant_step_with_condition() {
>From 9d1a270877ae5eb8e850ffbf930d6852943ce61b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= <omer at osa1.net>
Date: Wed, 23 Sep 2026 14:27:53 +0100
Subject: [PATCH 2/3] Improve analysis
---
llvm/lib/Analysis/ValueTracking.cpp | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index ed1e2f7467e19..2fdf3c4154dd1 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1899,13 +1899,35 @@ static void computeKnownBitsFromOperator(const Operator *I,
break;
}
+ case Instruction::And: {
+ // Start's zeros will always stay zero, ones can change.
+ KnownBits KnownStep(BitWidth);
+ computeKnownBitsForRecurrenceOperands(P, Start, Step, DemandedElts,
+ KnownStart, KnownStep, Q, Depth);
+
+ Known.Zero = KnownStart.Zero;
+ Known.One = KnownStart.One & KnownStep.One;
+
+ break;
+ }
+
+ case Instruction::Or: {
+ // Start's ones will always stay one, zeros can change.
+ KnownBits KnownStep(BitWidth);
+ computeKnownBitsForRecurrenceOperands(P, Start, Step, DemandedElts,
+ KnownStart, KnownStep, Q, Depth);
+
+ Known.One = KnownStart.One;
+ Known.Zero = KnownStart.Zero & KnownStep.Zero;
+
+ break;
+ }
+
// Check for operations that have the property that if
// both their operands have low zero bits, the result
// will have low zero bits.
case Instruction::Add:
case Instruction::Sub:
- case Instruction::And:
- case Instruction::Or:
case Instruction::Mul: {
// Ok, we have a recurrence of the form {Start,op,Step}. Check for low
// zero bits.
>From 5f656770a588d21c12d1e0f69a60c553359dca94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= <omer at osa1.net>
Date: Wed, 23 Sep 2026 14:28:23 +0100
Subject: [PATCH 3/3] Update tests
---
llvm/test/Transforms/InstCombine/recurrence.ll | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/recurrence.ll b/llvm/test/Transforms/InstCombine/recurrence.ll
index 5c2b5b56f438c..853e178a86a44 100644
--- a/llvm/test/Transforms/InstCombine/recurrence.ll
+++ b/llvm/test/Transforms/InstCombine/recurrence.ll
@@ -92,8 +92,7 @@ define i64 @test_or_start_known_ones(i32 %s, ptr %p) {
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[STEP:%.*]] = load volatile i64, ptr [[P:%.*]], align 4
; CHECK-NEXT: [[IV_NEXT]] = or i64 [[IV]], [[STEP]]
-; CHECK-NEXT: [[IV_NEXT_MASKED:%.*]] = or i64 [[IV_NEXT]], -4294967296
-; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT_MASKED]])
+; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT]])
; CHECK-NEXT: br label [[LOOP]]
;
entry:
@@ -114,15 +113,10 @@ loop:
define i64 @test_or_step_known_zeros(i32 %s, ptr %p) {
; CHECK-LABEL: @test_or_step_known_zeros(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[START:%.*]] = zext i32 [[S:%.*]] to i64
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
-; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[STEP_I32:%.*]] = load volatile i32, ptr [[P:%.*]], align 4
-; CHECK-NEXT: [[STEP:%.*]] = zext i32 [[STEP_I32]] to i64
-; CHECK-NEXT: [[IV_NEXT]] = or i64 [[IV]], [[STEP]]
-; CHECK-NEXT: [[IV_NEXT_MASKED:%.*]] = and i64 [[IV]], -4294967296
-; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT_MASKED]])
+; CHECK-NEXT: tail call void @use(i64 0)
; CHECK-NEXT: br label [[LOOP]]
;
entry:
@@ -230,8 +224,7 @@ define i64 @test_and_start_known_zeros(i32 %s, ptr %p) {
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[STEP:%.*]] = load volatile i64, ptr [[P:%.*]], align 4
; CHECK-NEXT: [[IV_NEXT]] = and i64 [[IV]], [[STEP]]
-; CHECK-NEXT: [[IV_NEXT_MASKED:%.*]] = and i64 [[IV_NEXT]], 4294967295
-; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT_MASKED]])
+; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT]])
; CHECK-NEXT: br label [[LOOP]]
;
entry:
@@ -260,8 +253,7 @@ define i64 @test_and_step_known_ones(i32 %s, ptr %p) {
; CHECK-NEXT: [[STEP_ZEXT:%.*]] = zext i32 [[STEP_I32]] to i64
; CHECK-NEXT: [[STEP:%.*]] = or disjoint i64 [[STEP_ZEXT]], -4294967296
; CHECK-NEXT: [[IV_NEXT]] = and i64 [[IV]], [[STEP]]
-; CHECK-NEXT: [[IV_NEXT_MASKED:%.*]] = or i64 [[IV_NEXT]], -4294967296
-; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT_MASKED]])
+; CHECK-NEXT: tail call void @use(i64 [[IV_NEXT]])
; CHECK-NEXT: br label [[LOOP]]
;
entry:
More information about the llvm-commits
mailing list