summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms
diff options
context:
space:
mode:
authorSanjay Patel <spatel@rotateright.com>2018-09-02 14:22:54 +0000
committerSanjay Patel <spatel@rotateright.com>2018-09-02 14:22:54 +0000
commitca36eb4e33e487d8ae0e77fd38218a73c8656433 (patch)
tree78e3e00ce7a52cf3d3ef67a5a1a76728de37c15b /llvm/lib/Transforms
parentd7a62444754e095377f84731658b9d8a5ecae471 (diff)
downloadbcm5719-llvm-ca36eb4e33e487d8ae0e77fd38218a73c8656433.tar.gz
bcm5719-llvm-ca36eb4e33e487d8ae0e77fd38218a73c8656433.zip
[Reassociate] swap binop operands to increase factoring potential
If we have a pair of binops feeding another pair of binops, rearrange the operands so the matching pair are together because that allows easy factorization folds to happen in instcombine: ((X << S) & Y) & (Z << S) --> ((X << S) & (Z << S)) & Y (reassociation) --> ((X & Z) << S) & Y (factorize shift from 'and' ops optimization) This is part of solving PR37098: https://bugs.llvm.org/show_bug.cgi?id=37098 Note that there's an instcombine version of this patch attached there, but we're trying to make instcombine have less responsibility to improve compile-time efficiency. For reasons I still don't completely understand, reassociate does this kind of transform sometimes, but misses everything in my motivating cases. This patch on its own is gluing an independent cleanup chunk to the end of the existing RewriteExprTree() loop. We can build on it and do something stronger to better order the full expression tree like D40049. That might be an alternative to the proposal to add a separate reassociation pass like D41574. Differential Revision: https://reviews.llvm.org/D45842 llvm-svn: 341288
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r--llvm/lib/Transforms/Scalar/Reassociate.cpp64
1 files changed, 64 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp
index 03cd7c10150..79ab44ff167 100644
--- a/llvm/lib/Transforms/Scalar/Reassociate.cpp
+++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp
@@ -63,6 +63,7 @@
using namespace llvm;
using namespace reassociate;
+using namespace PatternMatch;
#define DEBUG_TYPE "reassociate"
@@ -2131,6 +2132,66 @@ void ReassociatePass::OptimizeInst(Instruction *I) {
ReassociateExpression(BO);
}
+/// If we have an associative pair of binops with the same opcode and 2 of the 3
+/// operands to that pair of binops are some other matching binop, rearrange the
+/// operands of the associative binops so the matching ops are paired together.
+/// This transform creates factoring opportunities by pairing opcodes.
+/// TODO: Should those factoring optimizations be handled here or InstCombine?
+/// Example:
+/// ((X << S) & Y) & (Z << S) --> ((X << S) & (Z << S)) & Y (reassociation)
+/// --> ((X & Z) << S) & Y (factorize shift from 'and' ops optimization)
+void ReassociatePass::swapOperandsToMatchBinops(BinaryOperator &B) {
+ BinaryOperator *B0, *B1;
+ if (!B.isAssociative() || !B.isCommutative() ||
+ !match(&B, m_BinOp(m_BinOp(B0), m_BinOp(B1))))
+ return;
+
+ // We have (B0 op B1) where both operands are also binops.
+ // Canonicalize a binop with the same opcode as the parent binop (B) to B0 and
+ // a binop with a different opcode to B1.
+ Instruction::BinaryOps TopOpc = B.getOpcode();
+ if (B0->getOpcode() != TopOpc)
+ std::swap(B0, B1);
+
+ // If (1) we don't have a pair of binops with the same opcode or (2) B0 and B1
+ // already have the same opcode, there is nothing to do. If the binop with the
+ // same opcode (B0) has more than one use, reassociation would result in more
+ // instructions, so bail out.
+ Instruction::BinaryOps OtherOpc = B1->getOpcode();
+ if (B0->getOpcode() != TopOpc || !B0->hasOneUse() || OtherOpc == TopOpc)
+ return;
+
+ // Canonicalize a binop that matches B1 to V00 (operand 0 of B0) and a value
+ // that does not match B1 to V01.
+ Value *V00 = B0->getOperand(0), *V01 = B0->getOperand(1);
+ if (!match(V00, m_BinOp()) ||
+ cast<BinaryOperator>(V00)->getOpcode() != OtherOpc)
+ std::swap(V00, V01);
+
+ // We need a binop with the same opcode in V00, and a value with a different
+ // opcode in V01.
+ BinaryOperator *B00, *B01;
+ if (!match(V00, m_BinOp(B00)) || B00->getOpcode() != OtherOpc ||
+ (match(V01, m_BinOp(B01)) && B01->getOpcode() == OtherOpc))
+ return;
+
+ // B00 and B1 are displaced matching binops, so pull them together:
+ // (B00 & V01) & B1 --> (B00 & B1) & V01
+ IRBuilder<> Builder(&B);
+ Builder.SetInstDebugLocation(&B);
+ Value *NewBO1 = Builder.CreateBinOp(TopOpc, B00, B1);
+ Value *NewBO2 = Builder.CreateBinOp(TopOpc, NewBO1, V01);
+
+ // Fast-math-flags propagate from B; wrapping flags are cleared.
+ if (auto *I1 = dyn_cast<Instruction>(NewBO1))
+ I1->copyIRFlags(&B, false);
+ if (auto *I2 = dyn_cast<Instruction>(NewBO2))
+ I2->copyIRFlags(&B, false);
+
+ B.replaceAllUsesWith(NewBO2);
+ return;
+}
+
void ReassociatePass::ReassociateExpression(BinaryOperator *I) {
// First, walk the expression tree, linearizing the tree, collecting the
// operand information.
@@ -2250,6 +2311,9 @@ void ReassociatePass::ReassociateExpression(BinaryOperator *I) {
// Now that we ordered and optimized the expressions, splat them back into
// the expression tree, removing any unneeded nodes.
RewriteExprTree(I, Ops);
+
+ // Try a final reassociation of the root of the tree.
+ swapOperandsToMatchBinops(*I);
}
void
OpenPOWER on IntegriCloud