diff options
author | Erik Verbruggen <erikjv@me.com> | 2014-08-21 10:45:30 +0000 |
---|---|---|
committer | Erik Verbruggen <erikjv@me.com> | 2014-08-21 10:45:30 +0000 |
commit | 0edc5e839156ce1b8af863a01398c190634e99f0 (patch) | |
tree | b3d9feea26edce176cf3ae8cf63d91abeba7936d /lib/Transforms/Scalar/Reassociate.cpp | |
parent | f11ac42d01b99970f5335a78dd4277184c3a3c1f (diff) |
Reassociate x + -0.1234 * y into x - 0.1234 * y
This does not require -ffast-math, and it gives CSE/GVN more options to
eliminate duplicate expressions in, e.g.:
return ((x + 0.1234 * y) * (x - 0.1234 * y));
Differential Revision: http://reviews.llvm.org/D4904
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216169 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/Scalar/Reassociate.cpp')
-rw-r--r-- | lib/Transforms/Scalar/Reassociate.cpp | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/lib/Transforms/Scalar/Reassociate.cpp b/lib/Transforms/Scalar/Reassociate.cpp index b11567cc9df..d0cd48a3a26 100644 --- a/lib/Transforms/Scalar/Reassociate.cpp +++ b/lib/Transforms/Scalar/Reassociate.cpp @@ -193,6 +193,8 @@ namespace { Value *OptimizeMul(BinaryOperator *I, SmallVectorImpl<ValueEntry> &Ops); Value *RemoveFactorFromExpression(Value *V, Value *Factor); void EraseInst(Instruction *I); + void optimizeFAddNegExpr(ConstantFP *ConstOperand, Instruction *I, + int OperandNr); void OptimizeInst(Instruction *I); }; } @@ -1914,6 +1916,33 @@ void Reassociate::EraseInst(Instruction *I) { } } +void Reassociate::optimizeFAddNegExpr(ConstantFP *ConstOperand, Instruction *I, + int OperandNr) { + // Change the sign of the constant. + APFloat Val = ConstOperand->getValueAPF(); + Val.changeSign(); + I->setOperand(0, ConstantFP::get(ConstOperand->getContext(), Val)); + + assert(I->hasOneUse() && "Only a single use can be replaced."); + Instruction *Parent = I->user_back(); + + Value *OtherOperand = Parent->getOperand(1 - OperandNr); + + unsigned Opcode = Parent->getOpcode(); + assert(Opcode == Instruction::FAdd || + (Opcode == Instruction::FSub && Parent->getOperand(1) == I)); + + BinaryOperator *NI = Opcode == Instruction::FAdd + ? BinaryOperator::CreateFSub(OtherOperand, I) + : BinaryOperator::CreateFAdd(OtherOperand, I); + NI->setFastMathFlags(cast<FPMathOperator>(Parent)->getFastMathFlags()); + NI->insertBefore(Parent); + NI->setName(Parent->getName() + ".repl"); + Parent->replaceAllUsesWith(NI); + NI->setDebugLoc(I->getDebugLoc()); + MadeChange = true; +} + /// OptimizeInst - Inspect and optimize the given instruction. Note that erasing /// instructions is not allowed. void Reassociate::OptimizeInst(Instruction *I) { @@ -1940,8 +1969,8 @@ void Reassociate::OptimizeInst(Instruction *I) { if (I->getType()->isFloatingPointTy() || I->getType()->isVectorTy()) { // FAdd and FMul can be commuted. - if (I->getOpcode() == Instruction::FMul || - I->getOpcode() == Instruction::FAdd) { + unsigned Opcode = I->getOpcode(); + if (Opcode == Instruction::FMul || Opcode == Instruction::FAdd) { Value *LHS = I->getOperand(0); Value *RHS = I->getOperand(1); unsigned LHSRank = getRank(LHS); @@ -1954,6 +1983,24 @@ void Reassociate::OptimizeInst(Instruction *I) { } } + // Reassociate: x + -ConstantFP * y -> x - ConstantFP * y + // The FMul can also be an FDiv, and FAdd can be a FSub. + if (Opcode == Instruction::FMul || Opcode == Instruction::FDiv) { + if (ConstantFP *LHSConst = dyn_cast<ConstantFP>(I->getOperand(0))) { + if (LHSConst->isNegative() && I->hasOneUse()) { + Instruction *Parent = I->user_back(); + if (Parent->getOpcode() == Instruction::FAdd) { + if (Parent->getOperand(0) == I) + optimizeFAddNegExpr(LHSConst, I, 0); + else if (Parent->getOperand(1) == I) + optimizeFAddNegExpr(LHSConst, I, 1); + } else if (Parent->getOpcode() == Instruction::FSub) + if (Parent->getOperand(1) == I) + optimizeFAddNegExpr(LHSConst, I, 1); + } + } + } + // FIXME: We should commute vector instructions as well. However, this // requires further analysis to determine the effect on later passes. |