From: Sanjay Patel Date: Wed, 31 Oct 2018 16:34:43 +0000 (+0000) Subject: [InstCombine] refactor fabs+fcmp fold; NFC X-Git-Tag: llvmorg-8.0.0-rc1~5351 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1c254c6716cd01a228c5c35a225a45e6d8ee51ad;p=platform%2Fupstream%2Fllvm.git [InstCombine] refactor fabs+fcmp fold; NFC Also, remove/replace/minimize/enhance the tests for this fold. The code drops FMF, so it needs more tests and at least 1 fix. llvm-svn: 345734 --- diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 1ad648fe783a..9155ad125983 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -5288,6 +5288,46 @@ static Instruction *foldFCmpReciprocalAndZero(FCmpInst &I, Instruction *LHSI, return NewFCI; } +/// Optimize fabs(X) compared with zero. +static Instruction *foldFabsWithFcmpZero(FCmpInst &I) { + Value *X; + if (!match(I.getOperand(0), m_Intrinsic(m_Value(X))) || + !match(I.getOperand(1), m_PosZeroFP())) + return nullptr; + + switch (I.getPredicate()) { + case FCmpInst::FCMP_UGE: + case FCmpInst::FCMP_OLT: + // fabs(X) >= 0.0 --> true + // fabs(X) < 0.0 --> false + llvm_unreachable("fcmp should have simplified"); + + case FCmpInst::FCMP_OGT: + // fabs(X) > 0.0 --> X != 0.0 + return new FCmpInst(FCmpInst::FCMP_ONE, X, I.getOperand(1)); + + case FCmpInst::FCMP_OLE: + // fabs(X) <= 0.0 --> X == 0.0 + return new FCmpInst(FCmpInst::FCMP_OEQ, X, I.getOperand(1)); + + case FCmpInst::FCMP_OGE: + // fabs(X) >= 0.0 --> !isnan(X) + assert(!I.hasNoNaNs() && "fcmp should have simplified"); + return new FCmpInst(FCmpInst::FCMP_ORD, X, I.getOperand(1)); + + case FCmpInst::FCMP_OEQ: + case FCmpInst::FCMP_UEQ: + case FCmpInst::FCMP_ONE: + case FCmpInst::FCMP_UNE: + // fabs(X) == 0.0 --> X == 0.0 + // fabs(X) != 0.0 --> X != 0.0 + return new FCmpInst(I.getPredicate(), X, I.getOperand(1)); + + default: + return nullptr; + } +} + Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) { bool Changed = false; @@ -5418,45 +5458,11 @@ Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) { if (Instruction *Res = foldCmpLoadFromIndexedGlobal(GEP, GV, I)) return Res; break; - case Instruction::Call: { - if (!RHSC->isNullValue()) - break; - - CallInst *CI = cast(LHSI); - Intrinsic::ID IID = getIntrinsicForCallSite(CI, &TLI); - if (IID != Intrinsic::fabs) - break; - - // Various optimization for fabs compared with zero. - switch (Pred) { - default: - break; - case FCmpInst::FCMP_UGE: - case FCmpInst::FCMP_OLT: - // fabs(x) >= 0.0 --> true - // fabs(x) < 0.0 --> false - llvm_unreachable("fcmp should have simplified"); - - // fabs(x) > 0 --> x != 0 - case FCmpInst::FCMP_OGT: - return new FCmpInst(FCmpInst::FCMP_ONE, CI->getArgOperand(0), RHSC); - // fabs(x) <= 0 --> x == 0 - case FCmpInst::FCMP_OLE: - return new FCmpInst(FCmpInst::FCMP_OEQ, CI->getArgOperand(0), RHSC); - // fabs(x) >= 0 --> !isnan(x) - case FCmpInst::FCMP_OGE: - assert(!I.hasNoNaNs() && "fcmp should have simplified"); - return new FCmpInst(FCmpInst::FCMP_ORD, CI->getArgOperand(0), RHSC); - // fabs(x) == 0 --> x == 0 - // fabs(x) != 0 --> x != 0 - case FCmpInst::FCMP_OEQ: - case FCmpInst::FCMP_UEQ: - case FCmpInst::FCMP_ONE: - case FCmpInst::FCMP_UNE: - return new FCmpInst(Pred, CI->getArgOperand(0), RHSC); - } - } - } + case Instruction::Call: + if (Instruction *X = foldFabsWithFcmpZero(I)) + return X; + break; + } } // fcmp pred (fneg x), (fneg y) -> fcmp swap(pred) x, y diff --git a/llvm/test/Transforms/InstCombine/fcmp.ll b/llvm/test/Transforms/InstCombine/fcmp.ll index ff47496abe9b..c19aae4c03b7 100644 --- a/llvm/test/Transforms/InstCombine/fcmp.ll +++ b/llvm/test/Transforms/InstCombine/fcmp.ll @@ -1,7 +1,9 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -instcombine < %s | FileCheck %s -declare double @llvm.fabs.f64(double) readnone +declare half @llvm.fabs.f16(half) +declare double @llvm.fabs.f64(double) +declare <2 x float> @llvm.fabs.v2f32(<2 x float>) define i1 @test1(float %x, float %y) { ; CHECK-LABEL: @test1( @@ -133,194 +135,92 @@ define float @test8(float %x) { ; Float comparison to zero shouldn't cast to double. } -declare double @fabs(double) readnone - -define i32 @test9(double %a) { -; CHECK-LABEL: @test9( -; CHECK-NEXT: ret i32 0 -; - %call = tail call double @fabs(double %a) - %cmp = fcmp olt double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define i32 @test9_intrinsic(double %a) { -; CHECK-LABEL: @test9_intrinsic( -; CHECK-NEXT: ret i32 0 -; - %call = tail call double @llvm.fabs.f64(double %a) - %cmp = fcmp olt double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define i32 @test10(double %a) { -; CHECK-LABEL: @test10( -; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] +define i1 @fabs_uge(double %a) { +; CHECK-LABEL: @fabs_uge( +; CHECK-NEXT: ret i1 true ; - %call = tail call double @fabs(double %a) - %cmp = fcmp ole double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv + %call = call double @llvm.fabs.f64(double %a) + %cmp = fcmp uge double %call, 0.0 + ret i1 %cmp } -define i32 @test10_intrinsic(double %a) { -; CHECK-LABEL: @test10_intrinsic( -; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] +define i1 @fabs_olt(half %a) { +; CHECK-LABEL: @fabs_olt( +; CHECK-NEXT: ret i1 false ; - %call = tail call double @llvm.fabs.f64(double %a) - %cmp = fcmp ole double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv + %call = call half @llvm.fabs.f16(half %a) + %cmp = fcmp olt half %call, 0.0 + ret i1 %cmp } -define i32 @test11(double %a) { -; CHECK-LABEL: @test11( -; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] +define <2 x i1> @fabs_ole(<2 x float> %a) { +; CHECK-LABEL: @fabs_ole( +; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq <2 x float> [[A:%.*]], zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[CMP]] ; - %call = tail call double @fabs(double %a) - %cmp = fcmp ogt double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv + %call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a) + %cmp = fcmp ole <2 x float> %call, zeroinitializer + ret <2 x i1> %cmp } -define i32 @test11_intrinsic(double %a) { -; CHECK-LABEL: @test11_intrinsic( +define i1 @fabs_ogt(double %a) { +; CHECK-LABEL: @fabs_ogt( ; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] -; - %call = tail call double @llvm.fabs.f64(double %a) - %cmp = fcmp ogt double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define i32 @test12(double %a) { -; CHECK-LABEL: @test12( -; CHECK-NEXT: [[CMP:%.*]] = fcmp ord double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] +; CHECK-NEXT: ret i1 [[CMP]] ; - %call = tail call double @fabs(double %a) - %cmp = fcmp oge double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv + %call = call double @llvm.fabs.f64(double %a) + %cmp = fcmp ogt double %call, 0.0 + ret i1 %cmp } -define i32 @test12_intrinsic(double %a) { -; CHECK-LABEL: @test12_intrinsic( +define i1 @fabs_oge(double %a) { +; CHECK-LABEL: @fabs_oge( ; CHECK-NEXT: [[CMP:%.*]] = fcmp ord double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] -; - %call = tail call double @llvm.fabs.f64(double %a) - %cmp = fcmp oge double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define i32 @test13(double %a) { -; CHECK-LABEL: @test13( -; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] -; - %call = tail call double @fabs(double %a) - %cmp = fcmp une double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define i32 @test13_intrinsic(double %a) { -; CHECK-LABEL: @test13_intrinsic( -; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] +; CHECK-NEXT: ret i1 [[CMP]] ; - %call = tail call double @llvm.fabs.f64(double %a) - %cmp = fcmp une double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv + %call = call double @llvm.fabs.f64(double %a) + %cmp = fcmp oge double %call, 0.0 + ret i1 %cmp } -define i32 @test14(double %a) { -; CHECK-LABEL: @test14( -; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] +define i1 @fabs_une(half %a) { +; CHECK-LABEL: @fabs_une( +; CHECK-NEXT: [[CMP:%.*]] = fcmp une half [[A:%.*]], 0xH0000 +; CHECK-NEXT: ret i1 [[CMP]] ; - %call = tail call double @fabs(double %a) - %cmp = fcmp oeq double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv + %call = call half @llvm.fabs.f16(half %a) + %cmp = fcmp une half %call, 0.0 + ret i1 %cmp } -define i32 @test14_intrinsic(double %a) { -; CHECK-LABEL: @test14_intrinsic( +define i1 @fabs_oeq(double %a) { +; CHECK-LABEL: @fabs_oeq( ; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] -; - %call = tail call double @llvm.fabs.f64(double %a) - %cmp = fcmp oeq double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define i32 @test15(double %a) { -; CHECK-LABEL: @test15( -; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] +; CHECK-NEXT: ret i1 [[CMP]] ; - %call = tail call double @fabs(double %a) - %cmp = fcmp one double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv + %call = call double @llvm.fabs.f64(double %a) + %cmp = fcmp oeq double %call, 0.0 + ret i1 %cmp } -define i32 @test15_intrinsic(double %a) { -; CHECK-LABEL: @test15_intrinsic( +define i1 @fabs_one(double %a) { +; CHECK-LABEL: @fabs_one( ; CHECK-NEXT: [[CMP:%.*]] = fcmp one double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] -; - %call = tail call double @llvm.fabs.f64(double %a) - %cmp = fcmp one double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv -} - -define i32 @test16(double %a) { -; CHECK-LABEL: @test16( -; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] +; CHECK-NEXT: ret i1 [[CMP]] ; - %call = tail call double @fabs(double %a) - %cmp = fcmp ueq double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv + %call = call double @llvm.fabs.f64(double %a) + %cmp = fcmp one double %call, 0.0 + ret i1 %cmp } -define i32 @test16_intrinsic(double %a) { -; CHECK-LABEL: @test16_intrinsic( -; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq double [[A:%.*]], 0.000000e+00 -; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 -; CHECK-NEXT: ret i32 [[CONV]] +define <2 x i1> @fabs_ueq(<2 x float> %a) { +; CHECK-LABEL: @fabs_ueq( +; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq <2 x float> [[A:%.*]], zeroinitializer +; CHECK-NEXT: ret <2 x i1> [[CMP]] ; - %call = tail call double @llvm.fabs.f64(double %a) - %cmp = fcmp ueq double %call, 0.000000e+00 - %conv = zext i1 %cmp to i32 - ret i32 %conv + %call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a) + %cmp = fcmp ueq <2 x float> %call, zeroinitializer + ret <2 x i1> %cmp } ; Don't crash.