return 0;
}
+/// 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 convertion was successful, the simplified expression "X * 1/C" is
+/// returned; otherwise, NULL is returned.
+///
+static Instruction *CvtFDivConstToReciprocal(Value *Dividend,
+ ConstantFP *Divisor,
+ bool AllowReciprocal) {
+ const APFloat &FpVal = Divisor->getValueAPF();
+ APFloat Reciprocal(FpVal.getSemantics());
+ bool Cvt = FpVal.getExactInverse(&Reciprocal);
+
+ if (!Cvt && AllowReciprocal && FpVal.isNormal()) {
+ Reciprocal = APFloat(FpVal.getSemantics(), 1.0f);
+ (void)Reciprocal.divide(FpVal, APFloat::rmNearestTiesToEven);
+ Cvt = !Reciprocal.isDenormal();
+ }
+
+ if (!Cvt)
+ return 0;
+
+ ConstantFP *R;
+ R = ConstantFP::get(Dividend->getType()->getContext(), Reciprocal);
+ return BinaryOperator::CreateFMul(Dividend, R);
+}
+
Instruction *InstCombiner::visitFDiv(BinaryOperator &I) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (Value *V = SimplifyFDivInst(Op0, Op1, TD))
return ReplaceInstUsesWith(I, V);
+ bool AllowReassociate = I.hasUnsafeAlgebra();
+ bool AllowReciprocal = I.hasAllowReciprocal();
+
if (ConstantFP *Op1C = dyn_cast<ConstantFP>(Op1)) {
- const APFloat &Op1F = Op1C->getValueAPF();
-
- // If the divisor has an exact multiplicative inverse we can turn the fdiv
- // into a cheaper fmul.
- APFloat Reciprocal(Op1F.getSemantics());
- if (Op1F.getExactInverse(&Reciprocal)) {
- ConstantFP *RFP = ConstantFP::get(Builder->getContext(), Reciprocal);
- return BinaryOperator::CreateFMul(Op0, RFP);
+ if (AllowReassociate) {
+ ConstantFP *C1 = 0;
+ ConstantFP *C2 = Op1C;
+ Value *X;
+ Instruction *Res = 0;
+
+ if (match(Op0, m_FMul(m_Value(X), m_ConstantFP(C1)))) {
+ // (X*C1)/C2 => X * (C1/C2)
+ //
+ Constant *C = ConstantExpr::getFDiv(C1, C2);
+ const APFloat &F = cast<ConstantFP>(C)->getValueAPF();
+ if (F.isNormal() && !F.isDenormal())
+ Res = BinaryOperator::CreateFMul(X, C);
+ } else if (match(Op0, m_FDiv(m_Value(X), m_ConstantFP(C1)))) {
+ // (X/C1)/C2 => X /(C2*C1) [=> X * 1/(C2*C1) if reciprocal is allowed]
+ //
+ Constant *C = ConstantExpr::getFMul(C1, C2);
+ const APFloat &F = cast<ConstantFP>(C)->getValueAPF();
+ if (F.isNormal() && !F.isDenormal()) {
+ Res = CvtFDivConstToReciprocal(X, cast<ConstantFP>(C),
+ AllowReciprocal);
+ if (!Res)
+ Res = BinaryOperator::CreateFDiv(X, C);
+ }
+ }
+
+ if (Res) {
+ Res->setFastMathFlags(I.getFastMathFlags());
+ return Res;
+ }
+ }
+
+ // X / C => X * 1/C
+ if (Instruction *T = CvtFDivConstToReciprocal(Op0, Op1C, AllowReciprocal))
+ return T;
+
+ return 0;
+ }
+
+ if (AllowReassociate && isa<ConstantFP>(Op0)) {
+ ConstantFP *C1 = cast<ConstantFP>(Op0), *C2;
+ Constant *Fold = 0;
+ Value *X;
+ bool CreateDiv = true;
+
+ // C1 / (X*C2) => (C1/C2) / X
+ if (match(Op1, m_FMul(m_Value(X), m_ConstantFP(C2))))
+ Fold = ConstantExpr::getFDiv(C1, C2);
+ else if (match(Op1, m_FDiv(m_Value(X), m_ConstantFP(C2)))) {
+ // C1 / (X/C2) => (C1*C2) / X
+ Fold = ConstantExpr::getFMul(C1, C2);
+ } else if (match(Op1, m_FDiv(m_ConstantFP(C2), m_Value(X)))) {
+ // C1 / (C2/X) => (C1/C2) * X
+ Fold = ConstantExpr::getFDiv(C1, C2);
+ CreateDiv = false;
+ }
+
+ if (Fold) {
+ const APFloat &FoldC = cast<ConstantFP>(Fold)->getValueAPF();
+ if (FoldC.isNormal() && !FoldC.isDenormal()) {
+ Instruction *R = CreateDiv ?
+ BinaryOperator::CreateFDiv(Fold, X) :
+ BinaryOperator::CreateFMul(X, Fold);
+ R->setFastMathFlags(I.getFastMathFlags());
+ return R;
+ }
+ }
+ return 0;
+ }
+
+ if (AllowReassociate) {
+ Value *X, *Y;
+ Value *NewInst = 0;
+ Instruction *SimpR = 0;
+
+ if (Op0->hasOneUse() && match(Op0, m_FDiv(m_Value(X), m_Value(Y)))) {
+ // (X/Y) / Z => X / (Y*Z)
+ //
+ if (!isa<ConstantFP>(Y) || !isa<ConstantFP>(Op1)) {
+ NewInst = Builder->CreateFMul(Y, Op1);
+ SimpR = BinaryOperator::CreateFDiv(X, NewInst);
+ }
+ } else if (Op1->hasOneUse() && match(Op1, m_FDiv(m_Value(X), m_Value(Y)))) {
+ // Z / (X/Y) => Z*Y / X
+ //
+ if (!isa<ConstantFP>(Y) || !isa<ConstantFP>(Op0)) {
+ NewInst = Builder->CreateFMul(Op0, Y);
+ SimpR = BinaryOperator::CreateFDiv(NewInst, X);
+ }
+ }
+
+ if (NewInst) {
+ if (Instruction *T = dyn_cast<Instruction>(NewInst))
+ T->setDebugLoc(I.getDebugLoc());
+ SimpR->setFastMathFlags(I.getFastMathFlags());
+ return SimpR;
}
}
; CHECK: @fneg1
; CHECK: fmul float %f1, %f2
}
+
+; =========================================================================
+;
+; Testing-cases about div
+;
+; =========================================================================
+; X/C1 / C2 => X * (1/(C2*C1))
+
+define float @fdiv1(float %x) {
+ %div = fdiv float %x, 0x3FF3333340000000
+ %div1 = fdiv fast float %div, 0x4002666660000000
+ ret float %div1
+; 0x3FF3333340000000 = 1.2f
+; 0x4002666660000000 = 2.3f
+; 0x3FD7303B60000000 = 0.36231884057971014492
+; CHECK: @fdiv1
+; CHECK: fmul fast float %x, 0x3FD7303B60000000
+}
+
+; X*C1 / C2 => X * (C1/C2)
+define float @fdiv2(float %x) {
+ %mul = fmul float %x, 0x3FF3333340000000
+ %div1 = fdiv fast float %mul, 0x4002666660000000
+ ret float %div1
+
+; 0x3FF3333340000000 = 1.2f
+; 0x4002666660000000 = 2.3f
+; 0x3FE0B21660000000 = 0.52173918485641479492
+; CHECK: @fdiv2
+; CHECK: fmul fast float %x, 0x3FE0B21660000000
+}
+
+; "X/C1 / C2 => X * (1/(C2*C1))" is disabled (for now) is C2/C1 is a denormal
+;
+define float @fdiv3(float %x) {
+ %div = fdiv float %x, 0x47EFFFFFE0000000
+ %div1 = fdiv fast float %div, 0x4002666660000000
+ ret float %div1
+; CHECK: @fdiv3
+; CHECK: fdiv float %x, 0x47EFFFFFE0000000
+}
+
+; "X*C1 / C2 => X * (C1/C2)" is disabled if C1/C2 is a denormal
+define float @fdiv4(float %x) {
+ %mul = fmul float %x, 0x47EFFFFFE0000000
+ %div = fdiv float %mul, 0x3FC99999A0000000
+ ret float %div
+; CHECK: @fdiv4
+; CHECK: fmul float %x, 0x47EFFFFFE0000000
+}
+
+; (X/Y)/Z = > X/(Y*Z)
+define float @fdiv5(float %f1, float %f2, float %f3) {
+ %t1 = fdiv float %f1, %f2
+ %t2 = fdiv fast float %t1, %f3
+ ret float %t2
+; CHECK: @fdiv5
+; CHECK: fmul float %f2, %f3
+}
+
+; Z/(X/Y) = > (Z*Y)/X
+define float @fdiv6(float %f1, float %f2, float %f3) {
+ %t1 = fdiv float %f1, %f2
+ %t2 = fdiv fast float %f3, %t1
+ ret float %t2
+; CHECK: @fdiv6
+; CHECK: fmul float %f3, %f2
+}
+
+; C1/(X*C2) => (C1/C2) / X
+define float @fdiv7(float %x) {
+ %t1 = fmul float %x, 3.0e0
+ %t2 = fdiv fast float 15.0e0, %t1
+ ret float %t2
+; CHECK: @fdiv7
+; CHECK: fdiv fast float 5.000000e+00, %x
+}
+
+; C1/(X/C2) => (C1*C2) / X
+define float @fdiv8(float %x) {
+ %t1 = fdiv float %x, 3.0e0
+ %t2 = fdiv fast float 15.0e0, %t1
+ ret float %t2
+; CHECK: @fdiv8
+; CHECK: fdiv fast float 4.500000e+01, %x
+}
+
+; C1/(C2/X) => (C1/C2) * X
+define float @fdiv9(float %x) {
+ %t1 = fdiv float 3.0e0, %x
+ %t2 = fdiv fast float 15.0e0, %t1
+ ret float %t2
+; CHECK: @fdiv9
+; CHECK: fmul fast float %x, 5.000000e+00
+}
+