diff options
Diffstat (limited to 'llvm/lib/Transforms')
| -rw-r--r-- | llvm/lib/Transforms/Scalar/Reassociate.cpp | 288 | 
1 files changed, 185 insertions, 103 deletions
| diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp index d00423edf5a..341cac64c77 100644 --- a/llvm/lib/Transforms/Scalar/Reassociate.cpp +++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -31,6 +31,7 @@  #include "llvm/Support/Debug.h"  #include "llvm/ADT/PostOrderIterator.h"  #include "llvm/ADT/Statistic.h" +#include <algorithm>  using namespace llvm;  namespace { @@ -38,9 +39,19 @@ 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); @@ -50,8 +61,11 @@ namespace {    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"); @@ -105,67 +119,135 @@ unsigned Reassociate::getRank(Value *V) {    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 @@ -201,13 +283,6 @@ static Value *NegateValue(Value *V, Instruction *BI) {    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. @@ -265,63 +340,70 @@ static Instruction *ConvertShiftToMul(Instruction *Shl) {  /// 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;  } @@ -329,13 +411,13 @@ bool Reassociate::runOnFunction(Function &F) {    // 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;  } | 

