summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorErik Verbruggen <erikjv@me.com>2014-08-21 10:45:30 +0000
committerErik Verbruggen <erikjv@me.com>2014-08-21 10:45:30 +0000
commit2b98bd2a80aea506506c6479e87283330edef86c (patch)
tree53e12be0117a60b8b41c6755189d68294d4beed2 /llvm/lib
parentb791ef21d2a11b9117abac5cc40ccae73a22c2a8 (diff)
downloadbcm5719-llvm-2b98bd2a80aea506506c6479e87283330edef86c.tar.gz
bcm5719-llvm-2b98bd2a80aea506506c6479e87283330edef86c.zip
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 llvm-svn: 216169
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Target/README.txt38
-rw-r--r--llvm/lib/Transforms/Scalar/Reassociate.cpp51
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.
OpenPOWER on IntegriCloud