#include "llvm/Support/Debug.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Statistic.h"
+#include <algorithm>
using namespace llvm;
namespace {
Statistic<> NumChanged("reassociate","Number of insts reassociated");
Statistic<> NumSwapped("reassociate","Number of insts with operands swapped");
+ struct ValueEntry {
+ unsigned Rank;
+ Value *Op;
+ ValueEntry(unsigned R, Value *O) : Rank(R), Op(O) {}
+ };
+ inline bool operator<(const ValueEntry &LHS, const ValueEntry &RHS) {
+ return LHS.Rank > RHS.Rank; // Sort so that highest rank goes to start.
+ }
+
class Reassociate : public FunctionPass {
std::map<BasicBlock*, unsigned> RankMap;
std::map<Value*, unsigned> ValueRankMap;
+ bool MadeChange;
public:
bool runOnFunction(Function &F);
private:
void BuildRankMap(Function &F);
unsigned getRank(Value *V);
- bool ReassociateExpr(BinaryOperator *I);
- bool ReassociateBB(BasicBlock *BB);
+ void RewriteExprTree(BinaryOperator *I, unsigned Idx,
+ std::vector<ValueEntry> &Ops);
+ void LinearizeExprTree(BinaryOperator *I, std::vector<ValueEntry> &Ops);
+ void LinearizeExpr(BinaryOperator *I);
+ void ReassociateBB(BasicBlock *BB);
};
RegisterOpt<Reassociate> X("reassociate", "Reassociate expressions");
return CachedRank = Rank+1;
}
+/// isReassociableOp - Return true if V is an instruction of the specified
+/// opcode and if it only has one use.
+static BinaryOperator *isReassociableOp(Value *V, unsigned Opcode) {
+ if (V->hasOneUse() && isa<Instruction>(V) &&
+ cast<Instruction>(V)->getOpcode() == Opcode)
+ return cast<BinaryOperator>(V);
+ return 0;
+}
-bool Reassociate::ReassociateExpr(BinaryOperator *I) {
- Value *LHS = I->getOperand(0);
- Value *RHS = I->getOperand(1);
- unsigned LHSRank = getRank(LHS);
- unsigned RHSRank = getRank(RHS);
+// Given an expression of the form '(A+B)+(D+C)', turn it into '(((A+B)+C)+D)'.
+// Note that if D is also part of the expression tree that we recurse to
+// linearize it as well. Besides that case, this does not recurse into A,B, or
+// C.
+void Reassociate::LinearizeExpr(BinaryOperator *I) {
+ BinaryOperator *LHS = cast<BinaryOperator>(I->getOperand(0));
+ BinaryOperator *RHS = cast<BinaryOperator>(I->getOperand(1));
+ assert(isReassociableOp(LHS, I->getOpcode()) &&
+ isReassociableOp(RHS, I->getOpcode()) &&
+ "Not an expression that needs linearization?");
+
+ DEBUG(std::cerr << "Linear" << *LHS << *RHS << *I);
+
+ // Move the RHS instruction to live immediately before I, avoiding breaking
+ // dominator properties.
+ I->getParent()->getInstList().splice(I, RHS->getParent()->getInstList(), RHS);
+
+ // Move operands around to do the linearization.
+ I->setOperand(1, RHS->getOperand(0));
+ RHS->setOperand(0, LHS);
+ I->setOperand(0, RHS);
+
+ ++NumLinear;
+ MadeChange = true;
+ DEBUG(std::cerr << "Linearized: " << *I);
- bool Changed = false;
+ // If D is part of this expression tree, tail recurse.
+ if (isReassociableOp(I->getOperand(1), I->getOpcode()))
+ LinearizeExpr(I);
+}
- // Make sure the LHS of the operand always has the greater rank...
- if (LHSRank < RHSRank) {
- bool Success = !I->swapOperands();
- assert(Success && "swapOperands failed");
- std::swap(LHS, RHS);
- std::swap(LHSRank, RHSRank);
- Changed = true;
- ++NumSwapped;
- DEBUG(std::cerr << "Transposed: " << *I
- /* << " Result BB: " << I->getParent()*/);
+/// LinearizeExprTree - Given an associative binary expression tree, traverse
+/// all of the uses putting it into canonical form. This forces a left-linear
+/// form of the the expression (((a+b)+c)+d), and collects information about the
+/// rank of the non-tree operands.
+///
+/// This returns the rank of the RHS operand, which is known to be the highest
+/// rank value in the expression tree.
+///
+void Reassociate::LinearizeExprTree(BinaryOperator *I,
+ std::vector<ValueEntry> &Ops) {
+ Value *LHS = I->getOperand(0), *RHS = I->getOperand(1);
+ unsigned Opcode = I->getOpcode();
+
+ // First step, linearize the expression if it is in ((A+B)+(C+D)) form.
+ BinaryOperator *LHSBO = isReassociableOp(LHS, Opcode);
+ BinaryOperator *RHSBO = isReassociableOp(RHS, Opcode);
+
+ if (!LHSBO) {
+ if (!RHSBO) {
+ // Neither the LHS or RHS as part of the tree, thus this is a leaf. As
+ // such, just remember these operands and their rank.
+ Ops.push_back(ValueEntry(getRank(LHS), LHS));
+ Ops.push_back(ValueEntry(getRank(RHS), RHS));
+ return;
+ } else {
+ // Turn X+(Y+Z) -> (Y+Z)+X
+ std::swap(LHSBO, RHSBO);
+ std::swap(LHS, RHS);
+ bool Success = !I->swapOperands();
+ assert(Success && "swapOperands failed");
+ MadeChange = true;
+ }
+ } else if (RHSBO) {
+ // Turn (A+B)+(C+D) -> (((A+B)+C)+D). This guarantees the the RHS is not
+ // part of the expression tree.
+ LinearizeExpr(I);
+ LHS = LHSBO = cast<BinaryOperator>(I->getOperand(0));
+ RHS = I->getOperand(1);
+ RHSBO = 0;
}
- // If the LHS is the same operator as the current one is, and if we are the
- // only expression using it...
- //
- if (BinaryOperator *LHSI = dyn_cast<BinaryOperator>(LHS))
- if (LHSI->getOpcode() == I->getOpcode() && LHSI->hasOneUse()) {
- // If the rank of our current RHS is less than the rank of the LHS's LHS,
- // then we reassociate the two instructions...
-
- unsigned TakeOp = 0;
- if (BinaryOperator *IOp = dyn_cast<BinaryOperator>(LHSI->getOperand(0)))
- if (IOp->getOpcode() == LHSI->getOpcode())
- TakeOp = 1; // Hoist out non-tree portion
-
- if (RHSRank < getRank(LHSI->getOperand(TakeOp))) {
- // Convert ((a + 12) + 10) into (a + (12 + 10))
- I->setOperand(0, LHSI->getOperand(TakeOp));
- LHSI->setOperand(TakeOp, RHS);
- I->setOperand(1, LHSI);
-
- // Move the LHS expression forward, to ensure that it is dominated by
- // its operands.
- LHSI->getParent()->getInstList().remove(LHSI);
- I->getParent()->getInstList().insert(I, LHSI);
-
- ++NumChanged;
- DEBUG(std::cerr << "Reassociated: " << *I/* << " Result BB: "
- << I->getParent()*/);
-
- // Since we modified the RHS instruction, make sure that we recheck it.
- ReassociateExpr(LHSI);
- ReassociateExpr(I);
- return true;
- }
- }
+ // Okay, now we know that the LHS is a nested expression and that the RHS is
+ // not. Perform reassociation.
+ assert(!isReassociableOp(RHS, Opcode) && "LinearizeExpr failed!");
- return Changed;
+ // Move LHS right before I to make sure that the tree expression dominates all
+ // values.
+ I->getParent()->getInstList().splice(I,
+ LHSBO->getParent()->getInstList(), LHSBO);
+
+ // Linearize the expression tree on the LHS.
+ LinearizeExprTree(LHSBO, Ops);
+
+ // Remember the RHS operand and its rank.
+ Ops.push_back(ValueEntry(getRank(RHS), RHS));
+}
+
+// RewriteExprTree - Now that the operands for this expression tree are
+// linearized and optimized, emit them in-order. This function is written to be
+// tail recursive.
+void Reassociate::RewriteExprTree(BinaryOperator *I, unsigned i,
+ std::vector<ValueEntry> &Ops) {
+ if (i+2 == Ops.size()) {
+ if (I->getOperand(0) != Ops[i].Op ||
+ I->getOperand(1) != Ops[i+1].Op) {
+ DEBUG(std::cerr << "RA: " << *I);
+ I->setOperand(0, Ops[i].Op);
+ I->setOperand(1, Ops[i+1].Op);
+ DEBUG(std::cerr << "TO: " << *I);
+ MadeChange = true;
+ ++NumChanged;
+ }
+ return;
+ }
+ assert(i+2 < Ops.size() && "Ops index out of range!");
+
+ if (I->getOperand(1) != Ops[i].Op) {
+ DEBUG(std::cerr << "RA: " << *I);
+ I->setOperand(1, Ops[i].Op);
+ DEBUG(std::cerr << "TO: " << *I);
+ MadeChange = true;
+ ++NumChanged;
+ }
+ RewriteExprTree(cast<BinaryOperator>(I->getOperand(0)), i+1, Ops);
}
+
// NegateValue - Insert instructions before the instruction pointed to by BI,
// that computes the negative version of the value specified. The negative
// version of the value is returned, and BI is left pointing at the instruction
return BinaryOperator::createNeg(V, V->getName() + ".neg", BI);
}
-/// isReassociableOp - Return true if V is an instruction of the specified
-/// opcode and if it only has one use.
-static bool isReassociableOp(Value *V, unsigned Opcode) {
- return V->hasOneUse() && isa<Instruction>(V) &&
- cast<Instruction>(V)->getOpcode() == Opcode;
-}
-
/// BreakUpSubtract - If we have (X-Y), and if either X is an add, or if this is
/// only used by an add, transform this into (X+(0-Y)) to promote better
/// reassociation.
/// ReassociateBB - Inspect all of the instructions in this basic block,
/// reassociating them as we go.
-bool Reassociate::ReassociateBB(BasicBlock *BB) {
- bool Changed = false;
+void Reassociate::ReassociateBB(BasicBlock *BB) {
for (BasicBlock::iterator BI = BB->begin(); BI != BB->end(); ++BI) {
// If this is a subtract instruction which is not already in negate form,
// see if we can convert it to X+-Y.
if (BI->getOpcode() == Instruction::Sub && !BinaryOperator::isNeg(BI))
if (Instruction *NI = BreakUpSubtract(BI)) {
- Changed = true;
+ MadeChange = true;
BI = NI;
}
if (BI->getOpcode() == Instruction::Shl &&
isa<ConstantInt>(BI->getOperand(1)))
if (Instruction *NI = ConvertShiftToMul(BI)) {
- Changed = true;
+ MadeChange = true;
BI = NI;
}
- // If this instruction is a commutative binary operator, and the ranks of
- // the two operands are sorted incorrectly, fix it now.
- //
- if (BI->isAssociative()) {
- DEBUG(std::cerr << "Reassociating: " << *BI);
- BinaryOperator *I = cast<BinaryOperator>(BI);
- if (!I->use_empty()) {
- // Make sure that we don't have a tree-shaped computation. If we do,
- // linearize it. Convert (A+B)+(C+D) into ((A+B)+C)+D
- //
- Instruction *LHSI = dyn_cast<Instruction>(I->getOperand(0));
- Instruction *RHSI = dyn_cast<Instruction>(I->getOperand(1));
- if (LHSI && (int)LHSI->getOpcode() == I->getOpcode() &&
- RHSI && (int)RHSI->getOpcode() == I->getOpcode() &&
- RHSI->hasOneUse()) {
- // Insert a new temporary instruction... (A+B)+C
- BinaryOperator *Tmp = BinaryOperator::create(I->getOpcode(), LHSI,
- RHSI->getOperand(0),
- RHSI->getName()+".ra",
- BI);
- BI = Tmp;
- I->setOperand(0, Tmp);
- I->setOperand(1, RHSI->getOperand(1));
-
- // Process the temporary instruction for reassociation now.
- I = Tmp;
- ++NumLinear;
- Changed = true;
- DEBUG(std::cerr << "Linearized: " << *I/* << " Result BB: " << BB*/);
+ // If this instruction is a commutative binary operator, process it.
+ if (!BI->isAssociative()) continue;
+ BinaryOperator *I = cast<BinaryOperator>(BI);
+
+ // If this is an interior node of a reassociable tree, ignore it until we
+ // get to the root of the tree, to avoid N^2 analysis.
+ if (I->hasOneUse() && isReassociableOp(I->use_back(), I->getOpcode()))
+ continue;
+
+ // First, walk the expression tree, linearizing the tree, collecting
+ std::vector<ValueEntry> Ops;
+ LinearizeExprTree(I, Ops);
+
+ // Now that we have linearized the tree to a list and have gathered all of
+ // the operands and their ranks, sort the operands by their rank. Use a
+ // stable_sort so that values with equal ranks will have their relative
+ // positions maintained (and so the compiler is deterministic). Note that
+ // this sorts so that the highest ranking values end up at the beginning of
+ // the vector.
+ std::stable_sort(Ops.begin(), Ops.end());
+
+ // Now that we have the linearized expression tree, try to optimize it.
+ // Start by folding any constants that we found.
+ FoldConstants:
+ if (Ops.size() > 1)
+ if (Constant *V1 = dyn_cast<Constant>(Ops[Ops.size()-2].Op))
+ if (Constant *V2 = dyn_cast<Constant>(Ops.back().Op)) {
+ Ops.pop_back();
+ Ops.back().Op = ConstantExpr::get(I->getOpcode(), V1, V2);
+ goto FoldConstants;
}
- // Make sure that this expression is correctly reassociated with respect
- // to it's used values...
- //
- Changed |= ReassociateExpr(I);
- }
+ // FIXME: Handle destructive annihilation here. Ensure RANK(neg(x)) ==
+ // RANK(x) [and not]. Handle case when Cst = 0 and op = AND f.e.
+
+ // FIXME: Handle +0,*1,&~0,... at end of the list.
+
+
+ if (Ops.size() == 1) {
+ // This expression tree simplified to something that isn't a tree,
+ // eliminate it.
+ I->replaceAllUsesWith(Ops[0].Op);
+ } else {
+ // Now that we ordered and optimized the expressions, splat them back into
+ // the expression tree, removing any unneeded nodes.
+ RewriteExprTree(I, 0, Ops);
}
}
-
- return Changed;
}
// Recalculate the rank map for F
BuildRankMap(F);
- bool Changed = false;
+ MadeChange = false;
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
- Changed |= ReassociateBB(FI);
+ ReassociateBB(FI);
// We are done with the rank map...
RankMap.clear();
ValueRankMap.clear();
- return Changed;
+ return MadeChange;
}