aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNate Begeman <natebegeman@mac.com>2004-10-18 21:08:22 +0000
committerNate Begeman <natebegeman@mac.com>2004-10-18 21:08:22 +0000
commiteaa13851a7fe604363577350c5cf65c257c4d41a (patch)
tree6a697cff36c099f32c520d2e6b67cb043cc71875
parent103f2eede3f0586449be1601afc0ea26275c4c10 (diff)
downloadexternal_llvm-eaa13851a7fe604363577350c5cf65c257c4d41a.zip
external_llvm-eaa13851a7fe604363577350c5cf65c257c4d41a.tar.gz
external_llvm-eaa13851a7fe604363577350c5cf65c257c4d41a.tar.bz2
Initial implementation of the strength reduction for GEP instructions in
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
-rw-r--r--include/llvm/Transforms/Scalar.h7
-rw-r--r--lib/Transforms/Scalar/LoopStrengthReduce.cpp251
2 files changed, 257 insertions, 1 deletions
diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h
index 34e87dc..5515c6a 100644
--- a/include/llvm/Transforms/Scalar.h
+++ b/include/llvm/Transforms/Scalar.h
@@ -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
index 0000000..db57ce6
--- /dev/null
+++ b/lib/Transforms/Scalar/LoopStrengthReduce.cpp
@@ -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);
+ }
+ }
+ }
+ }
+}