Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -5229,6 +5229,57 @@ return new ICmpInst(Pred, LHSI->getOperand(0), RHSInt); } +/// Fold (C / X) < 0.0 --> X < 0.0 if possible. Swap predicate if necessary. +static Instruction *foldFCmpReciprocalAndZero(FCmpInst &I, Instruction *LHSI, + Constant *RHSC) { + // When C is not 0.0 and infinities are not allowed: + // (C / X) < 0.0 is a sign-bit test of X + // (C / X) < 0.0 --> X < 0.0 (if C is positive) + // (C / X) < 0.0 --> X > 0.0 (if C is negative, swap the predicate) + // + // Proof: + // Multiply (C / X) < 0.0 by X * X / C. + // - X is non zero, if it is the flag 'ninf' is violated. + // - C defines the sign of X * X * C. Thus it also defines whether to swap + // the predicate. C is also non zero by definition. + // + // Thus X * X / C is non zero and the transformation is valid. [qed] + + FCmpInst::Predicate Pred = I.getPredicate(); + + // Check that predicates are valid. + if ((Pred != FCmpInst::FCMP_OGT) && (Pred != FCmpInst::FCMP_OLT) && + (Pred != FCmpInst::FCMP_OGE) && (Pred != FCmpInst::FCMP_OLE)) + return nullptr; + + // Check that RHS operand is zero. + if (!match(RHSC, m_AnyZeroFP())) + return nullptr; + + // Check fastmath flags ('ninf'). + if (!LHSI->hasNoInfs() || !I.hasNoInfs()) + return nullptr; + + // Check the properties of the dividend. It must not be zero to avoid a + // division by zero (see Proof). + const APFloat *C; + if (!match(LHSI->getOperand(0), m_APFloat(C))) + return nullptr; + + if (C->isZero()) + return nullptr; + + // Get swapped predicate if necessary. + if (C->isNegative()) + Pred = I.getSwappedPredicate(); + + // Finally emit the new fcmp. + Value *X = LHSI->getOperand(1); + FCmpInst *NewFCI = new FCmpInst(Pred, X, RHSC); + NewFCI->setFastMathFlags(I.getFastMathFlags()); + return NewFCI; +} + Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) { bool Changed = false; @@ -5363,6 +5414,10 @@ ConstantExpr::getFNeg(RHSC)); break; } + case Instruction::FDiv: + if (Instruction *NV = foldFCmpReciprocalAndZero(I, LHSI, RHSC)) + return NV; + break; case Instruction::Load: if (GetElementPtrInst *GEP = dyn_cast(LHSI->getOperand(0))) { Index: llvm/trunk/test/Transforms/InstCombine/fcmp.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/fcmp.ll +++ llvm/trunk/test/Transforms/InstCombine/fcmp.ll @@ -380,8 +380,7 @@ ; Can fold 1.0 / X < 0.0 --> X < 0 with ninf define i1 @test20_recipX_olt_0(float %X) { ; CHECK-LABEL: @test20_recipX_olt_0( -; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf float 1.000000e+00, [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf olt float [[DIV]], 0.000000e+00 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf olt float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[CMP]] ; %div = fdiv ninf float 1.0, %X @@ -392,8 +391,7 @@ ; Can fold -2.0 / X <= 0.0 --> X >= 0 with ninf define i1 @test21_recipX_ole_0(float %X) { ; CHECK-LABEL: @test21_recipX_ole_0( -; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf float -2.000000e+00, [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ole float [[DIV]], 0.000000e+00 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf oge float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[CMP]] ; %div = fdiv ninf float -2.0, %X @@ -404,8 +402,7 @@ ; Can fold 2.0 / X > 0.0 --> X > 0 with ninf define i1 @test22_recipX_ogt_0(float %X) { ; CHECK-LABEL: @test22_recipX_ogt_0( -; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf float 2.000000e+00, [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ogt float [[DIV]], 0.000000e+00 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ogt float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[CMP]] ; %div = fdiv ninf float 2.0, %X @@ -416,8 +413,7 @@ ; Can fold -1.0 / X >= 0.0 --> X <= 0 with ninf define i1 @test23_recipX_oge_0(float %X) { ; CHECK-LABEL: @test23_recipX_oge_0( -; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf float -1.000000e+00, [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf oge float [[DIV]], 0.000000e+00 +; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ole float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[CMP]] ; %div = fdiv ninf float -1.0, %X @@ -464,8 +460,7 @@ ; Fold <-1.0, -1.0> / X > <-0.0, -0.0> define <2 x i1> @test27_recipX_gt_vecsplat(<2 x float> %X) { ; CHECK-LABEL: @test27_recipX_gt_vecsplat( -; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf <2 x float> , [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf ogt <2 x float> [[DIV]], +; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf olt <2 x float> [[X:%.*]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %div = fdiv ninf <2 x float> , %X