mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-12 18:33:22 +00:00
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
This commit is contained in:
parent
103f2eede3
commit
eaa13851a7
@ -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
|
||||
|
251
lib/Transforms/Scalar/LoopStrengthReduce.cpp
Normal file
251
lib/Transforms/Scalar/LoopStrengthReduce.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user