Skip to content

Commit 2b8a9a4

Browse files
committed
[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.
1 parent bf7eb96 commit 2b8a9a4

File tree

2 files changed

+36
-35
lines changed

2 files changed

+36
-35
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,9 +2449,20 @@ static bool isNonZeroRecurrence(const PHINode *PN) {
24492449
}
24502450
}
24512451

2452+
static bool matchOpWithOpEqZero(Value *Op0, Value *Op1) {
2453+
ICmpInst::Predicate Pred;
2454+
return (match(Op0, m_ZExtOrSExt(m_ICmp(Pred, m_Specific(Op1), m_Zero()))) ||
2455+
match(Op1, m_ZExtOrSExt(m_ICmp(Pred, m_Specific(Op0), m_Zero())))) &&
2456+
Pred == ICmpInst::ICMP_EQ;
2457+
}
2458+
24522459
static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
24532460
const SimplifyQuery &Q, unsigned BitWidth, Value *X,
24542461
Value *Y, bool NSW, bool NUW) {
2462+
// (X + (X != 0)) is non zero
2463+
if (matchOpWithOpEqZero(X, Y))
2464+
return true;
2465+
24552466
if (NUW)
24562467
return isKnownNonZero(Y, DemandedElts, Q, Depth) ||
24572468
isKnownNonZero(X, DemandedElts, Q, Depth);
@@ -2495,6 +2506,11 @@ static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
24952506
static bool isNonZeroSub(const APInt &DemandedElts, unsigned Depth,
24962507
const SimplifyQuery &Q, unsigned BitWidth, Value *X,
24972508
Value *Y) {
2509+
// (X - (X != 0)) is non zero
2510+
// ((X != 0) - X) is non zero
2511+
if (matchOpWithOpEqZero(X, Y))
2512+
return true;
2513+
24982514
// TODO: Move this case into isKnownNonEqual().
24992515
if (auto *C = dyn_cast<Constant>(X))
25002516
if (C->isNullValue() && isKnownNonZero(Y, DemandedElts, Q, Depth))
@@ -2654,7 +2670,15 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
26542670
case Instruction::Sub:
26552671
return isNonZeroSub(DemandedElts, Depth, Q, BitWidth, I->getOperand(0),
26562672
I->getOperand(1));
2673+
case Instruction::Xor:
2674+
// (X ^ (X != 0)) is non zero
2675+
if (matchOpWithOpEqZero(I->getOperand(0), I->getOperand(1)))
2676+
return true;
2677+
break;
26572678
case Instruction::Or:
2679+
// (X | (X != 0)) is non zero
2680+
if (matchOpWithOpEqZero(I->getOperand(0), I->getOperand(1)))
2681+
return true;
26582682
// X | Y != 0 if X != 0 or Y != 0.
26592683
return isKnownNonZero(I->getOperand(1), DemandedElts, Q, Depth) ||
26602684
isKnownNonZero(I->getOperand(0), DemandedElts, Q, Depth);
@@ -2945,6 +2969,11 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
29452969
return isKnownNonZero(II->getArgOperand(0), Q, Depth);
29462970
case Intrinsic::umax:
29472971
case Intrinsic::uadd_sat:
2972+
// umax(X, (X != 0)) is non zero
2973+
// X +usat (X != 0) is non zero
2974+
if (matchOpWithOpEqZero(II->getArgOperand(0), II->getArgOperand(1)))
2975+
return true;
2976+
29482977
return isKnownNonZero(II->getArgOperand(1), DemandedElts, Q, Depth) ||
29492978
isKnownNonZero(II->getArgOperand(0), DemandedElts, Q, Depth);
29502979
case Intrinsic::smax: {

llvm/test/Transforms/InstSimplify/known-non-zero.ll

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -403,11 +403,7 @@ define i1 @nonzero_reduce_or_fail(<2 x i8> %xx) {
403403

404404
define i1 @src_x_add_x_eq_0(i8 %x) {
405405
; CHECK-LABEL: @src_x_add_x_eq_0(
406-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
407-
; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
408-
; CHECK-NEXT: [[V:%.*]] = add i8 [[X]], [[Y]]
409-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
410-
; CHECK-NEXT: ret i1 [[R]]
406+
; CHECK-NEXT: ret i1 false
411407
;
412408
%x_eq_0 = icmp eq i8 %x, 0
413409
%y = zext i1 %x_eq_0 to i8
@@ -433,11 +429,7 @@ define i1 @src_x_add_x_eq_1_fail(i8 %x) {
433429

434430
define i1 @src_x_or_x_eq_0(i8 %x) {
435431
; CHECK-LABEL: @src_x_or_x_eq_0(
436-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
437-
; CHECK-NEXT: [[Y:%.*]] = sext i1 [[X_EQ_0]] to i8
438-
; CHECK-NEXT: [[V:%.*]] = or i8 [[X]], [[Y]]
439-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
440-
; CHECK-NEXT: ret i1 [[R]]
432+
; CHECK-NEXT: ret i1 false
441433
;
442434
%x_eq_0 = icmp eq i8 %x, 0
443435
%y = sext i1 %x_eq_0 to i8
@@ -463,11 +455,7 @@ define i1 @src_x_or_x_sle_0_fail(i8 %x) {
463455

464456
define i1 @src_x_xor_x_eq_0(i8 %x) {
465457
; CHECK-LABEL: @src_x_xor_x_eq_0(
466-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
467-
; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
468-
; CHECK-NEXT: [[V:%.*]] = xor i8 [[X]], [[Y]]
469-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
470-
; CHECK-NEXT: ret i1 [[R]]
458+
; CHECK-NEXT: ret i1 false
471459
;
472460
%x_eq_0 = icmp eq i8 %x, 0
473461
%y = zext i1 %x_eq_0 to i8
@@ -493,11 +481,7 @@ define i1 @src_x_xor_x_ne_0_fail(i8 %x) {
493481

494482
define i1 @src_x_sub0_x_eq_0(i8 %x) {
495483
; CHECK-LABEL: @src_x_sub0_x_eq_0(
496-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
497-
; CHECK-NEXT: [[Y:%.*]] = sext i1 [[X_EQ_0]] to i8
498-
; CHECK-NEXT: [[V:%.*]] = sub i8 [[X]], [[Y]]
499-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
500-
; CHECK-NEXT: ret i1 [[R]]
484+
; CHECK-NEXT: ret i1 false
501485
;
502486
%x_eq_0 = icmp eq i8 %x, 0
503487
%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) {
523507

524508
define i1 @src_x_sub1_x_eq_0(i8 %x) {
525509
; CHECK-LABEL: @src_x_sub1_x_eq_0(
526-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
527-
; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
528-
; CHECK-NEXT: [[V:%.*]] = sub i8 [[Y]], [[X]]
529-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
530-
; CHECK-NEXT: ret i1 [[R]]
510+
; CHECK-NEXT: ret i1 false
531511
;
532512
%x_eq_0 = icmp eq i8 %x, 0
533513
%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) {
555535

556536
define i1 @src_x_umax_x_eq_0(i8 %x) {
557537
; CHECK-LABEL: @src_x_umax_x_eq_0(
558-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
559-
; CHECK-NEXT: [[Y:%.*]] = sext i1 [[X_EQ_0]] to i8
560-
; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.umax.i8(i8 [[Y]], i8 [[X]])
561-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
562-
; CHECK-NEXT: ret i1 [[R]]
538+
; CHECK-NEXT: ret i1 false
563539
;
564540
%x_eq_0 = icmp eq i8 %x, 0
565541
%y = sext i1 %x_eq_0 to i8
@@ -585,11 +561,7 @@ define i1 @src_x_umax_x_ugt_10_fail(i8 %x) {
585561

586562
define i1 @src_x_uadd.sat_x_eq_0(i8 %x) {
587563
; CHECK-LABEL: @src_x_uadd.sat_x_eq_0(
588-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
589-
; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
590-
; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Y]], i8 [[X]])
591-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
592-
; CHECK-NEXT: ret i1 [[R]]
564+
; CHECK-NEXT: ret i1 false
593565
;
594566
%x_eq_0 = icmp eq i8 %x, 0
595567
%y = zext i1 %x_eq_0 to i8

0 commit comments

Comments
 (0)