Skip to content

Commit a756fce

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 17beeb1 commit a756fce

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
@@ -2420,9 +2420,20 @@ static bool isNonZeroRecurrence(const PHINode *PN) {
24202420
}
24212421
}
24222422

2423+
static bool matchOpWithOpEqZero(Value *Op0, Value *Op1) {
2424+
ICmpInst::Predicate Pred;
2425+
return (match(Op0, m_ZExtOrSExt(m_ICmp(Pred, m_Specific(Op1), m_Zero()))) ||
2426+
match(Op1, m_ZExtOrSExt(m_ICmp(Pred, m_Specific(Op0), m_Zero())))) &&
2427+
Pred == ICmpInst::ICMP_EQ;
2428+
}
2429+
24232430
static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
24242431
const SimplifyQuery &Q, unsigned BitWidth, Value *X,
24252432
Value *Y, bool NSW, bool NUW) {
2433+
// (X + (X != 0)) is non zero
2434+
if (matchOpWithOpEqZero(X, Y))
2435+
return true;
2436+
24262437
if (NUW)
24272438
return isKnownNonZero(Y, DemandedElts, Depth, Q) ||
24282439
isKnownNonZero(X, DemandedElts, Depth, Q);
@@ -2466,6 +2477,11 @@ static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
24662477
static bool isNonZeroSub(const APInt &DemandedElts, unsigned Depth,
24672478
const SimplifyQuery &Q, unsigned BitWidth, Value *X,
24682479
Value *Y) {
2480+
// (X - (X != 0)) is non zero
2481+
// ((X != 0) - X) is non zero
2482+
if (matchOpWithOpEqZero(X, Y))
2483+
return true;
2484+
24692485
// TODO: Move this case into isKnownNonEqual().
24702486
if (auto *C = dyn_cast<Constant>(X))
24712487
if (C->isNullValue() && isKnownNonZero(Y, DemandedElts, Depth, Q))
@@ -2618,7 +2634,15 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
26182634
case Instruction::Sub:
26192635
return isNonZeroSub(DemandedElts, Depth, Q, BitWidth, I->getOperand(0),
26202636
I->getOperand(1));
2637+
case Instruction::Xor:
2638+
// (X ^ (X != 0)) is non zero
2639+
if (matchOpWithOpEqZero(I->getOperand(0), I->getOperand(1)))
2640+
return true;
2641+
break;
26212642
case Instruction::Or:
2643+
// (X | (X != 0)) is non zero
2644+
if (matchOpWithOpEqZero(I->getOperand(0), I->getOperand(1)))
2645+
return true;
26222646
// X | Y != 0 if X != 0 or Y != 0.
26232647
return isKnownNonZero(I->getOperand(1), DemandedElts, Depth, Q) ||
26242648
isKnownNonZero(I->getOperand(0), DemandedElts, Depth, Q);
@@ -2909,6 +2933,11 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
29092933
return isKnownNonZero(II->getArgOperand(0), Depth, Q);
29102934
case Intrinsic::umax:
29112935
case Intrinsic::uadd_sat:
2936+
// umax(X, (X != 0)) is non zero
2937+
// X +usat (X != 0) is non zero
2938+
if (matchOpWithOpEqZero(II->getArgOperand(0), II->getArgOperand(1)))
2939+
return true;
2940+
29122941
return isKnownNonZero(II->getArgOperand(1), DemandedElts, Depth, Q) ||
29132942
isKnownNonZero(II->getArgOperand(0), DemandedElts, Depth, Q);
29142943
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
@@ -380,11 +380,7 @@ define <2 x i1> @insert_nonzero_any_idx_fail(<2 x i8> %xx, i8 %yy, i32 %idx) {
380380

381381
define i1 @src_x_add_x_eq_0(i8 %x) {
382382
; CHECK-LABEL: @src_x_add_x_eq_0(
383-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
384-
; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
385-
; CHECK-NEXT: [[V:%.*]] = add i8 [[X]], [[Y]]
386-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
387-
; CHECK-NEXT: ret i1 [[R]]
383+
; CHECK-NEXT: ret i1 false
388384
;
389385
%x_eq_0 = icmp eq i8 %x, 0
390386
%y = zext i1 %x_eq_0 to i8
@@ -410,11 +406,7 @@ define i1 @src_x_add_x_eq_1_fail(i8 %x) {
410406

411407
define i1 @src_x_or_x_eq_0(i8 %x) {
412408
; CHECK-LABEL: @src_x_or_x_eq_0(
413-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
414-
; CHECK-NEXT: [[Y:%.*]] = sext i1 [[X_EQ_0]] to i8
415-
; CHECK-NEXT: [[V:%.*]] = or i8 [[X]], [[Y]]
416-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
417-
; CHECK-NEXT: ret i1 [[R]]
409+
; CHECK-NEXT: ret i1 false
418410
;
419411
%x_eq_0 = icmp eq i8 %x, 0
420412
%y = sext i1 %x_eq_0 to i8
@@ -440,11 +432,7 @@ define i1 @src_x_or_x_sle_0_fail(i8 %x) {
440432

441433
define i1 @src_x_xor_x_eq_0(i8 %x) {
442434
; CHECK-LABEL: @src_x_xor_x_eq_0(
443-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
444-
; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
445-
; CHECK-NEXT: [[V:%.*]] = xor i8 [[X]], [[Y]]
446-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
447-
; CHECK-NEXT: ret i1 [[R]]
435+
; CHECK-NEXT: ret i1 false
448436
;
449437
%x_eq_0 = icmp eq i8 %x, 0
450438
%y = zext i1 %x_eq_0 to i8
@@ -470,11 +458,7 @@ define i1 @src_x_xor_x_ne_0_fail(i8 %x) {
470458

471459
define i1 @src_x_sub0_x_eq_0(i8 %x) {
472460
; CHECK-LABEL: @src_x_sub0_x_eq_0(
473-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
474-
; CHECK-NEXT: [[Y:%.*]] = sext i1 [[X_EQ_0]] to i8
475-
; CHECK-NEXT: [[V:%.*]] = sub i8 [[X]], [[Y]]
476-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
477-
; CHECK-NEXT: ret i1 [[R]]
461+
; CHECK-NEXT: ret i1 false
478462
;
479463
%x_eq_0 = icmp eq i8 %x, 0
480464
%y = sext i1 %x_eq_0 to i8
@@ -500,11 +484,7 @@ define i1 @src_x_sub0_z_eq_0_fail(i8 %x, i8 %z) {
500484

501485
define i1 @src_x_sub1_x_eq_0(i8 %x) {
502486
; CHECK-LABEL: @src_x_sub1_x_eq_0(
503-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
504-
; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
505-
; CHECK-NEXT: [[V:%.*]] = sub i8 [[Y]], [[X]]
506-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
507-
; CHECK-NEXT: ret i1 [[R]]
487+
; CHECK-NEXT: ret i1 false
508488
;
509489
%x_eq_0 = icmp eq i8 %x, 0
510490
%y = zext i1 %x_eq_0 to i8
@@ -532,11 +512,7 @@ define i1 @src_x_sub1_x_eq_0_or_fail(i8 %x, i1 %c1) {
532512

533513
define i1 @src_x_umax_x_eq_0(i8 %x) {
534514
; CHECK-LABEL: @src_x_umax_x_eq_0(
535-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
536-
; CHECK-NEXT: [[Y:%.*]] = sext i1 [[X_EQ_0]] to i8
537-
; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.umax.i8(i8 [[Y]], i8 [[X]])
538-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
539-
; CHECK-NEXT: ret i1 [[R]]
515+
; CHECK-NEXT: ret i1 false
540516
;
541517
%x_eq_0 = icmp eq i8 %x, 0
542518
%y = sext i1 %x_eq_0 to i8
@@ -562,11 +538,7 @@ define i1 @src_x_umax_x_ugt_10_fail(i8 %x) {
562538

563539
define i1 @src_x_uadd.sat_x_eq_0(i8 %x) {
564540
; CHECK-LABEL: @src_x_uadd.sat_x_eq_0(
565-
; CHECK-NEXT: [[X_EQ_0:%.*]] = icmp eq i8 [[X:%.*]], 0
566-
; CHECK-NEXT: [[Y:%.*]] = zext i1 [[X_EQ_0]] to i8
567-
; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[Y]], i8 [[X]])
568-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
569-
; CHECK-NEXT: ret i1 [[R]]
541+
; CHECK-NEXT: ret i1 false
570542
;
571543
%x_eq_0 = icmp eq i8 %x, 0
572544
%y = zext i1 %x_eq_0 to i8

0 commit comments

Comments
 (0)