mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-15 07:34:33 +00:00
This change is to implement following rules:
o. X/C1 * C2 => X * (C2/C1) (if C2/C1 is neither special FP nor denormal) o. X/C1 * C2 -> X/(C1/C2) (if C2/C1 is either specical FP or denormal, but C1/C2 is a normal Fp) Let MDC denote multiplication or dividion with one & only one operand being a constant o. (MDC ± C1) * C2 => (MDC * C2) ± (C1 * C2) (so long as the constant-folding doesn't yield any denormal or special value) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171793 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2f1bfc4c79
commit
d3ae2866d1
@ -116,6 +116,8 @@ public:
|
||||
Instruction *visitSub(BinaryOperator &I);
|
||||
Instruction *visitFSub(BinaryOperator &I);
|
||||
Instruction *visitMul(BinaryOperator &I);
|
||||
Value *foldFMulConst(Instruction *FMulOrDiv, ConstantFP *C,
|
||||
Instruction *InsertBefore);
|
||||
Instruction *visitFMul(BinaryOperator &I);
|
||||
Instruction *visitURem(BinaryOperator &I);
|
||||
Instruction *visitSRem(BinaryOperator &I);
|
||||
|
@ -291,10 +291,90 @@ static void detectLog2OfHalf(Value *&Op, Value *&Y, IntrinsicInst *&Log2) {
|
||||
Y = I->getOperand(0);
|
||||
}
|
||||
|
||||
/// Helper function of InstCombiner::visitFMul(BinaryOperator(). It returns
|
||||
/// true iff the given value is FMul or FDiv with one and only one operand
|
||||
/// being a normal constant (i.e. not Zero/NaN/Infinity).
|
||||
static bool isFMulOrFDivWithConstant(Value *V) {
|
||||
Instruction *I = dyn_cast<Instruction>(V);
|
||||
if (!I || (I->getOpcode() != Instruction::FMul &&
|
||||
I->getOpcode() != Instruction::FDiv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstantFP *C0 = dyn_cast<ConstantFP>(I->getOperand(0));
|
||||
ConstantFP *C1 = dyn_cast<ConstantFP>(I->getOperand(1));
|
||||
|
||||
if (C0 && C1)
|
||||
return false;
|
||||
|
||||
return (C0 && C0->getValueAPF().isNormal()) ||
|
||||
(C1 && C1->getValueAPF().isNormal());
|
||||
}
|
||||
|
||||
static bool isNormalFp(const ConstantFP *C) {
|
||||
const APFloat &Flt = C->getValueAPF();
|
||||
return Flt.isNormal() && !Flt.isDenormal();
|
||||
}
|
||||
|
||||
/// foldFMulConst() is a helper routine of InstCombiner::visitFMul().
|
||||
/// The input \p FMulOrDiv is a FMul/FDiv with one and only one operand
|
||||
/// being a constant (i.e. isFMulOrFDivWithConstant(FMulOrDiv) == true).
|
||||
/// This function is to simplify "FMulOrDiv * C" and returns the
|
||||
/// resulting expression. Note that this function could return NULL in
|
||||
/// case the constants cannot be folded into a normal floating-point.
|
||||
///
|
||||
Value *InstCombiner::foldFMulConst
|
||||
(Instruction *FMulOrDiv, ConstantFP *C, Instruction *InsertBefore) {
|
||||
assert(isFMulOrFDivWithConstant(FMulOrDiv) && "V is invalid");
|
||||
|
||||
Value *Opnd0 = FMulOrDiv->getOperand(0);
|
||||
Value *Opnd1 = FMulOrDiv->getOperand(1);
|
||||
|
||||
ConstantFP *C0 = dyn_cast<ConstantFP>(Opnd0);
|
||||
ConstantFP *C1 = dyn_cast<ConstantFP>(Opnd1);
|
||||
|
||||
BinaryOperator *R = 0;
|
||||
|
||||
// (X * C0) * C => X * (C0*C)
|
||||
if (FMulOrDiv->getOpcode() == Instruction::FMul) {
|
||||
Constant *F = ConstantExpr::getFMul(C1 ? C1 : C0, C);
|
||||
if (isNormalFp(cast<ConstantFP>(F)))
|
||||
R = BinaryOperator::CreateFMul(C1 ? Opnd0 : Opnd1, F);
|
||||
} else {
|
||||
if (C0) {
|
||||
// (C0 / X) * C => (C0 * C) / X
|
||||
ConstantFP *F = cast<ConstantFP>(ConstantExpr::getFMul(C0, C));
|
||||
if (isNormalFp(F))
|
||||
R = BinaryOperator::CreateFDiv(F, Opnd1);
|
||||
} else {
|
||||
// (X / C1) * C => X * (C/C1) if C/C1 is not a denormal
|
||||
ConstantFP *F = cast<ConstantFP>(ConstantExpr::getFDiv(C, C1));
|
||||
if (isNormalFp(F)) {
|
||||
R = BinaryOperator::CreateFMul(Opnd0, F);
|
||||
} else {
|
||||
// (X / C1) * C => X / (C1/C)
|
||||
Constant *F = ConstantExpr::getFDiv(C1, C);
|
||||
if (isNormalFp(cast<ConstantFP>(F)))
|
||||
R = BinaryOperator::CreateFDiv(Opnd0, F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (R) {
|
||||
R->setHasUnsafeAlgebra(true);
|
||||
InsertNewInstWith(R, *InsertBefore);
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
Instruction *InstCombiner::visitFMul(BinaryOperator &I) {
|
||||
bool Changed = SimplifyAssociativeOrCommutative(I);
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
|
||||
if (isa<Constant>(Op0))
|
||||
std::swap(Op0, Op1);
|
||||
|
||||
if (Value *V = SimplifyFMulInst(Op0, Op1, I.getFastMathFlags(), TD))
|
||||
return ReplaceInstUsesWith(I, V);
|
||||
|
||||
@ -308,6 +388,53 @@ Instruction *InstCombiner::visitFMul(BinaryOperator &I) {
|
||||
if (isa<PHINode>(Op0))
|
||||
if (Instruction *NV = FoldOpIntoPhi(I))
|
||||
return NV;
|
||||
|
||||
ConstantFP *C = dyn_cast<ConstantFP>(Op1);
|
||||
if (C && I.hasUnsafeAlgebra() && C->getValueAPF().isNormal()) {
|
||||
// Let MDC denote an expression in one of these forms:
|
||||
// X * C, C/X, X/C, where C is a constant.
|
||||
//
|
||||
// Try to simplify "MDC * Constant"
|
||||
if (isFMulOrFDivWithConstant(Op0)) {
|
||||
Value *V = foldFMulConst(cast<Instruction>(Op0), C, &I);
|
||||
if (V)
|
||||
return ReplaceInstUsesWith(I, V);
|
||||
}
|
||||
|
||||
// (MDC +/- C1) * C2 => (MDC * C2) +/- (C1 * C2)
|
||||
Instruction *FAddSub = dyn_cast<Instruction>(Op0);
|
||||
if (FAddSub &&
|
||||
(FAddSub->getOpcode() == Instruction::FAdd ||
|
||||
FAddSub->getOpcode() == Instruction::FSub)) {
|
||||
Value *Opnd0 = FAddSub->getOperand(0);
|
||||
Value *Opnd1 = FAddSub->getOperand(1);
|
||||
ConstantFP *C0 = dyn_cast<ConstantFP>(Opnd0);
|
||||
ConstantFP *C1 = dyn_cast<ConstantFP>(Opnd1);
|
||||
bool Swap = false;
|
||||
if (C0) {
|
||||
std::swap(C0, C1); std::swap(Opnd0, Opnd1); Swap = true;
|
||||
}
|
||||
|
||||
if (C1 && C1->getValueAPF().isNormal() &&
|
||||
isFMulOrFDivWithConstant(Opnd0)) {
|
||||
Value *M0 = ConstantExpr::getFMul(C1, C);
|
||||
Value *M1 = isNormalFp(cast<ConstantFP>(M0)) ?
|
||||
foldFMulConst(cast<Instruction>(Opnd0), C, &I) :
|
||||
0;
|
||||
if (M0 && M1) {
|
||||
if (Swap && FAddSub->getOpcode() == Instruction::FSub)
|
||||
std::swap(M0, M1);
|
||||
|
||||
Value *R = (FAddSub->getOpcode() == Instruction::FAdd) ?
|
||||
BinaryOperator::CreateFAdd(M0, M1) :
|
||||
BinaryOperator::CreateFSub(M0, M1);
|
||||
Instruction *RI = cast<Instruction>(R);
|
||||
RI->setHasUnsafeAlgebra(true);
|
||||
return RI;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Value *Op0v = dyn_castFNegVal(Op0)) // -X * -Y = X*Y
|
||||
|
@ -160,3 +160,88 @@ define double @select3(i32 %cond, double %x, double %y) {
|
||||
; CHECK: @select3
|
||||
; CHECK: fmul nnan nsz double %cond1, %x
|
||||
}
|
||||
|
||||
; =========================================================================
|
||||
;
|
||||
; Testing-cases about fmul begin
|
||||
;
|
||||
; =========================================================================
|
||||
|
||||
; ((X*C1) + C2) * C3 => (X * (C1*C3)) + (C2*C3) (i.e. distribution)
|
||||
define float @fmul_distribute1(float %f1) {
|
||||
%t1 = fmul float %f1, 6.0e+3
|
||||
%t2 = fadd float %t1, 2.0e+3
|
||||
%t3 = fmul fast float %t2, 5.0e+3
|
||||
ret float %t3
|
||||
; CHECK: @fmul_distribute1
|
||||
; CHECK: %1 = fmul fast float %f1, 3.000000e+07
|
||||
; CHECK: %t3 = fadd fast float %1, 1.000000e+07
|
||||
}
|
||||
|
||||
; (X/C1 + C2) * C3 => X/(C1/C3) + C2*C3
|
||||
define double @fmul_distribute2(double %f1, double %f2) {
|
||||
%t1 = fdiv double %f1, 3.0e+0
|
||||
%t2 = fadd double %t1, 5.0e+1
|
||||
; 0x10000000000000 = DBL_MIN
|
||||
%t3 = fmul fast double %t2, 0x10000000000000
|
||||
ret double %t3
|
||||
|
||||
; CHECK: @fmul_distribute2
|
||||
; CHECK: %1 = fdiv fast double %f1, 0x7FE8000000000000
|
||||
; CHECK: fadd fast double %1, 0x69000000000000
|
||||
}
|
||||
|
||||
; 5.0e-1 * DBL_MIN yields denormal, so "(f1*3.0 + 5.0e-1) * DBL_MIN" cannot
|
||||
; be simplified into f1 * (3.0*DBL_MIN) + (5.0e-1*DBL_MIN)
|
||||
define double @fmul_distribute3(double %f1) {
|
||||
%t1 = fdiv double %f1, 3.0e+0
|
||||
%t2 = fadd double %t1, 5.0e-1
|
||||
%t3 = fmul fast double %t2, 0x10000000000000
|
||||
ret double %t3
|
||||
|
||||
; CHECK: @fmul_distribute3
|
||||
; CHECK: fmul fast double %t2, 0x10000000000000
|
||||
}
|
||||
|
||||
; C1/X * C2 => (C1*C2) / X
|
||||
define float @fmul2(float %f1) {
|
||||
%t1 = fdiv float 2.0e+3, %f1
|
||||
%t3 = fmul fast float %t1, 6.0e+3
|
||||
ret float %t3
|
||||
; CHECK: @fmul2
|
||||
; CHECK: fdiv fast float 1.200000e+07, %f1
|
||||
}
|
||||
|
||||
; X/C1 * C2 => X * (C2/C1) (if C2/C1 is normal Fp)
|
||||
define float @fmul3(float %f1, float %f2) {
|
||||
%t1 = fdiv float %f1, 2.0e+3
|
||||
%t3 = fmul fast float %t1, 6.0e+3
|
||||
ret float %t3
|
||||
; CHECK: @fmul3
|
||||
; CHECK: fmul fast float %f1, 3.000000e+00
|
||||
}
|
||||
|
||||
; Rule "X/C1 * C2 => X * (C2/C1) is not applicable if C2/C1 is either a special
|
||||
; value of a denormal. The 0x3810000000000000 here take value FLT_MIN
|
||||
;
|
||||
define float @fmul4(float %f1, float %f2) {
|
||||
%t1 = fdiv float %f1, 2.0e+3
|
||||
%t3 = fmul fast float %t1, 0x3810000000000000
|
||||
ret float %t3
|
||||
; CHECK: @fmul4
|
||||
; CHECK: fmul fast float %t1, 0x3810000000000000
|
||||
}
|
||||
|
||||
; X / C1 * C2 => X / (C2/C1) if C1/C2 is either a special value of a denormal,
|
||||
; and C2/C1 is a normal value.
|
||||
;
|
||||
define float @fmul5(float %f1, float %f2) {
|
||||
%t1 = fdiv float %f1, 3.0e+0
|
||||
%t3 = fmul fast float %t1, 0x3810000000000000
|
||||
ret float %t3
|
||||
; CHECK: @fmul5
|
||||
; CHECK: fdiv fast float %f1, 0x47E8000000000000
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user