[InstCombine] replace negated operand in fcmp with 0.0

X (any pred) -X --> X (any pred) 0.0

This works with all FP values and preserves FMF.
Alive2 examples:
https://alive2.llvm.org/ce/z/dj6jhp

This can also create one of the patterns that we match as "fabs"
as shown in one of the test diffs.
This commit is contained in:
Sanjay Patel 2022-03-10 12:37:36 -05:00
parent 16da22d45a
commit 3491f2f4b0
3 changed files with 52 additions and 56 deletions

View file

@ -6527,6 +6527,25 @@ static Instruction *foldFabsWithFcmpZero(FCmpInst &I, InstCombinerImpl &IC) {
}
}
static Instruction *foldFCmpFNegCommonOp(FCmpInst &I) {
CmpInst::Predicate Pred = I.getPredicate();
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
// Canonicalize fneg as Op1.
if (match(Op0, m_FNeg(m_Value())) && !match(Op1, m_FNeg(m_Value()))) {
std::swap(Op0, Op1);
Pred = I.getSwappedPredicate();
}
if (!match(Op1, m_FNeg(m_Specific(Op0))))
return nullptr;
// Replace the negated operand with 0.0:
// fcmp Pred Op0, -Op0 --> fcmp Pred Op0, 0.0
Constant *Zero = ConstantFP::getNullValue(Op0->getType());
return new FCmpInst(Pred, Op0, Zero, "", &I);
}
Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
bool Changed = false;
@ -6585,6 +6604,9 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
if (match(Op0, m_FNeg(m_Value(X))) && match(Op1, m_FNeg(m_Value(Y))))
return new FCmpInst(I.getSwappedPredicate(), X, Y, "", &I);
if (Instruction *R = foldFCmpFNegCommonOp(I))
return R;
// Test if the FCmpInst instruction is used exclusively by a select as
// part of a minimum or maximum operation. If so, refrain from doing
// any other folding. This helps out other analyses which understand

View file

