mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[PM] Split the analysis manager into a function-specific interface and
a module-specific interface. This is the first of many steps necessary to generalize the infrastructure such that we can support both a Module-to-Function and Module-to-SCC-to-Function pass manager nestings. After a *lot* of attempts that never worked and didn't even make it to a committable state, it became clear that I had gotten the layering design of analyses flat out wrong. Four days later, I think I have most of the plan for how to correct this, and I'm starting to reshape the code into it. This is just a baby step I'm afraid, but starts separating the fundamentally distinct concepts of function analysis passes and module analysis passes so that in subsequent steps we can effectively layer them, and have a consistent design for the eventual SCC layer. As part of this, I've started some interface changes to make passes more regular. The module pass accepts the module in the run method, and some of the constructor parameters are gone. I'm still working out exactly where constructor parameters vs. method parameters will be used, so I expect this to fluctuate a bit. This actually makes the invalidation less "correct" at this phase, because now function passes don't invalidate module analysis passes, but that was actually somewhat of a misfeature. It will return in a better factored form which can scale to other units of IR. The documentation has gotten less verbose and helpful. llvm-svn: 195189
This commit is contained in:
parent
d1fc028d62
commit
9f55f1934e
@ -74,20 +74,99 @@ template <typename T, typename PassT> struct PassModel : PassConcept<T> {
|
||||
PassT Pass;
|
||||
};
|
||||
|
||||
/// \brief Abstract concept of an analysis result.
|
||||
///
|
||||
/// This concept is parameterized over the IR unit that this result pertains
|
||||
/// to.
|
||||
template <typename IRUnitT> struct AnalysisResultConcept {
|
||||
virtual ~AnalysisResultConcept() {}
|
||||
virtual AnalysisResultConcept *clone() = 0;
|
||||
|
||||
/// \brief Method to try and mark a result as invalid.
|
||||
///
|
||||
/// When the outer \c AnalysisManager detects a change in some underlying
|
||||
/// unit of the IR, it will call this method on all of the results cached.
|
||||
///
|
||||
/// \returns true if the result should indeed be invalidated (the default).
|
||||
virtual bool invalidate(IRUnitT *IR) = 0;
|
||||
};
|
||||
|
||||
/// \brief Wrapper to model the analysis result concept.
|
||||
///
|
||||
/// Can wrap any type which implements a suitable invalidate member and model
|
||||
/// the AnalysisResultConcept for the AnalysisManager.
|
||||
template <typename IRUnitT, typename ResultT>
|
||||
struct AnalysisResultModel : AnalysisResultConcept<IRUnitT> {
|
||||
AnalysisResultModel(ResultT Result) : Result(llvm_move(Result)) {}
|
||||
virtual AnalysisResultModel *clone() {
|
||||
return new AnalysisResultModel(Result);
|
||||
}
|
||||
|
||||
/// \brief The model delegates to the \c ResultT method.
|
||||
virtual bool invalidate(IRUnitT *IR) { return Result.invalidate(IR); }
|
||||
|
||||
ResultT Result;
|
||||
};
|
||||
|
||||
/// \brief Abstract concept of an analysis pass.
|
||||
///
|
||||
/// This concept is parameterized over the IR unit that it can run over and
|
||||
/// produce an analysis result.
|
||||
template <typename IRUnitT> struct AnalysisPassConcept {
|
||||
virtual ~AnalysisPassConcept() {}
|
||||
virtual AnalysisPassConcept *clone() = 0;
|
||||
|
||||
/// \brief Method to run this analysis over a unit of IR.
|
||||
/// \returns The analysis result object to be queried by users, the caller
|
||||
/// takes ownership.
|
||||
virtual AnalysisResultConcept<IRUnitT> *run(IRUnitT *IR) = 0;
|
||||
};
|
||||
|
||||
/// \brief Wrapper to model the analysis pass concept.
|
||||
///
|
||||
/// Can wrap any type which implements a suitable \c run method. The method
|
||||
/// must accept the IRUnitT as an argument and produce an object which can be
|
||||
/// wrapped in a \c AnalysisResultModel.
|
||||
template <typename PassT>
|
||||
struct AnalysisPassModel : AnalysisPassConcept<typename PassT::IRUnitT> {
|
||||
AnalysisPassModel(PassT Pass) : Pass(llvm_move(Pass)) {}
|
||||
virtual AnalysisPassModel *clone() { return new AnalysisPassModel(Pass); }
|
||||
|
||||
// FIXME: Replace PassT::IRUnitT with type traits when we use C++11.
|
||||
typedef typename PassT::IRUnitT IRUnitT;
|
||||
|
||||
// FIXME: Replace PassT::Result with type traits when we use C++11.
|
||||
typedef AnalysisResultModel<IRUnitT, typename PassT::Result> ResultModelT;
|
||||
|
||||
/// \brief The model delegates to the \c PassT::run method.
|
||||
///
|
||||
/// The return is wrapped in an \c AnalysisResultModel.
|
||||
virtual ResultModelT *run(IRUnitT *IR) {
|
||||
return new ResultModelT(Pass.run(IR));
|
||||
}
|
||||
|
||||
PassT Pass;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class AnalysisManager;
|
||||
class ModuleAnalysisManager;
|
||||
|
||||
class ModulePassManager {
|
||||
public:
|
||||
ModulePassManager(Module *M, AnalysisManager *AM = 0) : M(M), AM(AM) {}
|
||||
explicit ModulePassManager(ModuleAnalysisManager *AM = 0) : AM(AM) {}
|
||||
|
||||
/// \brief Run all of the module passes in this module pass manager over
|
||||
/// a module.
|
||||
///
|
||||
/// This method should only be called for a single module as there is the
|
||||
/// expectation that the lifetime of a pass is bounded to that of a module.
|
||||
void run(Module *M);
|
||||
|
||||
template <typename ModulePassT> void addPass(ModulePassT Pass) {
|
||||
Passes.push_back(new ModulePassModel<ModulePassT>(llvm_move(Pass)));
|
||||
}
|
||||
|
||||
void run();
|
||||
|
||||
private:
|
||||
// Pull in the concept type and model template specialized for modules.
|
||||
typedef detail::PassConcept<Module *> ModulePassConcept;
|
||||
@ -96,14 +175,15 @@ private:
|
||||
ModulePassModel(PassT Pass) : detail::PassModel<Module *, PassT>(Pass) {}
|
||||
};
|
||||
|
||||
Module *M;
|
||||
AnalysisManager *AM;
|
||||
ModuleAnalysisManager *AM;
|
||||
std::vector<polymorphic_ptr<ModulePassConcept> > Passes;
|
||||
};
|
||||
|
||||
class FunctionAnalysisManager;
|
||||
|
||||
class FunctionPassManager {
|
||||
public:
|
||||
FunctionPassManager(AnalysisManager *AM = 0) : AM(AM) {}
|
||||
explicit FunctionPassManager(FunctionAnalysisManager *AM = 0) : AM(AM) {}
|
||||
|
||||
template <typename FunctionPassT> void addPass(FunctionPassT Pass) {
|
||||
Passes.push_back(new FunctionPassModel<FunctionPassT>(llvm_move(Pass)));
|
||||
@ -120,58 +200,30 @@ private:
|
||||
: detail::PassModel<Function *, PassT>(Pass) {}
|
||||
};
|
||||
|
||||
AnalysisManager *AM;
|
||||
FunctionAnalysisManager *AM;
|
||||
std::vector<polymorphic_ptr<FunctionPassConcept> > Passes;
|
||||
};
|
||||
|
||||
|
||||
/// \brief An analysis manager to coordinate and cache analyses run over
|
||||
/// a module.
|
||||
///
|
||||
/// The analysis manager is typically used by passes in a pass pipeline
|
||||
/// (consisting potentially of several individual pass managers) over a module
|
||||
/// of IR. It provides registration of available analyses, declaring
|
||||
/// requirements on support for specific analyses, running of an specific
|
||||
/// analysis over a specific unit of IR to compute an analysis result, and
|
||||
/// caching of the analysis results to reuse them across multiple passes.
|
||||
///
|
||||
/// It is the responsibility of callers to use the invalidation API to
|
||||
/// invalidate analysis results when the IR they correspond to changes. The
|
||||
/// \c ModulePassManager and \c FunctionPassManager do this automatically.
|
||||
class AnalysisManager {
|
||||
/// \brief A module analysis pass manager with lazy running and caching of
|
||||
/// results.
|
||||
class ModuleAnalysisManager {
|
||||
public:
|
||||
AnalysisManager(Module *M) : M(M) {}
|
||||
ModuleAnalysisManager() {}
|
||||
|
||||
/// \brief Get the result of an analysis pass for this module.
|
||||
///
|
||||
/// If there is not a valid cached result in the manager already, this will
|
||||
/// re-run the analysis to produce a valid result.
|
||||
///
|
||||
/// The module passed in must be the same module as the analysis manager was
|
||||
/// constructed around.
|
||||
template <typename PassT>
|
||||
const typename PassT::Result &getResult(Module *M) {
|
||||
template <typename PassT> const typename PassT::Result &getResult(Module *M) {
|
||||
LLVM_STATIC_ASSERT((is_same<typename PassT::IRUnitT, Module>::value),
|
||||
"The analysis pass must be over a Module.");
|
||||
assert(ModuleAnalysisPasses.count(PassT::ID()) &&
|
||||
"This analysis pass was not registered prior to being queried");
|
||||
|
||||
const AnalysisResultConcept<Module> &ResultConcept =
|
||||
const detail::AnalysisResultConcept<Module> &ResultConcept =
|
||||
getResultImpl(PassT::ID(), M);
|
||||
typedef AnalysisResultModel<Module, typename PassT::Result> ResultModelT;
|
||||
return static_cast<const ResultModelT &>(ResultConcept).Result;
|
||||
}
|
||||
|
||||
/// \brief Get the result of an analysis pass for a function.
|
||||
///
|
||||
/// If there is not a valid cached result in the manager already, this will
|
||||
/// re-run the analysis to produce a valid result.
|
||||
template <typename PassT>
|
||||
const typename PassT::Result &getResult(Function *F) {
|
||||
assert(FunctionAnalysisPasses.count(PassT::ID()) &&
|
||||
"This analysis pass was not registered prior to being queried");
|
||||
|
||||
const AnalysisResultConcept<Function> &ResultConcept =
|
||||
getResultImpl(PassT::ID(), F);
|
||||
typedef AnalysisResultModel<Function, typename PassT::Result> ResultModelT;
|
||||
typedef detail::AnalysisResultModel<Module, typename PassT::Result>
|
||||
ResultModelT;
|
||||
return static_cast<const ResultModelT &>(ResultConcept).Result;
|
||||
}
|
||||
|
||||
@ -182,24 +234,26 @@ public:
|
||||
/// manager. Whomever is setting up analysis passes must use this to
|
||||
/// populate
|
||||
/// the manager with all of the analysis passes available.
|
||||
template <typename PassT> void registerAnalysisPass(PassT Pass) {
|
||||
registerAnalysisPassImpl<PassT>(llvm_move(Pass));
|
||||
template <typename PassT> void registerPass(PassT Pass) {
|
||||
LLVM_STATIC_ASSERT((is_same<typename PassT::IRUnitT, Module>::value),
|
||||
"The analysis pass must be over a Module.");
|
||||
assert(!ModuleAnalysisPasses.count(PassT::ID()) &&
|
||||
"Registered the same analysis pass twice!");
|
||||
ModuleAnalysisPasses[PassT::ID()] =
|
||||
new detail::AnalysisPassModel<PassT>(llvm_move(Pass));
|
||||
}
|
||||
|
||||
/// \brief Invalidate a specific analysis pass for an IR module.
|
||||
///
|
||||
/// Note that the analysis result can disregard invalidation.
|
||||
template <typename PassT> void invalidate(Module *M) {
|
||||
LLVM_STATIC_ASSERT((is_same<typename PassT::IRUnitT, Module>::value),
|
||||
"The analysis pass must be over a Module.");
|
||||
assert(ModuleAnalysisPasses.count(PassT::ID()) &&
|
||||
"This analysis pass was not registered prior to being invalidated");
|
||||
invalidateImpl(PassT::ID(), M);
|
||||
}
|
||||
|
||||
/// \brief Invalidate a specific analysis pass for an IR function.
|
||||
///
|
||||
/// Note that the analysis result can disregard invalidation.
|
||||
template <typename PassT> void invalidate(Function *F) {
|
||||
invalidateImpl(PassT::ID(), F);
|
||||
}
|
||||
|
||||
/// \brief Invalidate analyses cached for an IR Module.
|
||||
///
|
||||
/// Note that specific analysis results can disregard invalidation by
|
||||
@ -209,6 +263,82 @@ public:
|
||||
/// around.
|
||||
void invalidateAll(Module *M);
|
||||
|
||||
private:
|
||||
/// \brief Get a module pass result, running the pass if necessary.
|
||||
const detail::AnalysisResultConcept<Module> &getResultImpl(void *PassID,
|
||||
Module *M);
|
||||
|
||||
/// \brief Invalidate a module pass result.
|
||||
void invalidateImpl(void *PassID, Module *M);
|
||||
|
||||
/// \brief Map type from module analysis pass ID to pass concept pointer.
|
||||
typedef DenseMap<void *,
|
||||
polymorphic_ptr<detail::AnalysisPassConcept<Module> > >
|
||||
ModuleAnalysisPassMapT;
|
||||
|
||||
/// \brief Collection of module analysis passes, indexed by ID.
|
||||
ModuleAnalysisPassMapT ModuleAnalysisPasses;
|
||||
|
||||
/// \brief Map type from module analysis pass ID to pass result concept pointer.
|
||||
typedef DenseMap<void *,
|
||||
polymorphic_ptr<detail::AnalysisResultConcept<Module> > >
|
||||
ModuleAnalysisResultMapT;
|
||||
|
||||
/// \brief Cache of computed module analysis results for this module.
|
||||
ModuleAnalysisResultMapT ModuleAnalysisResults;
|
||||
};
|
||||
|
||||
/// \brief A function analysis manager to coordinate and cache analyses run over
|
||||
/// a module.
|
||||
class FunctionAnalysisManager {
|
||||
public:
|
||||
FunctionAnalysisManager() {}
|
||||
|
||||
/// \brief Get the result of an analysis pass for a function.
|
||||
///
|
||||
/// If there is not a valid cached result in the manager already, this will
|
||||
/// re-run the analysis to produce a valid result.
|
||||
template <typename PassT>
|
||||
const typename PassT::Result &getResult(Function *F) {
|
||||
LLVM_STATIC_ASSERT((is_same<typename PassT::IRUnitT, Function>::value),
|
||||
"The analysis pass must be over a Function.");
|
||||
assert(FunctionAnalysisPasses.count(PassT::ID()) &&
|
||||
"This analysis pass was not registered prior to being queried");
|
||||
|
||||
const detail::AnalysisResultConcept<Function> &ResultConcept =
|
||||
getResultImpl(PassT::ID(), F);
|
||||
typedef detail::AnalysisResultModel<Function, typename PassT::Result>
|
||||
ResultModelT;
|
||||
return static_cast<const ResultModelT &>(ResultConcept).Result;
|
||||
}
|
||||
|
||||
/// \brief Register an analysis pass with the manager.
|
||||
///
|
||||
/// This provides an initialized and set-up analysis pass to the
|
||||
/// analysis
|
||||
/// manager. Whomever is setting up analysis passes must use this to
|
||||
/// populate
|
||||
/// the manager with all of the analysis passes available.
|
||||
template <typename PassT> void registerPass(PassT Pass) {
|
||||
LLVM_STATIC_ASSERT((is_same<typename PassT::IRUnitT, Function>::value),
|
||||
"The analysis pass must be over a Function.");
|
||||
assert(!FunctionAnalysisPasses.count(PassT::ID()) &&
|
||||
"Registered the same analysis pass twice!");
|
||||
FunctionAnalysisPasses[PassT::ID()] =
|
||||
new detail::AnalysisPassModel<PassT>(llvm_move(Pass));
|
||||
}
|
||||
|
||||
/// \brief Invalidate a specific analysis pass for an IR module.
|
||||
///
|
||||
/// Note that the analysis result can disregard invalidation.
|
||||
template <typename PassT> void invalidate(Function *F) {
|
||||
LLVM_STATIC_ASSERT((is_same<typename PassT::IRUnitT, Function>::value),
|
||||
"The analysis pass must be over a Function.");
|
||||
assert(FunctionAnalysisPasses.count(PassT::ID()) &&
|
||||
"This analysis pass was not registered prior to being invalidated");
|
||||
invalidateImpl(PassT::ID(), F);
|
||||
}
|
||||
|
||||
/// \brief Invalidate analyses cached for an IR Function.
|
||||
///
|
||||
/// Note that specific analysis results can disregard invalidation by
|
||||
@ -216,134 +346,17 @@ public:
|
||||
void invalidateAll(Function *F);
|
||||
|
||||
private:
|
||||
/// \brief Abstract concept of an analysis result.
|
||||
///
|
||||
/// This concept is parameterized over the IR unit that this result pertains
|
||||
/// to.
|
||||
template <typename IRUnitT> struct AnalysisResultConcept {
|
||||
virtual ~AnalysisResultConcept() {}
|
||||
virtual AnalysisResultConcept *clone() = 0;
|
||||
|
||||
/// \brief Method to try and mark a result as invalid.
|
||||
///
|
||||
/// When the outer \c AnalysisManager detects a change in some underlying
|
||||
/// unit of the IR, it will call this method on all of the results cached.
|
||||
///
|
||||
/// \returns true if the result should indeed be invalidated (the default).
|
||||
virtual bool invalidate(IRUnitT *IR) = 0;
|
||||
};
|
||||
|
||||
/// \brief Wrapper to model the analysis result concept.
|
||||
///
|
||||
/// Can wrap any type which implements a suitable invalidate member and model
|
||||
/// the AnalysisResultConcept for the AnalysisManager.
|
||||
template <typename IRUnitT, typename ResultT>
|
||||
struct AnalysisResultModel : AnalysisResultConcept<IRUnitT> {
|
||||
AnalysisResultModel(ResultT Result) : Result(llvm_move(Result)) {}
|
||||
virtual AnalysisResultModel *clone() {
|
||||
return new AnalysisResultModel(Result);
|
||||
}
|
||||
|
||||
/// \brief The model delegates to the \c ResultT method.
|
||||
virtual bool invalidate(IRUnitT *IR) { return Result.invalidate(IR); }
|
||||
|
||||
ResultT Result;
|
||||
};
|
||||
|
||||
/// \brief Abstract concept of an analysis pass.
|
||||
///
|
||||
/// This concept is parameterized over the IR unit that it can run over and
|
||||
/// produce an analysis result.
|
||||
template <typename IRUnitT> struct AnalysisPassConcept {
|
||||
virtual ~AnalysisPassConcept() {}
|
||||
virtual AnalysisPassConcept *clone() = 0;
|
||||
|
||||
/// \brief Method to run this analysis over a unit of IR.
|
||||
/// \returns The analysis result object to be queried by users, the caller
|
||||
/// takes ownership.
|
||||
virtual AnalysisResultConcept<IRUnitT> *run(IRUnitT *IR) = 0;
|
||||
};
|
||||
|
||||
/// \brief Wrapper to model the analysis pass concept.
|
||||
///
|
||||
/// Can wrap any type which implements a suitable \c run method. The method
|
||||
/// must accept the IRUnitT as an argument and produce an object which can be
|
||||
/// wrapped in a \c AnalysisResultModel.
|
||||
template <typename PassT>
|
||||
struct AnalysisPassModel : AnalysisPassConcept<typename PassT::IRUnitT> {
|
||||
AnalysisPassModel(PassT Pass) : Pass(llvm_move(Pass)) {}
|
||||
virtual AnalysisPassModel *clone() { return new AnalysisPassModel(Pass); }
|
||||
|
||||
// FIXME: Replace PassT::IRUnitT with type traits when we use C++11.
|
||||
typedef typename PassT::IRUnitT IRUnitT;
|
||||
|
||||
// FIXME: Replace PassT::Result with type traits when we use C++11.
|
||||
typedef AnalysisResultModel<IRUnitT, typename PassT::Result> ResultModelT;
|
||||
|
||||
/// \brief The model delegates to the \c PassT::run method.
|
||||
///
|
||||
/// The return is wrapped in an \c AnalysisResultModel.
|
||||
virtual ResultModelT *run(IRUnitT *IR) {
|
||||
return new ResultModelT(Pass.run(IR));
|
||||
}
|
||||
|
||||
PassT Pass;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Get a module pass result, running the pass if necessary.
|
||||
const AnalysisResultConcept<Module> &getResultImpl(void *PassID, Module *M);
|
||||
|
||||
/// \brief Get a function pass result, running the pass if necessary.
|
||||
const AnalysisResultConcept<Function> &getResultImpl(void *PassID,
|
||||
Function *F);
|
||||
|
||||
/// \brief Invalidate a module pass result.
|
||||
void invalidateImpl(void *PassID, Module *M);
|
||||
const detail::AnalysisResultConcept<Function> &getResultImpl(void *PassID,
|
||||
Function *F);
|
||||
|
||||
/// \brief Invalidate a function pass result.
|
||||
void invalidateImpl(void *PassID, Function *F);
|
||||
|
||||
|
||||
/// \brief Module pass specific implementation of registration.
|
||||
template <typename PassT>
|
||||
typename enable_if<is_same<typename PassT::IRUnitT, Module> >::type
|
||||
registerAnalysisPassImpl(PassT Pass) {
|
||||
assert(!ModuleAnalysisPasses.count(PassT::ID()) &&
|
||||
"Registered the same analysis pass twice!");
|
||||
ModuleAnalysisPasses[PassT::ID()] =
|
||||
new AnalysisPassModel<PassT>(llvm_move(Pass));
|
||||
}
|
||||
|
||||
/// \brief Function pass specific implementation of registration.
|
||||
template <typename PassT>
|
||||
typename enable_if<is_same<typename PassT::IRUnitT, Function> >::type
|
||||
registerAnalysisPassImpl(PassT Pass) {
|
||||
assert(!FunctionAnalysisPasses.count(PassT::ID()) &&
|
||||
"Registered the same analysis pass twice!");
|
||||
FunctionAnalysisPasses[PassT::ID()] =
|
||||
new AnalysisPassModel<PassT>(llvm_move(Pass));
|
||||
}
|
||||
|
||||
|
||||
/// \brief Map type from module analysis pass ID to pass concept pointer.
|
||||
typedef DenseMap<void *, polymorphic_ptr<AnalysisPassConcept<Module> > >
|
||||
ModuleAnalysisPassMapT;
|
||||
|
||||
/// \brief Collection of module analysis passes, indexed by ID.
|
||||
ModuleAnalysisPassMapT ModuleAnalysisPasses;
|
||||
|
||||
/// \brief Map type from module analysis pass ID to pass result concept pointer.
|
||||
typedef DenseMap<void *, polymorphic_ptr<AnalysisResultConcept<Module> > >
|
||||
ModuleAnalysisResultMapT;
|
||||
|
||||
/// \brief Cache of computed module analysis results for this module.
|
||||
ModuleAnalysisResultMapT ModuleAnalysisResults;
|
||||
|
||||
|
||||
/// \brief Map type from function analysis pass ID to pass concept pointer.
|
||||
typedef DenseMap<void *, polymorphic_ptr<AnalysisPassConcept<Function> > >
|
||||
FunctionAnalysisPassMapT;
|
||||
typedef DenseMap<void *,
|
||||
polymorphic_ptr<detail::AnalysisPassConcept<Function> > >
|
||||
FunctionAnalysisPassMapT;
|
||||
|
||||
/// \brief Collection of function analysis passes, indexed by ID.
|
||||
FunctionAnalysisPassMapT FunctionAnalysisPasses;
|
||||
@ -353,12 +366,13 @@ private:
|
||||
/// Requires iterators to be valid across appending new entries and arbitrary
|
||||
/// erases. Provides both the pass ID and concept pointer such that it is
|
||||
/// half of a bijection and provides storage for the actual result concept.
|
||||
typedef std::list<
|
||||
std::pair<void *, polymorphic_ptr<AnalysisResultConcept<Function> > > >
|
||||
FunctionAnalysisResultListT;
|
||||
typedef std::list<std::pair<
|
||||
void *, polymorphic_ptr<detail::AnalysisResultConcept<Function> > > >
|
||||
FunctionAnalysisResultListT;
|
||||
|
||||
/// \brief Map type from function pointer to our custom list type.
|
||||
typedef DenseMap<Function *, FunctionAnalysisResultListT> FunctionAnalysisResultListMapT;
|
||||
typedef DenseMap<Function *, FunctionAnalysisResultListT>
|
||||
FunctionAnalysisResultListMapT;
|
||||
|
||||
/// \brief Map from function to a list of function analysis results.
|
||||
///
|
||||
@ -370,14 +384,11 @@ private:
|
||||
/// iterator into a particular result list.
|
||||
typedef DenseMap<std::pair<void *, Function *>,
|
||||
FunctionAnalysisResultListT::iterator>
|
||||
FunctionAnalysisResultMapT;
|
||||
FunctionAnalysisResultMapT;
|
||||
|
||||
/// \brief Map from an analysis ID and function to a particular cached
|
||||
/// analysis result.
|
||||
FunctionAnalysisResultMapT FunctionAnalysisResults;
|
||||
|
||||
/// \brief Module handle for the \c AnalysisManager.
|
||||
Module *M;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -12,10 +12,45 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void ModulePassManager::run() {
|
||||
void ModulePassManager::run(Module *M) {
|
||||
for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx)
|
||||
if (Passes[Idx]->run(M))
|
||||
if (AM) AM->invalidateAll(M);
|
||||
if (AM)
|
||||
AM->invalidateAll(M);
|
||||
}
|
||||
|
||||
void ModuleAnalysisManager::invalidateAll(Module *M) {
|
||||
// FIXME: This is a total hack based on the fact that erasure doesn't
|
||||
// invalidate iteration for DenseMap.
|
||||
for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(),
|
||||
E = ModuleAnalysisResults.end();
|
||||
I != E; ++I)
|
||||
if (I->second->invalidate(M))
|
||||
ModuleAnalysisResults.erase(I);
|
||||
}
|
||||
|
||||
const detail::AnalysisResultConcept<Module> &
|
||||
ModuleAnalysisManager::getResultImpl(void *PassID, Module *M) {
|
||||
ModuleAnalysisResultMapT::iterator RI;
|
||||
bool Inserted;
|
||||
llvm::tie(RI, Inserted) = ModuleAnalysisResults.insert(std::make_pair(
|
||||
PassID, polymorphic_ptr<detail::AnalysisResultConcept<Module> >()));
|
||||
|
||||
if (Inserted) {
|
||||
// We don't have a cached result for this result. Look up the pass and run
|
||||
// it to produce a result, which we then add to the cache.
|
||||
ModuleAnalysisPassMapT::const_iterator PI =
|
||||
ModuleAnalysisPasses.find(PassID);
|
||||
assert(PI != ModuleAnalysisPasses.end() &&
|
||||
"Analysis passes must be registered prior to being queried!");
|
||||
RI->second = PI->second->run(M);
|
||||
}
|
||||
|
||||
return *RI->second;
|
||||
}
|
||||
|
||||
void ModuleAnalysisManager::invalidateImpl(void *PassID, Module *M) {
|
||||
ModuleAnalysisResults.erase(PassID);
|
||||
}
|
||||
|
||||
bool FunctionPassManager::run(Module *M) {
|
||||
@ -24,24 +59,14 @@ bool FunctionPassManager::run(Module *M) {
|
||||
for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx)
|
||||
if (Passes[Idx]->run(I)) {
|
||||
Changed = true;
|
||||
if (AM) AM->invalidateAll(I);
|
||||
if (AM)
|
||||
AM->invalidateAll(I);
|
||||
}
|
||||
return Changed;
|
||||
}
|
||||
|
||||
void AnalysisManager::invalidateAll(Function *F) {
|
||||
assert(F->getParent() == M && "Invalidating a function from another module!");
|
||||
|
||||
// First invalidate any module results we still have laying about.
|
||||
// FIXME: This is a total hack based on the fact that erasure doesn't
|
||||
// invalidate iteration for DenseMap.
|
||||
for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(),
|
||||
E = ModuleAnalysisResults.end();
|
||||
I != E; ++I)
|
||||
if (I->second->invalidate(M))
|
||||
ModuleAnalysisResults.erase(I);
|
||||
|
||||
// Now clear all the invalidated results associated specifically with this
|
||||
void FunctionAnalysisManager::invalidateAll(Function *F) {
|
||||
// Clear all the invalidated results associated specifically with this
|
||||
// function.
|
||||
SmallVector<void *, 8> InvalidatedPassIDs;
|
||||
FunctionAnalysisResultListT &ResultsList = FunctionAnalysisResultLists[F];
|
||||
@ -59,66 +84,8 @@ void AnalysisManager::invalidateAll(Function *F) {
|
||||
std::make_pair(InvalidatedPassIDs.pop_back_val(), F));
|
||||
}
|
||||
|
||||
void AnalysisManager::invalidateAll(Module *M) {
|
||||
// First invalidate any module results we still have laying about.
|
||||
// FIXME: This is a total hack based on the fact that erasure doesn't
|
||||
// invalidate iteration for DenseMap.
|
||||
for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(),
|
||||
E = ModuleAnalysisResults.end();
|
||||
I != E; ++I)
|
||||
if (I->second->invalidate(M))
|
||||
ModuleAnalysisResults.erase(I);
|
||||
|
||||
// Now walk all of the functions for which there are cached results, and
|
||||
// attempt to invalidate each of those as the entire module may have changed.
|
||||
// FIXME: How do we handle functions which have been deleted or RAUWed?
|
||||
SmallVector<void *, 8> InvalidatedPassIDs;
|
||||
for (FunctionAnalysisResultListMapT::iterator
|
||||
FI = FunctionAnalysisResultLists.begin(),
|
||||
FE = FunctionAnalysisResultLists.end();
|
||||
FI != FE; ++FI) {
|
||||
Function *F = FI->first;
|
||||
FunctionAnalysisResultListT &ResultsList = FI->second;
|
||||
for (FunctionAnalysisResultListT::iterator I = ResultsList.begin(),
|
||||
E = ResultsList.end();
|
||||
I != E;)
|
||||
if (I->second->invalidate(F)) {
|
||||
InvalidatedPassIDs.push_back(I->first);
|
||||
I = ResultsList.erase(I);
|
||||
} else {
|
||||
++I;
|
||||
}
|
||||
while (!InvalidatedPassIDs.empty())
|
||||
FunctionAnalysisResults.erase(
|
||||
std::make_pair(InvalidatedPassIDs.pop_back_val(), F));
|
||||
}
|
||||
}
|
||||
|
||||
const AnalysisManager::AnalysisResultConcept<Module> &
|
||||
AnalysisManager::getResultImpl(void *PassID, Module *M) {
|
||||
assert(M == this->M && "Wrong module used when querying the AnalysisManager");
|
||||
ModuleAnalysisResultMapT::iterator RI;
|
||||
bool Inserted;
|
||||
llvm::tie(RI, Inserted) = ModuleAnalysisResults.insert(std::make_pair(
|
||||
PassID, polymorphic_ptr<AnalysisResultConcept<Module> >()));
|
||||
|
||||
if (Inserted) {
|
||||
// We don't have a cached result for this result. Look up the pass and run
|
||||
// it to produce a result, which we then add to the cache.
|
||||
ModuleAnalysisPassMapT::const_iterator PI =
|
||||
ModuleAnalysisPasses.find(PassID);
|
||||
assert(PI != ModuleAnalysisPasses.end() &&
|
||||
"Analysis passes must be registered prior to being queried!");
|
||||
RI->second = PI->second->run(M);
|
||||
}
|
||||
|
||||
return *RI->second;
|
||||
}
|
||||
|
||||
const AnalysisManager::AnalysisResultConcept<Function> &
|
||||
AnalysisManager::getResultImpl(void *PassID, Function *F) {
|
||||
assert(F->getParent() == M && "Analyzing a function from another module!");
|
||||
|
||||
const detail::AnalysisResultConcept<Function> &
|
||||
FunctionAnalysisManager::getResultImpl(void *PassID, Function *F) {
|
||||
FunctionAnalysisResultMapT::iterator RI;
|
||||
bool Inserted;
|
||||
llvm::tie(RI, Inserted) = FunctionAnalysisResults.insert(std::make_pair(
|
||||
@ -139,15 +106,7 @@ AnalysisManager::getResultImpl(void *PassID, Function *F) {
|
||||
return *RI->second->second;
|
||||
}
|
||||
|
||||
void AnalysisManager::invalidateImpl(void *PassID, Module *M) {
|
||||
assert(M == this->M && "Invalidating a pass over a different module!");
|
||||
ModuleAnalysisResults.erase(PassID);
|
||||
}
|
||||
|
||||
void AnalysisManager::invalidateImpl(void *PassID, Function *F) {
|
||||
assert(F->getParent() == M &&
|
||||
"Invalidating a pass over a function from another module!");
|
||||
|
||||
void FunctionAnalysisManager::invalidateImpl(void *PassID, Function *F) {
|
||||
FunctionAnalysisResultMapT::iterator RI =
|
||||
FunctionAnalysisResults.find(std::make_pair(PassID, F));
|
||||
if (RI == FunctionAnalysisResults.end())
|
||||
|
@ -61,9 +61,9 @@ struct TestModulePass {
|
||||
};
|
||||
|
||||
struct TestFunctionPass {
|
||||
TestFunctionPass(AnalysisManager &AM, int &RunCount, int &AnalyzedInstrCount)
|
||||
: AM(AM), RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) {
|
||||
}
|
||||
TestFunctionPass(FunctionAnalysisManager &AM, int &RunCount,
|
||||
int &AnalyzedInstrCount)
|
||||
: AM(AM), RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) {}
|
||||
|
||||
bool run(Function *F) {
|
||||
++RunCount;
|
||||
@ -74,7 +74,7 @@ struct TestFunctionPass {
|
||||
return true;
|
||||
}
|
||||
|
||||
AnalysisManager &AM;
|
||||
FunctionAnalysisManager &AM;
|
||||
int &RunCount;
|
||||
int &AnalyzedInstrCount;
|
||||
};
|
||||
@ -106,10 +106,10 @@ public:
|
||||
};
|
||||
|
||||
TEST_F(PassManagerTest, Basic) {
|
||||
AnalysisManager AM(M.get());
|
||||
AM.registerAnalysisPass(TestAnalysisPass());
|
||||
FunctionAnalysisManager AM;
|
||||
AM.registerPass(TestAnalysisPass());
|
||||
|
||||
ModulePassManager MPM(M.get(), &AM);
|
||||
ModulePassManager MPM;
|
||||
FunctionPassManager FPM(&AM);
|
||||
|
||||
// Count the runs over a module.
|
||||
@ -122,10 +122,9 @@ TEST_F(PassManagerTest, Basic) {
|
||||
FPM.addPass(TestFunctionPass(AM, FunctionPassRunCount, AnalyzedInstrCount));
|
||||
MPM.addPass(FPM);
|
||||
|
||||
MPM.run();
|
||||
MPM.run(M.get());
|
||||
EXPECT_EQ(1, ModulePassRunCount);
|
||||
EXPECT_EQ(3, FunctionPassRunCount);
|
||||
EXPECT_EQ(5, AnalyzedInstrCount);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user