summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp61
1 files changed, 27 insertions, 34 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 4cc2cbc493f..5457f19d7f4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/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<ConstantFP>(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<ConstantFP>(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<Constant>(Op0))
if (SelectInst *SI = dyn_cast<SelectInst>(Op1))
if (Instruction *R = FoldOpIntoSelect(I, SI))
return R;
bool AllowReassociate = I.isFast();
- bool AllowReciprocal = I.hasAllowReciprocal();
-
if (Constant *Op1C = dyn_cast<Constant>(Op1)) {
if (SelectInst *SI = dyn_cast<SelectInst>(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;
}
OpenPOWER on IntegriCloud