Initial implementation of the strength reduction for GEP instructions in
authorNate Begeman <natebegeman@mac.com>
Mon, 18 Oct 2004 21:08:22 +0000 (21:08 +0000)
committerNate Begeman <natebegeman@mac.com>
Mon, 18 Oct 2004 21:08:22 +0000 (21:08 +0000)
loops.  This optimization is not turned on by default yet, but may be run
with the opt tool's -loop-reduce flag.  There are many FIXMEs listed in the
code that will make it far more applicable to a wide range of code, but you
have to start somewhere :)

This limited version currently triggers on the following tests in the
MultiSource directory:
pcompress2: 7 times
cfrac: 5 times
anagram: 2 times
ks: 6 times
yacr2: 2 times

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17134 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Transforms/Scalar.h
lib/Transforms/Scalar/LoopStrengthReduce.cpp [new file with mode: 0644]

index 34e87dc658e96f4fd3de3be300aca6646bfbd764..5515c6a59e602da85904bfa7dab275e648a6ea79 100644 (file)
@@ -141,6 +141,12 @@ FunctionPass *createInstructionCombiningPass();
 //
 FunctionPass *createLICMPass();
 
+//===----------------------------------------------------------------------===//
+//
+// LoopStrengthReduce - This pass is strength reduces GEP instructions that use
+// a loop's canonical induction variable as one of their indices.
+//
+FunctionPass *createLoopStrengthReducePass();
 
 //===----------------------------------------------------------------------===//
 //
@@ -155,7 +161,6 @@ FunctionPass *createLoopUnswitchPass();
 //
 FunctionPass *createLoopUnrollPass();
 
-
 //===----------------------------------------------------------------------===//
 //
 // This pass is used to promote memory references to be register references.  A
