diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp index 698b715fd8b..48ce7cffb58 100644 --- a/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2762,6 +2762,40 @@ Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) { if (Constant *RHSC = dyn_cast(Op1)) { if (Instruction *LHSI = dyn_cast(Op0)) switch (LHSI->getOpcode()) { + case Instruction::FPExt: { + // fcmp (fpext x), C -> fcmp x, (fptrunc C) if fptrunc is lossless + FPExtInst *LHSExt = cast(LHSI); + ConstantFP *RHSF = dyn_cast(RHSC); + if (!RHSF) + break; + + const fltSemantics *Sem; + // FIXME: This shouldn't be here. + if (LHSExt->getSrcTy()->isFloatTy()) + Sem = &APFloat::IEEEsingle; + else if (LHSExt->getSrcTy()->isDoubleTy()) + Sem = &APFloat::IEEEdouble; + else if (LHSExt->getSrcTy()->isFP128Ty()) + Sem = &APFloat::IEEEquad; + else if (LHSExt->getSrcTy()->isX86_FP80Ty()) + Sem = &APFloat::x87DoubleExtended; + else if (LHSExt->getSrcTy()->isPPC_FP128Ty()) + Sem = &APFloat::PPCDoubleDouble; + else + break; + + bool Lossy; + APFloat F = RHSF->getValueAPF(); + F.convert(*Sem, APFloat::rmNearestTiesToEven, &Lossy); + + // Avoid lossy conversions and denormals. + if (!Lossy && + F.compare(APFloat::getSmallestNormalized(*Sem)) != + APFloat::cmpLessThan) + return new FCmpInst(I.getPredicate(), LHSExt->getOperand(0), + ConstantFP::get(RHSC->getContext(), F)); + break; + } case Instruction::PHI: // Only fold fcmp into the PHI if the phi and fcmp are in the same // block. If in the same block, we're encouraging jump threading. If diff --git a/test/Transforms/InstCombine/fcmp.ll b/test/Transforms/InstCombine/fcmp.ll index bef4855a0ed..49bd50717dc 100644 --- a/test/Transforms/InstCombine/fcmp.ll +++ b/test/Transforms/InstCombine/fcmp.ll @@ -9,3 +9,26 @@ define i1 @test1(float %x, float %y) nounwind { ; CHECK-NEXT: fcmp ogt float %x, %y } +define i1 @test2(float %a) nounwind { + %ext = fpext float %a to double + %cmp = fcmp ogt double %ext, 1.000000e+00 + ret i1 %cmp +; CHECK: @test2 +; CHECK-NEXT: fcmp ogt float %a, 1.0 +} + +define i1 @test3(float %a) nounwind { + %ext = fpext float %a to double + %cmp = fcmp ogt double %ext, 0x3FF0000000000001 ; more precision than float. + ret i1 %cmp +; CHECK: @test3 +; CHECK-NEXT: fpext float %a to double +} + +define i1 @test4(float %a) nounwind { + %ext = fpext float %a to double + %cmp = fcmp ogt double %ext, 0x36A0000000000000 ; denormal in float. + ret i1 %cmp +; CHECK: @test4 +; CHECK-NEXT: fpext float %a to double +}