mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-02 07:32:52 +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;
|
||||
}
|
||||
|
||||
/// 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);
|
||||
|
||||
if (ConstantFP *Op1C = dyn_cast<ConstantFP>(Op1)) {
|
||||
const APFloat &Op1F = Op1C->getValueAPF();
|
||||
bool AllowReassociate = I.hasUnsafeAlgebra();
|
||||
bool AllowReciprocal = I.hasAllowReciprocal();
|
||||
|
||||
// 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 (ConstantFP *Op1C = dyn_cast<ConstantFP>(Op1)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user