From: Shuxin Yang Date: Mon, 14 Jan 2013 22:48:41 +0000 (+0000) Subject: This change is to implement following rules under the condition C_A and/or C_R X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=7d72cf892ec745d916af34cf9e68703010b4ded8;p=oota-llvm.git This change is to implement following rules under the condition C_A and/or C_R --------------------------------------------------------------------------- C_A: reassociation is allowed C_R: reciprocal of a constant C is appropriate, which means - 1/C is exact, or - reciprocal is allowed and 1/C is neither a special value nor a denormal. ----------------------------------------------------------------------------- rule1: (X/C1) / C2 => X / (C2*C1) (if C_A) => X * (1/(C2*C1)) (if C_A && C_R) rule 2: X*C1 / C2 => X * (C1/C2) if C_A rule 3: (X/Y)/Z = > X/(Y*Z) (if C_A && at least one of Y and Z is symbolic value) rule 4: Z/(X/Y) = > (Z*Y)/X (similar to rule3) rule 5: C1/(X*C2) => (C1/C2) / X (if C_A) rule 6: C1/(X/C2) => (C1*C2) / X (if C_A) rule 7: C1/(C2/X) => (C1/C2) * X (if C_A) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@172488 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index d0f43928c30..29846c156c4 100644 --- a/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -784,21 +784,140 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { 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(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(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(C)->getValueAPF(); + if (F.isNormal() && !F.isDenormal()) { + Res = CvtFDivConstToReciprocal(X, cast(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(Op0)) { + ConstantFP *C1 = cast(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(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(Y) || !isa(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(Y) || !isa(Op0)) { + NewInst = Builder->CreateFMul(Op0, Y); + SimpR = BinaryOperator::CreateFDiv(NewInst, X); + } + } + + if (NewInst) { + if (Instruction *T = dyn_cast(NewInst)) + T->setDebugLoc(I.getDebugLoc()); + SimpR->setFastMathFlags(I.getFastMathFlags()); + return SimpR; } } diff --git a/test/Transforms/InstCombine/fast-math.ll b/test/Transforms/InstCombine/fast-math.ll index df0455a2032..5a1ad5e6dbb 100644 --- a/test/Transforms/InstCombine/fast-math.ll +++ b/test/Transforms/InstCombine/fast-math.ll @@ -256,3 +256,99 @@ define float @fneg1(float %f1, float %f2) { ; 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 +} +