@ -351,10 +351,8 @@ define fp128 @select_fcmp_ogt_zero(fp128 %x) {
define float @select_fcmp_ogt_fneg(float %a) {
; CHECK-LABEL: @select_fcmp_ogt_fneg(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[FNEG]], [[A]]
; CHECK-NEXT: [[R:%.*]] = select nsz i1 [[CMP]], float [[A]], float [[FNEG]]
; CHECK-NEXT: ret float [[R]]
; CHECK-NEXT: [[TMP1:%.*]] = call nsz float @llvm.fabs.f32(float [[A:%.*]])
; CHECK-NEXT: ret float [[TMP1]]
;
%fneg = fneg float %a
%cmp = fcmp ogt float %a, %fneg

View file

@ -832,8 +832,7 @@ define i1 @lossy_uno(half %x) {
define i1 @fneg_oeq(float %a) {
; CHECK-LABEL: @fneg_oeq(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -843,8 +842,7 @@ define i1 @fneg_oeq(float %a) {
define i1 @fneg_ogt(half %a) {
; CHECK-LABEL: @fneg_ogt(
; CHECK-NEXT: [[FNEG:%.*]] = fneg half [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp fast ogt half [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp fast olt half [[A:%.*]], 0xH0000
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg half %a
@ -854,8 +852,7 @@ define i1 @fneg_ogt(half %a) {
define <2 x i1> @fneg_oge(<2 x float> %a) {
; CHECK-LABEL: @fneg_oge(
; CHECK-NEXT: [[FNEG:%.*]] = fneg fast <2 x float> [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge <2 x float> [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ole <2 x float> [[A:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%fneg = fneg fast <2 x float> %a
@ -867,7 +864,7 @@ define i1 @fneg_olt(float %a, float* %q) {
; CHECK-LABEL: @fneg_olt(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: store float [[FNEG]], float* [[Q:%.*]], align 4
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -878,8 +875,7 @@ define i1 @fneg_olt(float %a, float* %q) {
define i1 @fneg_ole(float %a) {
; CHECK-LABEL: @fneg_ole(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nsz ole float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nsz oge float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -889,8 +885,7 @@ define i1 @fneg_ole(float %a) {
define i1 @fneg_one(float %a) {
; CHECK-LABEL: @fneg_one(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan one float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan one float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -900,8 +895,7 @@ define i1 @fneg_one(float %a) {
define i1 @fneg_ord(float %a) {
; CHECK-LABEL: @fneg_ord(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ord float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ord float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -911,8 +905,7 @@ define i1 @fneg_ord(float %a) {
define i1 @fneg_uno(float %a) {
; CHECK-LABEL: @fneg_uno(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp uno float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp uno float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -922,8 +915,7 @@ define i1 @fneg_uno(float %a) {
define i1 @fneg_ueq(half %a) {
; CHECK-LABEL: @fneg_ueq(
; CHECK-NEXT: [[FNEG:%.*]] = fneg half [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp fast ueq half [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp fast ueq half [[A:%.*]], 0xH0000
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg half %a
@ -933,8 +925,7 @@ define i1 @fneg_ueq(half %a) {
define <2 x i1> @fneg_ugt(<2 x float> %a) {
; CHECK-LABEL: @fneg_ugt(
; CHECK-NEXT: [[FNEG:%.*]] = fneg fast <2 x float> [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ugt <2 x float> [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ult <2 x float> [[A:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%fneg = fneg fast <2 x float> %a
@ -946,7 +937,7 @@ define i1 @fneg_uge(float %a, float* %q) {
; CHECK-LABEL: @fneg_uge(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: store float [[FNEG]], float* [[Q:%.*]], align 4
; CHECK-NEXT: [[CMP:%.*]] = fcmp uge float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ule float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -957,8 +948,7 @@ define i1 @fneg_uge(float %a, float* %q) {
define i1 @fneg_ult(float %a) {
; CHECK-LABEL: @fneg_ult(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nsz ult float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nsz ugt float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -968,8 +958,7 @@ define i1 @fneg_ult(float %a) {
define i1 @fneg_ule(float %a) {
; CHECK-LABEL: @fneg_ule(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan ule float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan uge float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -979,8 +968,7 @@ define i1 @fneg_ule(float %a) {
define i1 @fneg_une(float %a) {
; CHECK-LABEL: @fneg_une(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf une float [[FNEG]], [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf une float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%fneg = fneg float %a
@ -991,8 +979,7 @@ define i1 @fneg_une(float %a) {
define i1 @fneg_oeq_swap(float %p) {
; CHECK-LABEL: @fneg_oeq_swap(
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization
@ -1004,8 +991,7 @@ define i1 @fneg_oeq_swap(float %p) {
define i1 @fneg_ogt_swap(half %p) {
; CHECK-LABEL: @fneg_ogt_swap(
; CHECK-NEXT: [[A:%.*]] = fadd half [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg half [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp fast ogt half [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp fast ogt half [[A]], 0xH0000
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd half %p, %p ; thwart complexity-based canonicalization
@ -1017,8 +1003,7 @@ define i1 @fneg_ogt_swap(half %p) {
define <2 x i1> @fneg_oge_swap(<2 x float> %p) {
; CHECK-LABEL: @fneg_oge_swap(
; CHECK-NEXT: [[A:%.*]] = fadd <2 x float> [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg fast <2 x float> [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge <2 x float> [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge <2 x float> [[A]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%a = fadd <2 x float> %p, %p ; thwart complexity-based canonicalization
@ -1032,7 +1017,7 @@ define i1 @fneg_olt_swap(float %p, float* %q) {
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: store float [[FNEG]], float* [[Q:%.*]], align 4
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization
@ -1045,8 +1030,7 @@ define i1 @fneg_olt_swap(float %p, float* %q) {
define i1 @fneg_ole_swap(float %p) {
; CHECK-LABEL: @fneg_ole_swap(
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nsz ole float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nsz ole float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization
@ -1058,8 +1042,7 @@ define i1 @fneg_ole_swap(float %p) {
define i1 @fneg_one_swap(float %p) {
; CHECK-LABEL: @fneg_one_swap(
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan one float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan one float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization
@ -1071,8 +1054,7 @@ define i1 @fneg_one_swap(float %p) {
define i1 @fneg_ord_swap(float %p) {
; CHECK-LABEL: @fneg_ord_swap(
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ord float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ord float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization
@ -1084,8 +1066,7 @@ define i1 @fneg_ord_swap(float %p) {
define i1 @fneg_uno_swap(float %p) {
; CHECK-LABEL: @fneg_uno_swap(
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp uno float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp uno float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization
@ -1097,8 +1078,7 @@ define i1 @fneg_uno_swap(float %p) {
define i1 @fneg_ueq_swap(half %p) {
; CHECK-LABEL: @fneg_ueq_swap(
; CHECK-NEXT: [[A:%.*]] = fadd half [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg half [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp fast ueq half [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp fast ueq half [[A]], 0xH0000
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd half %p, %p ; thwart complexity-based canonicalization
@ -1110,8 +1090,7 @@ define i1 @fneg_ueq_swap(half %p) {
define <2 x i1> @fneg_ugt_swap(<2 x float> %p) {
; CHECK-LABEL: @fneg_ugt_swap(
; CHECK-NEXT: [[A:%.*]] = fadd <2 x float> [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg fast <2 x float> [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ugt <2 x float> [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ugt <2 x float> [[A]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%a = fadd <2 x float> %p, %p ; thwart complexity-based canonicalization
@ -1125,7 +1104,7 @@ define i1 @fneg_uge_swap(float %p, float* %q) {
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: store float [[FNEG]], float* [[Q:%.*]], align 4
; CHECK-NEXT: [[CMP:%.*]] = fcmp uge float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp uge float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization
@ -1138,8 +1117,7 @@ define i1 @fneg_uge_swap(float %p, float* %q) {
define i1 @fneg_ult_swap(float %p) {
; CHECK-LABEL: @fneg_ult_swap(
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nsz ult float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nsz ult float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization
@ -1151,8 +1129,7 @@ define i1 @fneg_ult_swap(float %p) {
define i1 @fneg_ule_swap(float %p) {
; CHECK-LABEL: @fneg_ule_swap(
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan ule float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan ule float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization
@ -1164,8 +1141,7 @@ define i1 @fneg_ule_swap(float %p) {
define i1 @fneg_une_swap(float %p) {
; CHECK-LABEL: @fneg_une_swap(
; CHECK-NEXT: [[A:%.*]] = fadd float [[P:%.*]], [[P]]
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf une float [[A]], [[FNEG]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf une float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%a = fadd float %p, %p ; thwart complexity-based canonicalization