mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-12 13:30:51 +00:00
Implement a more powerful, simpler, pass system. This pass system can figure
out how to run a collection of passes optimially given their behaviors and charactaristics. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@1506 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
f2a1dbc1e3
commit
aff5bcebb7
@ -3,30 +3,15 @@
|
||||
// This file defines a base class that indicates that a specified class is a
|
||||
// transformation pass implementation.
|
||||
//
|
||||
// Pass's are designed this way so that it is possible to apply N passes to a
|
||||
// module, by first doing N Pass specific initializations for the module, then
|
||||
// looping over all of the methods in the module, doing method specific work
|
||||
// N times for each method. Like this:
|
||||
// Pass's are designed this way so that it is possible to run passes in a cache
|
||||
// and organizationally optimal order without having to specify it at the front
|
||||
// end. This allows arbitrary passes to be strung together and have them
|
||||
// executed as effeciently as possible.
|
||||
//
|
||||
// for_each(Passes.begin(), Passes.end(), doPassInitialization(Module));
|
||||
// for_each(Method *M <- Module->begin(), Module->end())
|
||||
// for_each(Passes.begin(), Passes.end(), doPerMethodWork(M));
|
||||
//
|
||||
// The other way to do things is like this:
|
||||
// for_each(Pass *P <- Passes.begin(), Passes.end()) {
|
||||
// Passes->doPassInitialization(Module)
|
||||
// for_each(Module->begin(), Module->end(), P->doPerMethodWork);
|
||||
// }
|
||||
//
|
||||
// But this can cause thrashing and poor cache performance, so we don't do it
|
||||
// that way.
|
||||
//
|
||||
// Because a transformation does not see all methods consecutively, it should
|
||||
// be careful about the state that it maintains... another pass may modify a
|
||||
// method between two invocatations of doPerMethodWork.
|
||||
//
|
||||
// Also, implementations of doMethodWork should not remove any methods from the
|
||||
// module.
|
||||
// Passes should extend one of the classes below, depending on the guarantees
|
||||
// that it can make about what will be modified as it is run. For example, most
|
||||
// global optimizations should derive from MethodPass, because they do not add
|
||||
// or delete methods, they operate on the internals of the method.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -36,91 +21,137 @@
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Method.h"
|
||||
|
||||
class MethodPassBatcher;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pass interface - Implemented by all 'passes'.
|
||||
// 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 {
|
||||
//===--------------------------------------------------------------------===//
|
||||
// The externally useful entry points
|
||||
//
|
||||
|
||||
// runAllPasses - Run a bunch of passes on the specified module, efficiently.
|
||||
static bool runAllPasses(Module *M, std::vector<Pass*> &Passes) {
|
||||
bool MadeChanges = false;
|
||||
// Run all of the pass initializers
|
||||
for (unsigned i = 0; i < Passes.size(); ++i)
|
||||
MadeChanges |= Passes[i]->doPassInitialization(M);
|
||||
|
||||
// Loop over all of the methods, applying all of the passes to them
|
||||
for (unsigned m = 0; m < M->size(); ++m)
|
||||
for (unsigned i = 0; i < Passes.size(); ++i)
|
||||
MadeChanges |= Passes[i]->doPerMethodWork(*(M->begin()+m));
|
||||
|
||||
// Run all of the pass finalizers...
|
||||
for (unsigned i = 0; i < Passes.size(); ++i)
|
||||
MadeChanges |= Passes[i]->doPassFinalization(M);
|
||||
return MadeChanges;
|
||||
}
|
||||
|
||||
// runAllPassesAndFree - Run a bunch of passes on the specified module,
|
||||
// efficiently. When done, delete all of the passes.
|
||||
//
|
||||
static bool runAllPassesAndFree(Module *M, std::vector<Pass*> &Passes) {
|
||||
// First run all of the passes
|
||||
bool MadeChanges = runAllPasses(M, Passes);
|
||||
|
||||
// Free all of the passes.
|
||||
for (unsigned i = 0; i < Passes.size(); ++i)
|
||||
delete Passes[i];
|
||||
return MadeChanges;
|
||||
}
|
||||
|
||||
|
||||
// run(Module*) - Run this pass on a module and all of the methods contained
|
||||
// within it. Returns true if any of the contained passes returned true.
|
||||
//
|
||||
bool run(Module *M) {
|
||||
bool MadeChanges = doPassInitialization(M);
|
||||
|
||||
// Loop over methods in the module. doPerMethodWork could add a method to
|
||||
// the Module, so we have to keep checking for end of method list condition.
|
||||
//
|
||||
for (unsigned m = 0; m < M->size(); ++m)
|
||||
MadeChanges |= doPerMethodWork(*(M->begin()+m));
|
||||
return MadeChanges | doPassFinalization(M);
|
||||
}
|
||||
|
||||
// run(Method*) - Run this pass on a module and one specific method. Returns
|
||||
// false on success.
|
||||
//
|
||||
bool run(Method *M) {
|
||||
return doPassInitialization(M->getParent()) | doPerMethodWork(M) |
|
||||
doPassFinalization(M->getParent());
|
||||
}
|
||||
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Functions to be implemented by subclasses
|
||||
//
|
||||
|
||||
// Destructor - Virtual so we can be subclassed
|
||||
inline virtual ~Pass() {}
|
||||
|
||||
// doPassInitialization - Virtual method overridden by subclasses to do
|
||||
virtual bool run(Module *M) = 0;
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MethodPass class - This class is used to implement most global optimizations.
|
||||
// Optimizations should subclass this class if they meet the following
|
||||
// constraints:
|
||||
// 1. Optimizations are organized globally, ie a method at a time
|
||||
// 2. Optimizing a method does not cause the addition or removal of any methods
|
||||
// in the module
|
||||
//
|
||||
struct MethodPass : public Pass {
|
||||
// doInitialization - Virtual method overridden by subclasses to do
|
||||
// any neccesary per-module initialization.
|
||||
//
|
||||
virtual bool doPassInitialization(Module *M) { return false; }
|
||||
virtual bool doInitialization(Module *M) { return false; }
|
||||
|
||||
// doPerMethodWork - Virtual method overriden by subclasses to do the
|
||||
// per-method processing of the pass.
|
||||
// runOnMethod - Virtual method overriden by subclasses to do the per-method
|
||||
// processing of the pass.
|
||||
//
|
||||
virtual bool doPerMethodWork(Method *M) { return false; }
|
||||
virtual bool runOnMethod(Method *M) = 0;
|
||||
|
||||
// doPassFinalization - Virtual method overriden by subclasses to do any post
|
||||
// doFinalization - Virtual method overriden by subclasses to do any post
|
||||
// processing needed after all passes have run.
|
||||
//
|
||||
virtual bool doPassFinalization(Module *M) { return false; }
|
||||
virtual bool doFinalization(Module *M) { return false; }
|
||||
|
||||
|
||||
virtual bool run(Module *M) {
|
||||
bool Changed = doInitialization(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());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
// meet the following constraints:
|
||||
// 1. Optimizations are local, operating on either a basic block or
|
||||
// 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.
|
||||
//
|
||||
struct BasicBlockPass : public CFGSafeMethodPass {
|
||||
// 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;
|
||||
}
|
||||
|
||||
bool run(BasicBlock *BB) {
|
||||
Module *M = BB->getParent()->getParent();
|
||||
return doInitialization(M) | runOnBasicBlock(BB) | doFinalization(M);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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.
|
||||
//
|
||||
class PassManager {
|
||||
std::vector<Pass*> Passes;
|
||||
MethodPassBatcher *Batcher;
|
||||
public:
|
||||
PassManager() : Batcher(0) {}
|
||||
~PassManager();
|
||||
|
||||
bool run(Module *M) {
|
||||
bool MadeChanges = false;
|
||||
// Run all of the pass initializers
|
||||
for (unsigned i = 0, e = Passes.size(); i < e; ++i)
|
||||
MadeChanges |= Passes[i]->run(M);
|
||||
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(Pass *P);
|
||||
void add(MethodPass *P);
|
||||
void add(BasicBlockPass *P);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user