diff options
Diffstat (limited to 'llvm/lib/Transforms/Scalar/InstructionCombining.cpp')
| -rw-r--r-- | llvm/lib/Transforms/Scalar/InstructionCombining.cpp | 150 | 
1 files changed, 150 insertions, 0 deletions
| diff --git a/llvm/lib/Transforms/Scalar/InstructionCombining.cpp b/llvm/lib/Transforms/Scalar/InstructionCombining.cpp new file mode 100644 index 00000000000..87f8ed1897f --- /dev/null +++ b/llvm/lib/Transforms/Scalar/InstructionCombining.cpp @@ -0,0 +1,150 @@ +//===- InstructionCombining.cpp - Combine multiple instructions -------------=// +// +// InstructionCombining - Combine instructions to form fewer, simple +//   instructions.  This pass does not modify the CFG, and has a tendancy to +//   make instructions dead, so a subsequent DCE pass is useful. +// +// This pass combines things like: +//    %Y = add int 1, %X +//    %Z = add int 1, %Y +// into: +//    %Z = add int 2, %X +// +// This is a simple worklist driven algorithm. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/InstructionCombining.h" +#include "../TransformInternals.h" +#include "llvm/Optimizations/ConstantHandling.h" +#include "llvm/Method.h" +#include "llvm/iMemory.h" + +using namespace opt; + +static Instruction *CombineBinOp(BinaryOperator *I) { +  bool Changed = false; + +  // First thing we do is make sure that this instruction has a constant on the +  // right hand side if it has any constant arguments. +  // +  if (isa<Constant>(I->getOperand(0)) && !isa<Constant>(I->getOperand(1))) +    if (!I->swapOperands()) +      Changed = true; + +  bool LocalChange = true; +  while (LocalChange) { +    LocalChange = false; +    Value *Op1 = I->getOperand(0); +    if (Constant *Op2 = dyn_cast<Constant>(I->getOperand(1))) { +      if (I->getOpcode() == Instruction::Add) { +        if (Instruction *IOp1 = dyn_cast<Instruction>(Op1)) { +          if (IOp1->getOpcode() == Instruction::Add && +              isa<Constant>(IOp1->getOperand(1))) { +            // Fold: +            //    %Y = add int %X, 1 +            //    %Z = add int %Y, 1 +            // into: +            //    %Z = add int %X, 2 +            //    +            // Constant fold both constants... +            Constant *Val = *Op2 + *cast<Constant>(IOp1->getOperand(1)); +             +            if (Val) { +              I->setOperand(0, IOp1->getOperand(0)); +              I->setOperand(1, Val); +              LocalChange = true; +            } +          } +           +        } +      } +    } +    Changed |= LocalChange; +  } + +  if (!Changed) return 0; +  return I; +} + +// Combine Indices - If the source pointer to this mem access instruction is a +// getelementptr instruction, combine the indices of the GEP into this +// instruction +// +static Instruction *CombineIndicies(MemAccessInst *MAI) { +  GetElementPtrInst *Src = +    dyn_cast<GetElementPtrInst>(MAI->getPointerOperand()); +  if (!Src) return 0; + +  vector<Value *> Indices; +   +  // Only special case we have to watch out for is pointer arithmetic on the +  // 0th index of MAI.  +  unsigned FirstIdx = MAI->getFirstIndexOperandNumber(); +  if (FirstIdx == MAI->getNumOperands() ||  +      (FirstIdx == MAI->getNumOperands()-1 && +       MAI->getOperand(FirstIdx) == ConstantUInt::get(Type::UIntTy, 0))) {  +    // Replace the index list on this MAI with the index on the getelementptr +    Indices.insert(Indices.end(), Src->idx_begin(), Src->idx_end()); +  } else if (*MAI->idx_begin() == ConstantUInt::get(Type::UIntTy, 0)) {  +    // Otherwise we can do the fold if the first index of the GEP is a zero +    Indices.insert(Indices.end(), Src->idx_begin(), Src->idx_end()); +    Indices.insert(Indices.end(), MAI->idx_begin()+1, MAI->idx_end()); +  } + +  if (Indices.empty()) return 0;  // Can't do the fold? + +  switch (MAI->getOpcode()) { +  case Instruction::GetElementPtr: +    return new GetElementPtrInst(Src->getOperand(0), Indices, MAI->getName()); +  case Instruction::Load: +    return new LoadInst(Src->getOperand(0), Indices, MAI->getName()); +  case Instruction::Store: +    return new StoreInst(MAI->getOperand(0), Src->getOperand(0), +                         Indices, MAI->getName()); +  default: +    assert(0 && "Unknown memaccessinst!"); +    break; +  } +  abort(); +  return 0; +} + +bool InstructionCombining::CombineInstruction(Instruction *I) { +  Instruction *Result = 0; +  if (BinaryOperator *BOP = dyn_cast<BinaryOperator>(I)) +    Result = CombineBinOp(BOP); +  else if (MemAccessInst *MAI = dyn_cast<MemAccessInst>(I)) +    Result = CombineIndicies(MAI); + +  if (!Result) return false; +  if (Result == I) return true; + +  // If we get to here, we are to replace I with Result. +  ReplaceInstWithInst(I, Result); +  return true; +} + + +bool InstructionCombining::doit(Method *M) { +  // Start the worklist out with all of the instructions in the method in it. +  vector<Instruction*> WorkList(M->inst_begin(), M->inst_end()); + +  while (!WorkList.empty()) { +    Instruction *I = WorkList.back();  // Get an instruction from the worklist +    WorkList.pop_back(); + +    // Now that we have an instruction, try combining it to simplify it... +    if (CombineInstruction(I)) { +      // The instruction was simplified, add all users of the instruction to +      // the work lists because they might get more simplified now... +      // +      for (Value::use_iterator UI = I->use_begin(), UE = I->use_end(); +           UI != UE; ++UI) +        if (Instruction *User = dyn_cast<Instruction>(*UI)) +          WorkList.push_back(User); +    } +  } + +  return false; +} | 

