[llvm] [ValueTracking] Improve `and` and `or` recurrence handling (PR #225775)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 06:52:28 PDT 2026


=?utf-8?q?Ömer_Sinan_Ağacan?= <omer at osa1.net>,
=?utf-8?q?Ömer_Sinan_Ağacan?= <omer at osa1.net>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/225775 at github.com>


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-analysis

Author: Ömer Sinan Ağacan (osa1)

<details>
<summary>Changes</summary>



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


2 Files Affected:

- (modified) llvm/lib/Analysis/ValueTracking.cpp (+24-2) 
- (modified) llvm/test/Transforms/InstCombine/recurrence.ll (+110) 


``````````diff
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.
diff --git a/llvm/test/Transforms/InstCombine/recurrence.ll b/llvm/test/Transforms/InstCombine/recurrence.ll
index 090e22c803b76..853e178a86a44 100644
--- a/llvm/test/Transforms/InstCombine/recurrence.ll
+++ b/llvm/test/Transforms/InstCombine/recurrence.ll
@@ -81,6 +81,58 @@ 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:    tail call void @use(i64 [[IV_NEXT]])
+; 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:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[STEP_I32:%.*]] = load volatile i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT:    tail call void @use(i64 0)
+; 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 +214,64 @@ 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:    tail call void @use(i64 [[IV_NEXT]])
+; 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:    tail call void @use(i64 [[IV_NEXT]])
+; 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() {

``````````

</details>


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


More information about the llvm-commits mailing list