From 3491f2f4b0336cdb788fed3ff03a4b31c58db14e Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Thu, 10 Mar 2022 12:37:36 -0500 Subject: [PATCH] [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. --- .../Transforms/InstCombine/InstCombineCompares.cpp | 22 ++++++ llvm/test/Transforms/InstCombine/fabs.ll | 6 +- llvm/test/Transforms/InstCombine/fcmp.ll | 80 ++++++++-------------- 3 files changed, 52 insertions(+), 56 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index d3f6693..651d564 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -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 diff --git a/llvm/test/Transforms/InstCombine/fabs.ll b/llvm/test/Transforms/InstCombine/fabs.ll index 6d42ca9..725b906 100644 --- a/llvm/test/Transforms/InstCombine/fabs.ll +++ b/llvm/test/Transforms/InstCombine/fabs.ll @@ -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 diff --git a/llvm/test/Transforms/InstCombine/fcmp.ll b/llvm/test/Transforms/InstCombine/fcmp.ll index 5db6bd3..b0211d5 100644 --- a/llvm/test/Transforms/InstCombine/fcmp.ll +++ b/llvm/test/Transforms/InstCombine/fcmp.ll @@ -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 -- 2.7.4