From 019b67ac3db03ab66df85628efb7452f25465d5a Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Wed, 14 Feb 2018 23:04:17 +0000 Subject: [PATCH] [InstCombine] clean up fold for X / C -> X * (1.0/C); NFCI This should work with vector constants too, but it's currently limited to scalar. llvm-svn: 325187 --- .../InstCombine/InstCombineMulDivRem.cpp | 61 ++++++++----------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 4cc2cbc493f..5457f19d7f4 100644 --- a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1317,33 +1317,34 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { return nullptr; } -/// CvtFDivConstToReciprocal tries to convert X/C into X*1/C if C not a special -/// FP value and: -/// 1) 1/C is exact, or -/// 2) reciprocal is allowed. -/// If the conversion was successful, the simplified expression "X * 1/C" is -/// returned; otherwise, nullptr is returned. -static Instruction *CvtFDivConstToReciprocal(Value *Dividend, Constant *Divisor, - bool AllowReciprocal) { - if (!isa(Divisor)) // TODO: handle vectors. +/// Try to convert X/C into X * (1/C). +static Instruction *foldFDivConstantDivisor(BinaryOperator &FDiv) { + // TODO: Handle vector constants. + ConstantFP *CFP; + if (!match(FDiv.getOperand(1), m_ConstantFP(CFP))) return nullptr; - const APFloat &FpVal = cast(Divisor)->getValueAPF(); + const APFloat &FpVal = CFP->getValueAPF(); APFloat Reciprocal(FpVal.getSemantics()); - bool Cvt = FpVal.getExactInverse(&Reciprocal); - if (!Cvt && AllowReciprocal && FpVal.isFiniteNonZero()) { + // This returns false if the inverse would be a denormal. + bool HasRecip = FpVal.getExactInverse(&Reciprocal); + // If the inverse is not exact, we may still be able to convert if we are + // not operating with strict math. + if (!HasRecip && FDiv.hasAllowReciprocal() && FpVal.isFiniteNonZero()) { Reciprocal = APFloat(FpVal.getSemantics(), 1.0f); - (void)Reciprocal.divide(FpVal, APFloat::rmNearestTiesToEven); - Cvt = !Reciprocal.isDenormal(); + Reciprocal.divide(FpVal, APFloat::rmNearestTiesToEven); + // Disallow denormal constants because we don't know what would happen + // on all targets. + // TODO: Function attributes can tell us that denorms are flushed? + HasRecip = !Reciprocal.isDenormal(); } - if (!Cvt) + if (!HasRecip) return nullptr; - ConstantFP *R; - R = ConstantFP::get(Dividend->getType()->getContext(), Reciprocal); - return BinaryOperator::CreateFMul(Dividend, R); + auto *RecipCFP = ConstantFP::get(FDiv.getContext(), Reciprocal); + return BinaryOperator::CreateFMul(FDiv.getOperand(0), RecipCFP); } Instruction *InstCombiner::visitFDiv(BinaryOperator &I) { @@ -1356,14 +1357,17 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) { SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); + if (Instruction *FMul = foldFDivConstantDivisor(I)) { + FMul->copyFastMathFlags(&I); + return FMul; + } + if (isa(Op0)) if (SelectInst *SI = dyn_cast(Op1)) if (Instruction *R = FoldOpIntoSelect(I, SI)) return R; bool AllowReassociate = I.isFast(); - bool AllowReciprocal = I.hasAllowReciprocal(); - if (Constant *Op1C = dyn_cast(Op1)) { if (SelectInst *SI = dyn_cast(Op0)) if (Instruction *R = FoldOpIntoSelect(I, SI)) @@ -1377,18 +1381,14 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) { if (match(Op0, m_FMul(m_Value(X), m_Constant(C1)))) { // (X*C1)/C2 => X * (C1/C2) - // Constant *C = ConstantExpr::getFDiv(C1, C2); if (isNormalFp(C)) Res = BinaryOperator::CreateFMul(X, C); } else if (match(Op0, m_FDiv(m_Value(X), m_Constant(C1)))) { - // (X/C1)/C2 => X /(C2*C1) [=> X * 1/(C2*C1) if reciprocal is allowed] + // (X/C1)/C2 => X /(C2*C1) Constant *C = ConstantExpr::getFMul(C1, C2); - if (isNormalFp(C)) { - Res = CvtFDivConstToReciprocal(X, C, AllowReciprocal); - if (!Res) - Res = BinaryOperator::CreateFDiv(X, C); - } + if (isNormalFp(C)) + Res = BinaryOperator::CreateFDiv(X, C); } if (Res) { @@ -1396,13 +1396,6 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) { return Res; } } - - // X / C => X * 1/C - if (Instruction *T = CvtFDivConstToReciprocal(Op0, Op1C, AllowReciprocal)) { - T->copyFastMathFlags(&I); - return T; - } - return nullptr; }