diff --git a/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/lib/Transforms/Scalar/LoopStrengthReduce.cpp
new file mode 100644 (file)
index 0000000..db57ce6
--- /dev/null
@@ -0,0 +1,251 @@
+//===- LoopStrengthReduce.cpp - Strength Reduce GEPs in Loops -------------===//
+// 
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Nate Begeman and is distributed under the
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+// 
+//===----------------------------------------------------------------------===//
+//
+// This pass performs a strength reduction on array references inside loops that
+// have as one or more of their components the loop induction variable.  This is
+// accomplished by creating a new Value to hold the initial value of the array
+// access for the first iteration, and then creating a new GEP instruction in
+// the loop to increment the value by the appropriate amount.
+//
+// There are currently several deficiencies in the implementation, marked with
+// FIXME in the code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Constants.h"
+#include "llvm/Instructions.h"
+#include "llvm/Type.h"
+#include "llvm/Analysis/Dominators.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Support/CFG.h"
+#include "llvm/Transforms/Utils/Local.h"
+#include "llvm/ADT/Statistic.h"
+#include <set>
+using namespace llvm;
+
+namespace {
+  Statistic<> NumReduced ("loop-reduce", "Number of GEPs strength reduced");
+
+  class LoopStrengthReduce : public FunctionPass {
+    LoopInfo *LI;
+    DominatorSet *DS;
+    bool Changed;
+  public:
+    virtual bool runOnFunction(Function &) {
+      LI = &getAnalysis<LoopInfo>();
+      DS = &getAnalysis<DominatorSet>();
+      Changed = false;
+
+      for (LoopInfo::iterator I = LI->begin(), E = LI->end(); I != E; ++I)
+        runOnLoop(*I);
+      return Changed;
+    }
+
+    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+      AU.setPreservesCFG();
+      AU.addRequired<LoopInfo>();
+      AU.addRequired<DominatorSet>();
+    }
+  private:
+    void runOnLoop(Loop *L);
+    void strengthReduceGEP(GetElementPtrInst *GEPI, Loop *L,
+                           Instruction *InsertBefore,
+                           std::set<Instruction*> &DeadInsts);
+    void DeleteTriviallyDeadInstructions(std::set<Instruction*> &Insts);
+  };
+  RegisterOpt<LoopStrengthReduce> X("loop-reduce", 
+                                    "Strength Reduce GEP Uses of Ind. Vars");
+}
+
+FunctionPass *llvm::createLoopStrengthReducePass() {
+  return new LoopStrengthReduce();
+}
+
+/// DeleteTriviallyDeadInstructions - If any of the instructions is the
+/// specified set are trivially dead, delete them and see if this makes any of
+/// their operands subsequently dead.
+void LoopStrengthReduce::
+DeleteTriviallyDeadInstructions(std::set<Instruction*> &Insts) {
+  while (!Insts.empty()) {
+    Instruction *I = *Insts.begin();
+    Insts.erase(Insts.begin());
+    if (isInstructionTriviallyDead(I)) {
+      for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i)
+        if (Instruction *U = dyn_cast<Instruction>(I->getOperand(i)))
+          Insts.insert(U);
+      I->getParent()->getInstList().erase(I);
+      Changed = true;
+    }
+  }
+}
+
+void LoopStrengthReduce::strengthReduceGEP(GetElementPtrInst *GEPI, Loop *L,
+                                           Instruction *InsertBefore,
+                                           std::set<Instruction*> &DeadInsts) {
+  // We will strength reduce the GEP by splitting it into two parts.  The first
+  // is a GEP to hold the initial value of the non-strength-reduced GEP upon
+  // entering the loop, which we will insert at the end of the loop preheader.
+  // The second is a GEP to hold the incremented value of the initial GEP.
+  // The LoopIndVarSimplify pass guarantees that loop counts start at zero, so
+  // we will replace the indvar with a constant zero value to create the first
+  // GEP.
+  //
+  // We currently only handle GEP instructions that consist of zero or more
+  // constants and one instance of the canonical induction variable.
+  bool foundIndvar = false;
+  bool indvarLast = false;
+  std::vector<Value *> pre_op_vector;
+  std::vector<Value *> inc_op_vector;
+  Value *CanonicalIndVar = L->getCanonicalInductionVariable();
+  for (unsigned op = 1, e = GEPI->getNumOperands(); op != e; ++op) {
+    Value *operand = GEPI->getOperand(op);
+    if (operand == CanonicalIndVar) {
+      // FIXME: We currently only support strength reducing GEP instructions
+      // with one instance of the canonical induction variable.  This means that 
+      // we can't deal with statements of the form A[i][i].
+      if (foundIndvar == true)
+        return;
+        
+      // FIXME: use getCanonicalInductionVariableIncrement to choose between
+      // one and neg one maybe?  We need to support int *foo = GEP base, -1
+      const Type *Ty = CanonicalIndVar->getType();
+      pre_op_vector.push_back(Constant::getNullValue(Ty));
+      inc_op_vector.push_back(ConstantInt::get(Ty, 1));
+      foundIndvar = true;
+      indvarLast = true;
+    } else if (isa<Constant>(operand)) {
+      pre_op_vector.push_back(operand);
+      if (indvarLast == true) indvarLast = false;
+    } else
+      return;
+  }
+  // FIXME: handle GEPs where the indvar is not the last element of the index
+  // array.
+  if (indvarLast == false)
+    return;
+  assert(true == foundIndvar && "Indvar used by GEP not found in operand list");
+  
+  // FIXME: Being able to hoist the definition of the initial pointer value
+  // would allow us to strength reduce more loops.  For example, %tmp.32 in the
+  // following loop:
+  // entry:
+  //   br label %no_exit.0
+  // no_exit.0:                ; preds = %entry, %no_exit.0
+  //   %init.1.0 = phi uint [ 0, %entry ], [ %indvar.next, %no_exit.0 ]
+  //   %tmp.32 = load uint** %CROSSING
+  //   %tmp.35 = getelementptr uint* %tmp.32, uint %init.1.0
+  //   br label %no_exit.0
+  BasicBlock *Header = L->getHeader();
+  if (Instruction *GepPtrOp = dyn_cast<Instruction>(GEPI->getOperand(0)))
+    if (!DS->dominates(GepPtrOp, Header->begin()))
+      return;
+  
+  // If all operands of the GEP we are going to insert into the preheader
+  // are constants, generate a GEP ConstantExpr instead. 
+  //
+  // If there is only one operand after the initial non-constant one, we know
+  // that it was the induction variable, and has been replaced by a constant
+  // null value.  In this case, replace the GEP with a use of pointer directly.
+  //
+  // 
+  BasicBlock *Preheader = L->getLoopPreheader();
+  Value *PreGEP;
+  if (isa<Constant>(GEPI->getOperand(0))) {
+    Constant *C = dyn_cast<Constant>(GEPI->getOperand(0));
+    PreGEP = ConstantExpr::getGetElementPtr(C, pre_op_vector);
+  } else if (pre_op_vector.size() == 1) {
+    PreGEP = GEPI->getOperand(0);
+  } else {
+    PreGEP = new GetElementPtrInst(GEPI->getOperand(0),
+                                   pre_op_vector, GEPI->getName(), 
+                                   Preheader->getTerminator());
+  }
+
+  // The next step of the strength reduction is to create a PHI that will choose
+  // between the initial GEP we created and inserted into the preheader, and 
+  // the incremented GEP that we will create below and insert into the loop body
+  PHINode *NewPHI = new PHINode(PreGEP->getType(), 
+                                GEPI->getName()+".str", InsertBefore);
+  NewPHI->addIncoming(PreGEP, Preheader);
+  
+  // Now, create the GEP instruction to increment the value selected by the PHI
+  // instruction we just created above by one, and add it as the second incoming
+  // Value and BasicBlock pair to the PHINode.
+  Instruction *IncrInst = 
+    const_cast<Instruction*>(L->getCanonicalInductionVariableIncrement());
+  GetElementPtrInst *StrGEP = new GetElementPtrInst(NewPHI, inc_op_vector,
+                                                    GEPI->getName()+".inc",
+                                                    IncrInst);
+  NewPHI->addIncoming(StrGEP, IncrInst->getParent());
+  
+  // Replace all uses of the old GEP instructions with the new PHI
+  GEPI->replaceAllUsesWith(NewPHI);
+  
+  // The old GEP is now dead.
+  DeadInsts.insert(GEPI);
+  ++NumReduced;
+}
+
+void LoopStrengthReduce::runOnLoop(Loop *L) {
+  // First step, transform all loops nesting inside of this loop.
+  for (LoopInfo::iterator I = L->begin(), E = L->end(); I != E; ++I)
+    runOnLoop(*I);
+
+  // Next, get the first PHINode since it is guaranteed to be the canonical
+  // induction variable for the loop by the preceding IndVarSimplify pass.
+  PHINode *PN = L->getCanonicalInductionVariable();
+  if (0 == PN)
+    return;
+
+  // Insert secondary PHI nodes after the canonical induction variable's PHI
+  // for the strength reduced pointers that we will be creating.
+  Instruction *InsertBefore = PN->getNext();
+
+  // FIXME: Need to use SCEV to detect GEP uses of the indvar, since indvars
+  // pass creates code like this, which we can't currently detect:
+  //  %tmp.1 = sub uint 2000, %indvar
+  //  %tmp.8 = getelementptr int* %y, uint %tmp.1
+  
+  // Strength reduce all GEPs in the Loop
+  std::set<Instruction*> DeadInsts;
+  for (Value::use_iterator UI = PN->use_begin(), UE = PN->use_end();
+       UI != UE; ++UI)
+    if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(*UI))
+      strengthReduceGEP(GEPI, L, InsertBefore, DeadInsts);
+
+  // Clean up after ourselves
+  if (!DeadInsts.empty()) {
+    DeleteTriviallyDeadInstructions(DeadInsts);
+
+    // At this point, we know that we have killed one or more GEP instructions.
+    // It is worth checking to see if the cann indvar is also dead, so that we
+    // can remove it as well.  The requirements for the cann indvar to be
+    // considered dead are:
+    // 1. the cann indvar has one use
+    // 2. the use is an add instruction
+    // 3. the add has one use
+    // 4. the add is used by the cann indvar
+    // If all four cases above are true, then we can remove both the add and
+    // the cann indvar.
+    if (PN->hasOneUse()) {
+      BinaryOperator *BO = dyn_cast<BinaryOperator>(*(PN->use_begin()));
+      if (BO && BO->getOpcode() == Instruction::Add)
+        if (BO->hasOneUse()) {
+          PHINode *PotentialIndvar = dyn_cast<PHINode>(*(BO->use_begin()));
+          if (PotentialIndvar && PN == PotentialIndvar) {
+            PN->dropAllReferences();
+            DeadInsts.insert(BO);
+            DeadInsts.insert(PN);
+            DeleteTriviallyDeadInstructions(DeadInsts);
+          }
+        }
+    }
+  }
+}