Skip to content

Commit 2232843

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. Closes #88579
1 parent 2a45f89 commit 2232843

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
@@ -2493,9 +2493,20 @@ static bool isNonZeroRecurrence(const PHINode *PN) {
24932493
}
24942494
}
24952495

2496+
static bool matchOpWithOpEqZero(Value *Op0, Value *Op1) {
2497+
ICmpInst::Predicate Pred;
2498+
return (match(Op0, m_ZExtOrSExt(m_ICmp(Pred, m_Specific(Op1), m_Zero()))) ||
2499+
match(Op1, m_ZExtOrSExt(m_ICmp(Pred, m_Specific(Op0), m_Zero())))) &&
2500+
Pred == ICmpInst::ICMP_EQ;
2501+
}
2502+
24962503
static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
24972504
const SimplifyQuery &Q, unsigned BitWidth, Value *X,
24982505
Value *Y, bool NSW, bool NUW) {
2506+
// (X + (X != 0)) is non zero
2507+
if (matchOpWithOpEqZero(X, Y))
2508+
return true;
2509+
24992510
if (NUW)
25002511
return isKnownNonZero(Y, DemandedElts, Q, Depth) ||
25012512
isKnownNonZero(X, DemandedElts, Q, Depth);
@@ -2539,6 +2550,11 @@ static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
25392550
static bool isNonZeroSub(const APInt &DemandedElts, unsigned Depth,
25402551
const SimplifyQuery &Q, unsigned BitWidth, Value *X,
25412552
Value *Y) {
2553+
// (X - (X != 0)) is non zero
2554+
// ((X != 0) - X) is non zero
2555+
if (matchOpWithOpEqZero(X, Y))
2556+
return true;
2557+
25422558
// TODO: Move this case into isKnownNonEqual().
25432559
if (auto *C = dyn_cast<Constant>(X))
25442560
if (C->isNullValue() && isKnownNonZero(Y, DemandedElts, Q, Depth))
@@ -2698,7 +2714,15 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
26982714
case Instruction::Sub:
26992715
return isNonZeroSub(DemandedElts, Depth, Q, BitWidth, I->getOperand(0),
27002716
I->getOperand(1));
2717+
case Instruction::Xor:
2718+
// (X ^ (X != 0)) is non zero
2719+
if (matchOpWithOpEqZero(I->getOperand(0), I->getOperand(1)))
2720+
return true;
2721+
break;
27012722
case Instruction::Or:
2723+
// (X | (X != 0)) is non zero
2724+
if (matchOpWithOpEqZero(I->getOperand(0), I->getOperand(1)))
2725+
return true;
27022726
// X | Y != 0 if X != 0 or Y != 0.
27032727
return isKnownNonZero(I->getOperand(1), DemandedElts, Q, Depth) ||
27042728
isKnownNonZero(I->getOperand(0), DemandedElts, Q, Depth);
@@ -2989,6 +3013,11 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
29893013
return isKnownNonZero(II->getArgOperand(0), Q, Depth);
29903014
case Intrinsic::umax:
29913015
case Intrinsic::uadd_sat:
3016+
// umax(X, (X != 0)) is non zero
3017+
// X +usat (X != 0) is non zero
3018+
if (matchOpWithOpEqZero(II->getArgOperand(0), II->getArgOperand(1)))
3019+
return true;
3020+
29923021
return isKnownNonZero(II->getArgOperand(1), DemandedElts, Q, Depth) ||
29933022
isKnownNonZero(II->getArgOperand(0), DemandedElts, Q, Depth);
29943023
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)