Checkin new pass framework. This one is more useful and automatically

creates analysis results for passes that need them.   MethodPass's never
have to worry about being invoked on external methods.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@1594 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2002-01-30 23:20:39 +00:00
parent b1244c54a4
commit 05ad462d1b
2 changed files with 554 additions and 67 deletions

View File

@ -18,21 +18,80 @@
#ifndef LLVM_PASS_H
#define LLVM_PASS_H
#include "llvm/Module.h"
#include "llvm/Method.h"
class MethodPassBatcher;
#include <vector>
#include <map>
class Value;
class BasicBlock;
class Method;
class Module;
class AnalysisID;
class Pass;
template<class UnitType> class PassManagerT;
struct AnalysisResolver;
//===----------------------------------------------------------------------===//
// Pass interface - Implemented by all 'passes'. Subclass this if you are an
// interprocedural optimization or you do not fit into any of the more
// constrained passes described below.
//
struct Pass {
// Destructor - Virtual so we can be subclassed
inline virtual ~Pass() {}
class Pass {
friend class AnalysisResolver;
AnalysisResolver *Resolver; // AnalysisResolver this pass is owned by...
public:
typedef std::vector<AnalysisID> AnalysisSet;
inline Pass(AnalysisResolver *AR = 0) : Resolver(AR) {}
inline virtual ~Pass() {} // Destructor is virtual so we can be subclassed
// run - Run this pass, returning true if a modification was made to the
// module argument. This should be implemented by all concrete subclasses.
//
virtual bool run(Module *M) = 0;
// getAnalysisUsageInfo - This function should be overriden by passes that
// need analysis information to do their job. If a pass specifies that it
// uses a particular analysis result to this function, it can then use the
// getAnalysis<AnalysisType>() function, below.
//
// The Destroyed vector is used to communicate what analyses are invalidated
// by this pass. This is critical to specify so that the PassManager knows
// which analysis must be rerun after this pass has proceeded. Analysis are
// only invalidated if run() returns true.
//
// The Provided vector is used for passes that provide analysis information,
// these are the analysis passes themselves. All analysis passes should
// override this method to return themselves in the provided set.
//
virtual void getAnalysisUsageInfo(AnalysisSet &Required,
AnalysisSet &Destroyed,
AnalysisSet &Provided) {
// By default, no analysis results are used or destroyed.
}
#ifndef NDEBUG
// dumpPassStructure - Implement the -debug-passes=PassStructure option
virtual void dumpPassStructure(unsigned Offset = 0);
#endif
protected:
// getAnalysis<AnalysisType>() - This function is used by subclasses to get to
// the analysis information that they claim to use by overriding the
// getAnalysisUsageInfo function.
//
template<typename AnalysisType>
AnalysisType &getAnalysis(AnalysisID AID = AnalysisType::ID) {
assert(Resolver && "Pass not resident in a PassManager object!");
return *(AnalysisType*)Resolver->getAnalysis(AID);
}
private:
friend class PassManagerT<Module>;
friend class PassManagerT<Method>;
friend class PassManagerT<BasicBlock>;
virtual void addToPassManager(PassManagerT<Module> *PM,
AnalysisSet &Destroyed,
AnalysisSet &Provided);
};
@ -60,40 +119,27 @@ struct MethodPass : public Pass {
//
virtual bool doFinalization(Module *M) { return false; }
// run - On a module, we run this pass by initializing, ronOnMethod'ing once
// for every method in the module, then by finalizing.
//
virtual bool run(Module *M);
virtual bool run(Module *M) {
bool Changed = doInitialization(M);
// run - On a method, we simply initialize, run the method, then finalize.
//
bool run(Method *M);
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
Changed |= runOnMethod(*I);
return Changed | doFinalization(M);
}
bool run(Method *M) {
return doInitialization(M->getParent()) | runOnMethod(M)
| doFinalization(M->getParent());
}
private:
friend class PassManagerT<Module>;
friend class PassManagerT<Method>;
friend class PassManagerT<BasicBlock>;
virtual void addToPassManager(PassManagerT<Module> *PM,AnalysisSet &Destroyed,
AnalysisSet &Provided);
virtual void addToPassManager(PassManagerT<Method> *PM,AnalysisSet &Destroyed,
AnalysisSet &Provided);
};
//===----------------------------------------------------------------------===//
// CFGSafeMethodPass class - This class is used to implement global
// optimizations that do not modify the CFG of a method. Optimizations should
// subclass this class if they meet the following constraints:
// 1. Optimizations are global, operating on a method at a time.
// 2. Optimizations do not modify the CFG of the contained method, by adding,
// removing, or changing the order of basic blocks in a method.
// 3. Optimizations conform to all of the contstraints of MethodPass's.
//
struct CFGSafeMethodPass : public MethodPass {
// TODO: Differentiation from MethodPass will come later
};
//===----------------------------------------------------------------------===//
// BasicBlockPass class - This class is used to implement most local
// optimizations. Optimizations should subclass this class if they
@ -102,52 +148,98 @@ struct CFGSafeMethodPass : public MethodPass {
// instruction at a time.
// 2. Optimizations do not modify the CFG of the contained method, or any
// other basic block in the method.
// 3. Optimizations conform to all of the contstraints of CFGSafeMethodPass's.
// 3. Optimizations conform to all of the contstraints of MethodPass's.
//
struct BasicBlockPass : public CFGSafeMethodPass {
struct BasicBlockPass : public MethodPass {
// runOnBasicBlock - Virtual method overriden by subclasses to do the
// per-basicblock processing of the pass.
//
virtual bool runOnBasicBlock(BasicBlock *M) = 0;
virtual bool runOnMethod(Method *M) {
bool Changed = false;
for (Method::iterator I = M->begin(), E = M->end(); I != E; ++I)
Changed |= runOnBasicBlock(*I);
return Changed;
// To run this pass on a method, we simply call runOnBasicBlock once for each
// method.
//
virtual bool runOnMethod(Method *BB);
// To run directly on the basic block, we initialize, runOnBasicBlock, then
// finalize.
//
bool run(BasicBlock *BB);
private:
friend class PassManagerT<Method>;
friend class PassManagerT<BasicBlock>;
virtual void addToPassManager(PassManagerT<Method> *PM,AnalysisSet &Destroyed,
AnalysisSet &Provided);
virtual void addToPassManager(PassManagerT<BasicBlock> *PM,
AnalysisSet &Destroyed,
AnalysisSet &Provided);
};
// CreatePass - Helper template to invoke the constructor for the AnalysisID
// class. Note that this should be a template internal to AnalysisID, but
// GCC 2.95.3 crashes if we do that, doh.
//
template<class AnalysisType>
static Pass *CreatePass(AnalysisID ID) { return new AnalysisType(ID); }
//===----------------------------------------------------------------------===//
// AnalysisID - This class is used to uniquely identify an analysis pass that
// is referenced by a transformation.
//
class AnalysisID {
static unsigned NextID; // Next ID # to deal out...
unsigned ID; // Unique ID for this analysis
Pass *(*Constructor)(AnalysisID); // Constructor to return the Analysis
AnalysisID(); // Disable default ctor
AnalysisID(unsigned id, Pass *(*Ct)(AnalysisID)) : ID(id), Constructor(Ct) {}
public:
// create - the only way to define a new AnalysisID. This static method is
// supposed to be used to define the class static AnalysisID's that are
// provided by analysis passes. In the implementation (.cpp) file for the
// class, there should be a line that looks like this (using CallGraph as an
// example):
//
// AnalysisID CallGraph::ID(AnalysisID::create<CallGraph>());
//
template<class AnalysisType>
static AnalysisID create() {
return AnalysisID(NextID++, CreatePass<AnalysisType>);
}
bool run(BasicBlock *BB) {
Module *M = BB->getParent()->getParent();
return doInitialization(M) | runOnBasicBlock(BB) | doFinalization(M);
inline Pass *createPass() const { return Constructor(*this); }
inline bool operator==(const AnalysisID &A) const {
return A.ID == ID;
}
inline bool operator!=(const AnalysisID &A) const {
return A.ID != ID;
}
inline bool operator<(const AnalysisID &A) const {
return ID < A.ID;
}
};
//===----------------------------------------------------------------------===//
// PassManager - Container object for passes. The PassManager destructor
// deletes all passes contained inside of the PassManager, so you shouldn't
// delete passes manually, and all passes should be dynamically allocated.
// AnalysisResolver - Simple interface implemented by PassManagers objects that
// is used to pull analysis information out of them.
//
class PassManager {
std::vector<Pass*> Passes;
MethodPassBatcher *Batcher;
public:
PassManager() : Batcher(0) {}
~PassManager();
// run - Run all of the queued passes on the specified module in an optimal
// way.
bool run(Module *M);
// add - Add a pass to the queue of passes to run. This passes ownership of
// the Pass to the PassManager. When the PassManager is destroyed, the pass
// will be destroyed as well, so there is no need to delete the pass. Also,
// all passes MUST be new'd.
//
void add(Pass *P);
void add(MethodPass *P);
void add(BasicBlockPass *P);
struct AnalysisResolver {
virtual Pass *getAnalysisOrNullUp(AnalysisID ID) = 0;
virtual Pass *getAnalysisOrNullDown(AnalysisID ID) = 0;
Pass *getAnalysis(AnalysisID ID) {
Pass *Result = getAnalysisOrNullUp(ID);
assert(Result && "Pass has an incorrect analysis uses set!");
return Result;
}
virtual unsigned getDepth() const = 0;
protected:
void setAnalysisResolver(Pass *P, AnalysisResolver *AR);
};
#endif

395
lib/VMCore/PassManagerT.h Normal file
View File

@ -0,0 +1,395 @@
//===- llvm/PassManager.h - Container for Passes -----------------*- C++ -*--=//
//
// This file defines the PassManager class. This class is used to hold,
// maintain, and optimize execution of Pass's. The PassManager class ensures
// that analysis results are available before a pass runs, and that Pass's are
// destroyed when the PassManager is destroyed.
//
// The PassManagerT template is instantiated three times to do its job.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_PASSMANAGER_H
#define LLVM_PASSMANAGER_H
#include "llvm/Pass.h"
#include <string>
// PassManager - Top level PassManagerT instantiation intended to be used.
typedef PassManagerT<Module> PassManager;
//===----------------------------------------------------------------------===//
// PMDebug class - a set of debugging functions that are enabled when compiling
// with -g on. If compiling at -O, all functions are inlined noops.
//
struct PMDebug {
#ifdef NDEBUG
inline static void PrintPassStructure(Pass *) {}
inline static void PrintPassInformation(unsigned,const char*,Pass*,Value*) {}
inline static void PrintAnalysisSetInfo(unsigned,const char*,
const Pass::AnalysisSet &) {}
#else
// If compiled in debug mode, these functions can be enabled by setting
// -debug-pass on the command line of the tool being used.
//
static void PrintPassStructure(Pass *P);
static void PrintPassInformation(unsigned,const char*,Pass *, Value *);
static void PrintAnalysisSetInfo(unsigned,const char*,const Pass::AnalysisSet&);
#endif
};
//===----------------------------------------------------------------------===//
// Declare the PassManagerTraits which will be specialized...
//
template<class UnitType> class PassManagerTraits; // Do not define.
//===----------------------------------------------------------------------===//
// PassManagerT - Container object for passes. The PassManagerT destructor
// deletes all passes contained inside of the PassManagerT, so you shouldn't
// delete passes manually, and all passes should be dynamically allocated.
//
template<typename UnitType>
class PassManagerT : public PassManagerTraits<UnitType>,public AnalysisResolver{
typedef typename PassManagerTraits<UnitType>::PassClass PassClass;
typedef typename PassManagerTraits<UnitType>::SubPassClass SubPassClass;
typedef typename PassManagerTraits<UnitType>::BatcherClass BatcherClass;
typedef typename PassManagerTraits<UnitType>::ParentClass ParentClass;
typedef PassManagerTraits<UnitType> Traits;
friend typename PassManagerTraits<UnitType>::PassClass;
friend typename PassManagerTraits<UnitType>::SubPassClass;
friend class PassManagerTraits<UnitType>;
std::vector<PassClass*> Passes; // List of pass's to run
// The parent of this pass manager...
const ParentClass *Parent;
// The current batcher if one is in use, or null
BatcherClass *Batcher;
// CurrentAnalyses - As the passes are being run, this map contains the
// analyses that are available to the current pass for use. This is accessed
// through the getAnalysis() function in this class and in Pass.
//
std::map<AnalysisID, Pass*> CurrentAnalyses;
public:
PassManagerT(ParentClass *Par = 0) : Parent(Par), Batcher(0) {}
~PassManagerT() {
// Delete all of the contained passes...
for (std::vector<PassClass*>::iterator I = Passes.begin(), E = Passes.end();
I != E; ++I)
delete *I;
}
// run - Run all of the queued passes on the specified module in an optimal
// way.
virtual bool runOnUnit(UnitType *M) {
bool MadeChanges = false;
closeBatcher();
CurrentAnalyses.clear();
// Output debug information...
if (Parent == 0) PMDebug::PrintPassStructure(this);
// Run all of the passes
for (unsigned i = 0, e = Passes.size(); i < e; ++i) {
PassClass *P = Passes[i];
PMDebug::PrintPassInformation(getDepth(), "Executing Pass", P, (Value*)M);
// Get information about what analyses the pass uses...
std::vector<AnalysisID> Required, Destroyed, Provided;
P->getAnalysisUsageInfo(Required, Destroyed, Provided);
PMDebug::PrintAnalysisSetInfo(getDepth(), "Required", Required);
#ifndef NDEBUG
// All Required analyses should be available to the pass as it runs!
for (Pass::AnalysisSet::iterator I = Required.begin(),
E = Required.end(); I != E; ++I) {
assert(getAnalysisOrNullUp(*I) && "Analysis used but not available!");
}
#endif
// Run the sub pass!
MadeChanges |= Traits::runPass(P, M);
PMDebug::PrintAnalysisSetInfo(getDepth(), "Destroyed", Destroyed);
PMDebug::PrintAnalysisSetInfo(getDepth(), "Provided", Provided);
// Erase all analyses in the destroyed set...
for (Pass::AnalysisSet::iterator I = Destroyed.begin(),
E = Destroyed.end(); I != E; ++I)
CurrentAnalyses.erase(*I);
// Add all analyses in the provided set...
for (Pass::AnalysisSet::iterator I = Provided.begin(),
E = Provided.end(); I != E; ++I)
CurrentAnalyses[*I] = P;
}
return MadeChanges;
}
// add - Add a pass to the queue of passes to run. This passes ownership of
// the Pass to the PassManager. When the PassManager is destroyed, the pass
// will be destroyed as well, so there is no need to delete the pass. Also,
// all passes MUST be new'd.
//
void add(PassClass *P) {
// Get information about what analyses the pass uses...
std::vector<AnalysisID> Required, Destroyed, Provided;
P->getAnalysisUsageInfo(Required, Destroyed, Provided);
// Loop over all of the analyses used by this pass,
for (std::vector<AnalysisID>::iterator I = Required.begin(),
E = Required.end(); I != E; ++I) {
if (getAnalysisOrNullDown(*I) == 0)
add(I->createPass());
}
// Tell the pass to add itself to this PassManager... the way it does so
// depends on the class of the pass, and is critical to laying out passes in
// an optimal order..
//
P->addToPassManager(this, Destroyed, Provided);
}
#ifndef NDEBUG
// dumpPassStructure - Implement the -debug-passes=PassStructure option
virtual void dumpPassStructure(unsigned Offset = 0) {
std::cerr << std::string(Offset*2, ' ') << "Pass Manager\n";
for (std::vector<PassClass*>::iterator I = Passes.begin(), E = Passes.end();
I != E; ++I)
(*I)->dumpPassStructure(Offset+1);
}
#endif
public:
Pass *getAnalysisOrNullDown(AnalysisID ID) {
std::map<AnalysisID, Pass*>::iterator I = CurrentAnalyses.find(ID);
if (I == CurrentAnalyses.end()) {
if (Batcher)
return ((AnalysisResolver*)Batcher)->getAnalysisOrNullDown(ID);
return 0;
}
return I->second;
}
Pass *getAnalysisOrNullUp(AnalysisID ID) {
std::map<AnalysisID, Pass*>::iterator I = CurrentAnalyses.find(ID);
if (I == CurrentAnalyses.end()) {
if (Parent)
return ((AnalysisResolver*)Parent)->getAnalysisOrNullUp(ID);
return 0;
}
return I->second;
}
virtual unsigned getDepth() const {
if (Parent == 0) return 0;
return 1 + ((AnalysisResolver*)Parent)->getDepth();
}
private:
// addPass - These functions are used to implement the subclass specific
// behaviors present in PassManager. Basically the add(Pass*) method ends up
// reflecting its behavior into a Pass::addToPassManager call. Subclasses of
// Pass override it specifically so that they can reflect the type
// information inherent in "this" back to the PassManager.
//
// For generic Pass subclasses (which are interprocedural passes), we simply
// add the pass to the end of the pass list and terminate any accumulation of
// MethodPasses that are present.
//
void addPass(PassClass *P, Pass::AnalysisSet &Destroyed,
Pass::AnalysisSet &Provided) {
// Providers are analysis classes which are forbidden to modify the module
// they are operating on, so they are allowed to be reordered to before the
// batcher...
//
if (Batcher && Provided.empty())
closeBatcher(); // This pass cannot be batched!
// Set the Resolver instance variable in the Pass so that it knows where to
// find this object...
//
setAnalysisResolver(P, this);
Passes.push_back(P);
// Erase all analyses in the destroyed set...
for (std::vector<AnalysisID>::iterator I = Destroyed.begin(),
E = Destroyed.end(); I != E; ++I)
CurrentAnalyses.erase(*I);
// Add all analyses in the provided set...
for (std::vector<AnalysisID>::iterator I = Provided.begin(),
E = Provided.end(); I != E; ++I)
CurrentAnalyses[*I] = P;
}
// For MethodPass subclasses, we must be sure to batch the MethodPasses
// together in a MethodPassBatcher object so that all of the analyses are run
// together a method at a time.
//
void addPass(SubPassClass *MP, Pass::AnalysisSet &Destroyed,
Pass::AnalysisSet &Provided) {
if (Batcher == 0) // If we don't have a batcher yet, make one now.
Batcher = new BatcherClass(this);
// The Batcher will queue them passes up
MP->addToPassManager(Batcher, Destroyed, Provided);
}
// closeBatcher - Terminate the batcher that is being worked on.
void closeBatcher() {
if (Batcher) {
Passes.push_back(Batcher);
Batcher = 0;
}
}
};
//===----------------------------------------------------------------------===//
// PassManagerTraits<BasicBlock> Specialization
//
// This pass manager is used to group together all of the BasicBlockPass's
// into a single unit.
//
template<> struct PassManagerTraits<BasicBlock> : public BasicBlockPass {
// PassClass - The type of passes tracked by this PassManager
typedef BasicBlockPass PassClass;
// SubPassClass - The types of classes that should be collated together
// This is impossible to match, so BasicBlock instantiations of PassManagerT
// do not collate.
//
typedef PassManagerT<Module> SubPassClass;
// BatcherClass - The type to use for collation of subtypes... This class is
// never instantiated for the PassManager<BasicBlock>, but it must be an
// instance of PassClass to typecheck.
//
typedef PassClass BatcherClass;
// ParentClass - The type of the parent PassManager...
typedef PassManagerT<Method> ParentClass;
// runPass - Specify how the pass should be run on the UnitType
static bool runPass(PassClass *P, BasicBlock *M) {
// todo, init and finalize
return P->runOnBasicBlock(M);
}
// run - Implement the Pass interface...
virtual bool runOnBasicBlock(BasicBlock *BB);
};
//===----------------------------------------------------------------------===//
// PassManagerTraits<Method> Specialization
//
// This pass manager is used to group together all of the MethodPass's
// into a single unit.
//
template<> struct PassManagerTraits<Method> : public MethodPass {
// PassClass - The type of passes tracked by this PassManager
typedef MethodPass PassClass;
// SubPassClass - The types of classes that should be collated together
typedef BasicBlockPass SubPassClass;
// BatcherClass - The type to use for collation of subtypes...
typedef PassManagerT<BasicBlock> BatcherClass;
// ParentClass - The type of the parent PassManager...
typedef PassManagerT<Module> ParentClass;
// PMType - The type of the passmanager that subclasses this class
typedef PassManagerT<Method> PMType;
// runPass - Specify how the pass should be run on the UnitType
static bool runPass(PassClass *P, Method *M) {
return P->runOnMethod(M);
}
// Implement the MethodPass interface...
virtual bool doInitialization(Module *M);
virtual bool runOnMethod(Method *M);
virtual bool doFinalization(Module *M);
};
//===----------------------------------------------------------------------===//
// PassManagerTraits<Module> Specialization
//
// This is the top level PassManager implementation that holds generic passes.
//
template<> struct PassManagerTraits<Module> : public Pass {
// PassClass - The type of passes tracked by this PassManager
typedef Pass PassClass;
// SubPassClass - The types of classes that should be collated together
typedef MethodPass SubPassClass;
// BatcherClass - The type to use for collation of subtypes...
typedef PassManagerT<Method> BatcherClass;
// ParentClass - The type of the parent PassManager...
typedef void ParentClass;
// runPass - Specify how the pass should be run on the UnitType
static bool runPass(PassClass *P, Module *M) { return P->run(M); }
// run - Implement the Pass interface...
virtual bool run(Module *M) {
return ((PassManagerT<Module>*)this)->runOnUnit(M);
}
};
//===----------------------------------------------------------------------===//
// PassManagerTraits Method Implementations
//
// PassManagerTraits<BasicBlock> Implementations
//
inline bool PassManagerTraits<BasicBlock>::runOnBasicBlock(BasicBlock *BB) {
return ((PassManagerT<BasicBlock>*)this)->runOnUnit(BB);
}
// PassManagerTraits<Method> Implementations
//
inline bool PassManagerTraits<Method>::doInitialization(Module *M) {
bool Changed = false;
for (unsigned i = 0, e = ((PMType*)this)->Passes.size(); i != e; ++i)
((PMType*)this)->Passes[i]->doInitialization(M);
return Changed;
}
inline bool PassManagerTraits<Method>::runOnMethod(Method *M) {
return ((PMType*)this)->runOnUnit(M);
}
// PassManagerTraits<Module> Implementations
//
inline bool PassManagerTraits<Method>::doFinalization(Module *M) {
bool Changed = false;
for (unsigned i = 0, e = ((PMType*)this)->Passes.size(); i != e; ++i)
((PMType*)this)->Passes[i]->doFinalization(M);
return Changed;
}
#endif