[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