[llvm] 43dc65d - [ValueTracking] Infer non-zero from shr (add nuw A, B), C (#203039)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 07:20:53 PDT 2026


Author: Marina Taylor
Date: 2026-06-12T15:20:47+01:00
New Revision: 43dc65d46b54415ea474b0bf0ad8b761444a7ba2

URL: https://github.com/llvm/llvm-project/commit/43dc65d46b54415ea474b0bf0ad8b761444a7ba2
DIFF: https://github.com/llvm/llvm-project/commit/43dc65d46b54415ea474b0bf0ad8b761444a7ba2.diff

LOG: [ValueTracking] Infer non-zero from shr (add nuw A, B), C  (#203039)

...if either A or B has a known-one bit at position >= C.

https://alive2.llvm.org/ce/z/ELYTjh

This eliminates null checks in some internal workloads.

Assisted-by: claude

Added: 
    llvm/test/Analysis/ValueTracking/known-non-zero-shr-add.ll

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 763620b353bb5..df689aa57da6f 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3338,6 +3338,21 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
     if (Known.isNegative())
       return true;
 
+    // shr (add nuw A, B), C is non-zero if A or B has a known-one bit at
+    // position >= C, because the sum >= max(A, B).
+    Value *A, *B;
+    const APInt *C;
+    if (Depth + 1 < MaxAnalysisRecursionDepth &&
+        match(I->getOperand(0), m_NUWAdd(m_Value(A), m_Value(B))) &&
+        match(I->getOperand(1), m_APInt(C)) && C->ult(BitWidth)) {
+      KnownBits KnownA = computeKnownBits(A, DemandedElts, Q, Depth + 1);
+      if (!KnownA.One.lshr(*C).isZero())
+        return true;
+      KnownBits KnownB = computeKnownBits(B, DemandedElts, Q, Depth + 1);
+      if (!KnownB.One.lshr(*C).isZero())
+        return true;
+    }
+
     return isNonZeroShift(I, DemandedElts, Q, Known, Depth);
   }
   case Instruction::UDiv:

diff  --git a/llvm/test/Analysis/ValueTracking/known-non-zero-shr-add.ll b/llvm/test/Analysis/ValueTracking/known-non-zero-shr-add.ll
new file mode 100644
index 0000000000000..577ad5409d1fb
--- /dev/null
+++ b/llvm/test/Analysis/ValueTracking/known-non-zero-shr-add.ll
@@ -0,0 +1,119 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=instsimplify < %s -S | FileCheck %s
+
+define i1 @lshr_add_nuw_lhs_has_high_bit(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_add_nuw_lhs_has_high_bit(
+; CHECK-NEXT:    ret i1 false
+;
+  %x_high = or i32 %x, 256
+  %add = add nuw i32 %x_high, %y
+  %shr = lshr i32 %add, 4
+  %cmp = icmp eq i32 %shr, 0
+  ret i1 %cmp
+}
+
+define i1 @lshr_add_nuw_rhs_has_high_bit(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_add_nuw_rhs_has_high_bit(
+; CHECK-NEXT:    ret i1 false
+;
+  %y_high = or i32 %y, 256
+  %add = add nuw i32 %x, %y_high
+  %shr = lshr i32 %add, 4
+  %cmp = icmp eq i32 %shr, 0
+  ret i1 %cmp
+}
+
+define i1 @lshr_add_nuw_rhs_has_high_bit_i13(i13 %x, i13 %y) {
+; CHECK-LABEL: @lshr_add_nuw_rhs_has_high_bit_i13(
+; CHECK-NEXT:    ret i1 false
+;
+  %y_high = or i13 %y, 256
+  %add = add nuw i13 %x, %y_high
+  %shr = lshr i13 %add, 4
+  %cmp = icmp eq i13 %shr, 0
+  ret i1 %cmp
+}
+
+define <2 x i1> @lshr_add_nuw_vec(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @lshr_add_nuw_vec(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %x_high = or <2 x i32> %x, splat (i32 256)
+  %add = add nuw <2 x i32> %x_high, %y
+  %shr = lshr <2 x i32> %add, splat (i32 4)
+  %cmp = icmp eq <2 x i32> %shr, zeroinitializer
+  ret <2 x i1> %cmp
+}
+
+define i1 @ashr_add_nuw_lhs_has_high_bit(i32 %x, i32 %y) {
+; CHECK-LABEL: @ashr_add_nuw_lhs_has_high_bit(
+; CHECK-NEXT:    ret i1 false
+;
+  %x_high = or i32 %x, 256
+  %add = add nuw i32 %x_high, %y
+  %shr = ashr i32 %add, 4
+  %cmp = icmp eq i32 %shr, 0
+  ret i1 %cmp
+}
+
+; negative tests
+
+define i1 @lshr_add_nuw_bit_shifted_out_fail(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_add_nuw_bit_shifted_out_fail(
+; CHECK-NEXT:    [[X_HIGH:%.*]] = or i32 [[X:%.*]], 16
+; CHECK-NEXT:    [[ADD:%.*]] = add nuw i32 [[X_HIGH]], [[Y:%.*]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[ADD]], 8
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[SHR]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x_high = or i32 %x, 16
+  %add = add nuw i32 %x_high, %y
+  %shr = lshr i32 %add, 8
+  %cmp = icmp eq i32 %shr, 0
+  ret i1 %cmp
+}
+
+define i1 @lshr_add_no_nuw_fail(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_add_no_nuw_fail(
+; CHECK-NEXT:    [[X_HIGH:%.*]] = or i32 [[X:%.*]], 256
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X_HIGH]], [[Y:%.*]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[ADD]], 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[SHR]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x_high = or i32 %x, 256
+  %add = add i32 %x_high, %y
+  %shr = lshr i32 %add, 4
+  %cmp = icmp eq i32 %shr, 0
+  ret i1 %cmp
+}
+
+define i1 @lshr_add_nsw_fail(i32 %x, i32 %y) {
+; CHECK-LABEL: @lshr_add_nsw_fail(
+; CHECK-NEXT:    [[X_HIGH:%.*]] = or i32 [[X:%.*]], 256
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[X_HIGH]], [[Y:%.*]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[ADD]], 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[SHR]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x_high = or i32 %x, 256
+  %add = add nsw i32 %x_high, %y
+  %shr = lshr i32 %add, 4
+  %cmp = icmp eq i32 %shr, 0
+  ret i1 %cmp
+}
+
+define i1 @lshr_add_nuw_variable_shift_fail(i32 %x, i32 %y, i32 %c) {
+; CHECK-LABEL: @lshr_add_nuw_variable_shift_fail(
+; CHECK-NEXT:    [[X_HIGH:%.*]] = or i32 [[X:%.*]], 256
+; CHECK-NEXT:    [[ADD:%.*]] = add nuw i32 [[X_HIGH]], [[Y:%.*]]
+; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[ADD]], [[C:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[SHR]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %x_high = or i32 %x, 256
+  %add = add nuw i32 %x_high, %y
+  %shr = lshr i32 %add, %c
+  %cmp = icmp eq i32 %shr, 0
+  ret i1 %cmp
+}


        


More information about the llvm-commits mailing list