[InstSimplify] Fold and/or using implied conditions

This adds two conjugated folds:

 * A | B -> B if A implies B (https://alive2.llvm.org/ce/z/R6GU4j)
 * A & B -> A if A implies B (https://alive2.llvm.org/ce/z/EGMqyy)

If A and B are icmps themselves, we will usually fold this through
other logic already (though the tests show a couple additional cases
we previously missed). However, isImpliedCond() also supports A
being of the form X & Y, which allows us to handle cases like
(X & Y) | B where X implies B. This addresses the regression from
D125398.

Something that notably doesn't work yet is the (X | Y) & B case.
This is due to an asymmetry in the isImpliedCondition()
implementation that will have to be addressed separately.

Differential Revision: https://reviews.llvm.org/D125530
This commit is contained in:
Nikita Popov 2022-05-13 10:38:33 +02:00
parent 5150d653aa
commit ddfee07519
4 changed files with 31 additions and 31 deletions

View File

@ -2219,6 +2219,15 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
match(Op1, m_c_Xor(m_Specific(Or), m_Specific(Y))))
return Constant::getNullValue(Op0->getType());
if (Op0->getType()->isIntOrIntVectorTy(1)) {
// Op0&Op1 -> Op0 where Op0 implies Op1
if (isImpliedCondition(Op0, Op1, Q.DL).getValueOr(false))
return Op0;
// Op0&Op1 -> Op1 where Op1 implies Op0
if (isImpliedCondition(Op1, Op0, Q.DL).getValueOr(false))
return Op1;
}
return nullptr;
}
@ -2451,6 +2460,15 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
if (Value *V = ThreadBinOpOverPHI(Instruction::Or, Op0, Op1, Q, MaxRecurse))
return V;
if (Op0->getType()->isIntOrIntVectorTy(1)) {
// Op0|Op1 -> Op1 where Op0 implies Op1
if (isImpliedCondition(Op0, Op1, Q.DL).getValueOr(false))
return Op1;
// Op0|Op1 -> Op0 where Op1 implies Op0
if (isImpliedCondition(Op1, Op0, Q.DL).getValueOr(false))
return Op0;
}
return nullptr;
}

View File

@ -1214,9 +1214,7 @@ define <2 x i1> @ult_ule_vec(<2 x i8> %a, <2 x i8> %b) {
define i1 @ult_uge_swap(i8 %a, i8 %b) {
; CHECK-LABEL: @ult_uge_swap(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 [[B]], [[A]]
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: ret i1 [[AND]]
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp1 = icmp ult i8 %a, %b
%cmp2 = icmp uge i8 %b, %a

View File

@ -3,11 +3,8 @@
define i1 @or_implied(i8 %x, i1 %c) {
; CHECK-LABEL: @or_implied(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X]], 1
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], [[C:%.*]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[AND]], [[CMP2]]
; CHECK-NEXT: ret i1 [[OR]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp eq i8 %x, 0
%cmp2 = icmp ne i8 %x, 1
@ -18,11 +15,8 @@ define i1 @or_implied(i8 %x, i1 %c) {
define i1 @or_implied_comm1(i8 %x, i1 %c) {
; CHECK-LABEL: @or_implied_comm1(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X]], 1
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], [[C:%.*]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP2]], [[AND]]
; CHECK-NEXT: ret i1 [[OR]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp eq i8 %x, 0
%cmp2 = icmp ne i8 %x, 1
@ -33,11 +27,8 @@ define i1 @or_implied_comm1(i8 %x, i1 %c) {
define i1 @or_implied_comm2(i8 %x, i1 %c) {
; CHECK-LABEL: @or_implied_comm2(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X]], 1
; CHECK-NEXT: [[AND:%.*]] = and i1 [[C:%.*]], [[CMP]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[AND]], [[CMP2]]
; CHECK-NEXT: ret i1 [[OR]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp eq i8 %x, 0
%cmp2 = icmp ne i8 %x, 1
@ -48,11 +39,8 @@ define i1 @or_implied_comm2(i8 %x, i1 %c) {
define i1 @or_implied_comm3(i8 %x, i1 %c) {
; CHECK-LABEL: @or_implied_comm3(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X]], 1
; CHECK-NEXT: [[AND:%.*]] = and i1 [[C:%.*]], [[CMP]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP2]], [[AND]]
; CHECK-NEXT: ret i1 [[OR]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = icmp eq i8 %x, 0
%cmp2 = icmp ne i8 %x, 1

View File

@ -1213,10 +1213,8 @@ define <2 x i1> @ult_ule_vec(<2 x i8> %a, <2 x i8> %b) {
define i1 @ult_ne_swap(i8 %a, i8 %b) {
; CHECK-LABEL: @ult_ne_swap(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[B]], [[A]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: ret i1 [[OR]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp ult i8 %a, %b
%cmp2 = icmp ne i8 %b, %a
@ -1226,10 +1224,8 @@ define i1 @ult_ne_swap(i8 %a, i8 %b) {
define i1 @ult_ule_swap(i8 %a, i8 %b) {
; CHECK-LABEL: @ult_ule_swap(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 [[B]], [[A]]
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: ret i1 [[OR]]
; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i8 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = icmp ult i8 %a, %b
%cmp2 = icmp uge i8 %b, %a