mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-04 21:30:49 +00:00
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
This commit is contained in:
parent
dd2e895022
commit
7d72cf892e
@ -784,21 +784,140 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) {
|
|||||||
return 0;
|
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) {
|
Instruction *InstCombiner::visitFDiv(BinaryOperator &I) {
|
||||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||||
|
|
||||||
if (Value *V = SimplifyFDivInst(Op0, Op1, TD))
|
if (Value *V = SimplifyFDivInst(Op0, Op1, TD))
|
||||||
return ReplaceInstUsesWith(I, V);
|
return ReplaceInstUsesWith(I, V);
|
||||||
|
|
||||||
if (ConstantFP *Op1C = dyn_cast<ConstantFP>(Op1)) {
|
bool AllowReassociate = I.hasUnsafeAlgebra();
|
||||||
const APFloat &Op1F = Op1C->getValueAPF();
|
bool AllowReciprocal = I.hasAllowReciprocal();
|
||||||
|
|
||||||
// If the divisor has an exact multiplicative inverse we can turn the fdiv
|
if (ConstantFP *Op1C = dyn_cast<ConstantFP>(Op1)) {
|
||||||
// into a cheaper fmul.
|
if (AllowReassociate) {
|
||||||
APFloat Reciprocal(Op1F.getSemantics());
|
ConstantFP *C1 = 0;
|
||||||
if (Op1F.getExactInverse(&Reciprocal)) {
|
ConstantFP *C2 = Op1C;
|
||||||
ConstantFP *RFP = ConstantFP::get(Builder->getContext(), Reciprocal);
|
Value *X;
|
||||||
return BinaryOperator::CreateFMul(Op0, RFP);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,3 +256,99 @@ define float @fneg1(float %f1, float %f2) {
|
|||||||
; CHECK: @fneg1
|
; CHECK: @fneg1
|
||||||
; CHECK: fmul float %f1, %f2
|
; 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
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user