[llvm] 2232843 - [ValueTracking] Recognize `X op (X != 0)` as non-zero
Noah Goldstein via llvm-commits
llvm-commits at lists.llvm.org
Mon May 20 13:26:33 PDT 2024
Author: Noah Goldstein
Date: 2024-05-20T15:25:40-05:00
New Revision: 223284316081e1af369c2d560da88e6211669250
URL: https://github.com/llvm/llvm-project/commit/223284316081e1af369c2d560da88e6211669250
DIFF: https://github.com/llvm/llvm-project/commit/223284316081e1af369c2d560da88e6211669250.diff
LOG: [ValueTracking] Recognize `X op (X != 0)` as non-zero
The ops supported are: `add`, `sub`, `xor`, `or`, `umax`, `uadd.sat`
Proofs: https://alive2.llvm.org/ce/z/8ZMSRg
The `add` case actually comes up in SPECInt, the rest are here mostly
for completeness.
Closes #88579
Added:
Modified:
llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Transforms/InstSimplify/known-non-zero.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 063162ed38ba5..3baa8ede28ffa 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2493,9 +2493,20 @@ static bool isNonZeroRecurrence(const PHINode *PN) {
}
}
+static bool matchOpWithOpEqZero(Value *Op0, Value *Op1) {
+ ICmpInst::Predicate Pred;
+ return (match(Op0, m_ZExtOrSExt(m_ICmp(Pred, m_Specific(Op1), m_Zero()))) ||
+ match(Op1, m_ZExtOrSExt(m_ICmp(Pred, m_Specific(Op0), m_Zero())))) &&
+ Pred == ICmpInst::ICMP_EQ;
+}
+
static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
const SimplifyQuery &Q, unsigned BitWidth, Value *X,
Value *Y, bool NSW, bool NUW) {
+ // (X + (X != 0)) is non zero
+ if (matchOpWithOpEqZero(X, Y))
+ return true;
+
if (NUW)
return isKnownNonZero(Y, DemandedElts, Q, Depth) ||
isKnownNonZero(X, DemandedElts, Q, Depth);
@@ -2539,6 +2550,11 @@ static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
static bool isNonZeroSub(const APInt &DemandedElts, unsigned Depth,
const SimplifyQuery &Q, unsigned BitWidth, Value *X,
Value *Y) {
+ // (X - (X != 0)) is non zero
+ // ((X != 0) - X) is non zero
+ if (matchOpWithOpEqZero(X, Y))
+ return true;
+
// TODO: Move this case into isKnownNonEqual().
if (auto *C = dyn_cast<Constant>(X))
if (C->isNullValue() && isKnownNonZero(Y, DemandedElts, Q, Depth))
@@ -2698,7 +2714,15 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
case Instruction::Sub:
return isNonZeroSub(DemandedElts, Depth, Q, BitWidth, I->getOperand(0),
I->getOperand(1));
+ case Instruction::Xor:
+ // (X ^ (X != 0)) is non zero
+ if (matchOpWithOpEqZero(I->getOperand(0), I->getOperand(1)))
+ return true;
+ break;
case Instruction::Or:
+ // (X | (X != 0)) is non zero
+ if (matchOpWithOpEqZero(I->getOperand(0), I->getOperand(1)))
+ return true;
// X | Y != 0 if X != 0 or Y != 0.
return isKnownNonZero(I->getOperand(1), DemandedElts, Q, Depth) ||
isKnownNonZero(I->getOperand(0), DemandedElts, Q, Depth);
@@ -2989,6 +3013,11 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
return isKnownNonZero(II->getArgOperand(0), Q, Depth);
case Intrinsic::umax:
case Intrinsic::uadd_sat:
+ // umax(X, (X != 0)) is non zero
+ // X +usat (X != 0) is non zero
+ if (matchOpWithOpEqZero(II->getArgOperand(0), II->getArgOperand(1)))
+ return true;
+
return isKnownNonZero(II->getArgOperand(1), DemandedElts, Q, Depth) ||
isKnownNonZero(II->getArgOperand(0), DemandedElts, Q, Depth);
case Intrinsic::smax: {
diff --git a/llvm/test/Transforms/InstSimplify/known-non-zero.ll b/llvm/test/Transforms/InstSimplify/known-non-zero.ll
index f56fbb40a40d4..965c333d306d1 100644
--- a/llvm/test/Transforms/InstSimplify/known-non-zero.ll
+++ b/llvm/test/Transforms/InstSimplify/known-non-zero.ll
@@ -403,11 +403,7 @@ define i1 @nonzero_reduce_or_fail(<2 x i8> %xx) {
define i1 @src_x_add_x_eq_0(i8 %x) {
; CHECK-LABEL: @src_x_add_x_eq_0(
-; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
-; CHECK-NEXT: [[V:%.*]] = add i8 [[X]], [[Y]]
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 false
;
%x_eq_0 = icmp eq i8 %x, 0
%y = zext i1 %x_eq_0 to i8
@@ -433,11 +429,7 @@ define i1 @src_x_add_x_eq_1_fail(i8 %x) {
define i1 @src_x_or_x_eq_0(i8 %x) {
; CHECK-LABEL: @src_x_or_x_eq_0(
-; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[Y:%.*]] = sext i1 [[X_EQ_0]] to i8
-; CHECK-NEXT: [[V:%.*]] = or i8 [[X]], [[Y]]
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 false
;
%x_eq_0 = icmp eq i8 %x, 0
%y = sext i1 %x_eq_0 to i8
@@ -463,11 +455,7 @@ define i1 @src_x_or_x_sle_0_fail(i8 %x) {
define i1 @src_x_xor_x_eq_0(i8 %x) {
; CHECK-LABEL: @src_x_xor_x_eq_0(
-; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
-; CHECK-NEXT: [[V:%.*]] = xor i8 [[X]], [[Y]]
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 false
;
%x_eq_0 = icmp eq i8 %x, 0
%y = zext i1 %x_eq_0 to i8
@@ -493,11 +481,7 @@ define i1 @src_x_xor_x_ne_0_fail(i8 %x) {
define i1 @src_x_sub0_x_eq_0(i8 %x) {
; CHECK-LABEL: @src_x_sub0_x_eq_0(
-; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[Y:%.*]] = sext i1 [[X_EQ_0]] to i8
-; CHECK-NEXT: [[V:%.*]] = sub i8 [[X]], [[Y]]
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 false
;
%x_eq_0 = icmp eq i8 %x, 0
%y = sext i1 %x_eq_0 to i8
@@ -523,11 +507,7 @@ define i1 @src_x_sub0_z_eq_0_fail(i8 %x, i8 %z) {
define i1 @src_x_sub1_x_eq_0(i8 %x) {
; CHECK-LABEL: @src_x_sub1_x_eq_0(
-; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
-; CHECK-NEXT: [[V:%.*]] = sub i8 [[Y]], [[X]]
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 false
;
%x_eq_0 = icmp eq i8 %x, 0
%y = zext i1 %x_eq_0 to i8
@@ -555,11 +535,7 @@ define i1 @src_x_sub1_x_eq_0_or_fail(i8 %x, i1 %c1) {
define i1 @src_x_umax_x_eq_0(i8 %x) {
; CHECK-LABEL: @src_x_umax_x_eq_0(
-; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[Y:%.*]] = sext i1 [[X_EQ_0]] to i8
-; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.umax.i8(i8 [[Y]], i8 [[X]])
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 false
;
%x_eq_0 = icmp eq i8 %x, 0
%y = sext i1 %x_eq_0 to i8
@@ -585,11 +561,7 @@ define i1 @src_x_umax_x_ugt_10_fail(i8 %x) {
define i1 @src_x_uadd.sat_x_eq_0(i8 %x) {
; CHECK-LABEL: @src_x_uadd.sat_x_eq_0(
-; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
-; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Y]], i8 [[X]])
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 false
;
%x_eq_0 = icmp eq i8 %x, 0
%y = zext i1 %x_eq_0 to i8
More information about the llvm-commits
mailing list