diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/README.txt | 38 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Scalar/Reassociate.cpp | 51 |
2 files changed, 49 insertions, 40 deletions
diff --git a/llvm/lib/Target/README.txt b/llvm/lib/Target/README.txt index f4338961718..bf8d465d0ae 100644 --- a/llvm/lib/Target/README.txt +++ b/llvm/lib/Target/README.txt @@ -95,44 +95,6 @@ something that reassoc doesn't think about yet. //===---------------------------------------------------------------------===// -This function: (derived from GCC PR19988) -double foo(double x, double y) { - return ((x + 0.1234 * y) * (x + -0.1234 * y)); -} - -compiles to: -_foo: - movapd %xmm1, %xmm2 - mulsd LCPI1_1(%rip), %xmm1 - mulsd LCPI1_0(%rip), %xmm2 - addsd %xmm0, %xmm1 - addsd %xmm0, %xmm2 - movapd %xmm1, %xmm0 - mulsd %xmm2, %xmm0 - ret - -Reassociate should be able to turn it into: - -double foo(double x, double y) { - return ((x + 0.1234 * y) * (x - 0.1234 * y)); -} - -Which allows the multiply by constant to be CSE'd, producing: - -_foo: - mulsd LCPI1_0(%rip), %xmm1 - movapd %xmm1, %xmm2 - addsd %xmm0, %xmm2 - subsd %xmm1, %xmm0 - mulsd %xmm2, %xmm0 - ret - -This doesn't need -ffast-math support at all. This is particularly bad because -the llvm-gcc frontend is canonicalizing the later into the former, but clang -doesn't have this problem. - -//===---------------------------------------------------------------------===// - These two functions should generate the same code on big-endian systems: int g(int *j,int *l) { return memcmp(j,l,4); } diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp index b11567cc9df..d0cd48a3a26 100644 --- a/llvm/lib/Transforms/Scalar/Reassociate.cpp +++ b/llvm/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. |

