mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-14 21:51:19 +00:00

manager. This starts to allow us to test analyses more easily, but it's really only the beginning. Some of the code here is still untestable without manual changes to create analysis passes, but I wanted to factor it into a small of chunks as possible. Next up in order to be able to test things are, in no particular order: - No-op analyses passes so we don't have to use real ones to exercise the pass maneger itself. - Automatic way of generating dummy passes that require an analysis be run, including a variant that calls a 'print' method on a pass to make it even easier to print out the results of an analysis. - Dummy passes that invalidate all analyses for their IR unit so we can test invalidation and re-runs. - Automatic way to print each analysis pass as it is re-run. - Automatic but optional verification of analysis passes everywhere possible. I'm not claiming I'll get to all of these immediately, but that's what is in the pipeline at some stage. I'm fleshing out exactly what I need and what to prioritize by working on converting analyses and then trying to test the conversion. =] llvm-svn: 225162
235 lines
7.8 KiB
C++
235 lines
7.8 KiB
C++
//===- PassManager.cpp - Infrastructure for managing & running IR passes --===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/PassManager.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
using namespace llvm;
|
|
|
|
static cl::opt<bool>
|
|
DebugPM("debug-pass-manager", cl::Hidden,
|
|
cl::desc("Print pass management debugging information"));
|
|
|
|
PreservedAnalyses ModulePassManager::run(Module &M, ModuleAnalysisManager *AM) {
|
|
PreservedAnalyses PA = PreservedAnalyses::all();
|
|
|
|
if (DebugPM)
|
|
dbgs() << "Starting module pass manager run.\n";
|
|
|
|
for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) {
|
|
if (DebugPM)
|
|
dbgs() << "Running module pass: " << Passes[Idx]->name() << "\n";
|
|
|
|
PreservedAnalyses PassPA = Passes[Idx]->run(M, AM);
|
|
if (AM)
|
|
AM->invalidate(M, PassPA);
|
|
PA.intersect(std::move(PassPA));
|
|
|
|
M.getContext().yield();
|
|
}
|
|
|
|
if (DebugPM)
|
|
dbgs() << "Finished module pass manager run.\n";
|
|
|
|
return PA;
|
|
}
|
|
|
|
ModuleAnalysisManager::ResultConceptT &
|
|
ModuleAnalysisManager::getResultImpl(void *PassID, Module &M) {
|
|
ModuleAnalysisResultMapT::iterator RI;
|
|
bool Inserted;
|
|
std::tie(RI, Inserted) = ModuleAnalysisResults.insert(std::make_pair(
|
|
PassID, std::unique_ptr<detail::AnalysisResultConcept<Module &>>()));
|
|
|
|
// If we don't have a cached result for this module, look up the pass and run
|
|
// it to produce a result, which we then add to the cache.
|
|
if (Inserted) {
|
|
auto &P = lookupPass(PassID);
|
|
if (DebugPM)
|
|
dbgs() << "Running module analysis: " << P.name() << "\n";
|
|
RI->second = P.run(M, this);
|
|
}
|
|
|
|
return *RI->second;
|
|
}
|
|
|
|
ModuleAnalysisManager::ResultConceptT *
|
|
ModuleAnalysisManager::getCachedResultImpl(void *PassID, Module &M) const {
|
|
ModuleAnalysisResultMapT::const_iterator RI =
|
|
ModuleAnalysisResults.find(PassID);
|
|
return RI == ModuleAnalysisResults.end() ? nullptr : &*RI->second;
|
|
}
|
|
|
|
void ModuleAnalysisManager::invalidateImpl(void *PassID, Module &M) {
|
|
if (DebugPM)
|
|
dbgs() << "Invalidating module analysis: " << lookupPass(PassID).name()
|
|
<< "\n";
|
|
ModuleAnalysisResults.erase(PassID);
|
|
}
|
|
|
|
void ModuleAnalysisManager::invalidateImpl(Module &M,
|
|
const PreservedAnalyses &PA) {
|
|
if (DebugPM)
|
|
dbgs() << "Invalidating all non-preserved analyses for module: "
|
|
<< M.getModuleIdentifier() << "\n";
|
|
|
|
// 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, PA)) {
|
|
if (DebugPM)
|
|
dbgs() << "Invalidating module analysis: "
|
|
<< lookupPass(I->first).name() << "\n";
|
|
|
|
ModuleAnalysisResults.erase(I);
|
|
}
|
|
}
|
|
|
|
PreservedAnalyses FunctionPassManager::run(Function &F,
|
|
FunctionAnalysisManager *AM) {
|
|
PreservedAnalyses PA = PreservedAnalyses::all();
|
|
|
|
if (DebugPM)
|
|
dbgs() << "Starting function pass manager run.\n";
|
|
|
|
for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) {
|
|
if (DebugPM)
|
|
dbgs() << "Running function pass: " << Passes[Idx]->name() << "\n";
|
|
|
|
PreservedAnalyses PassPA = Passes[Idx]->run(F, AM);
|
|
if (AM)
|
|
AM->invalidate(F, PassPA);
|
|
PA.intersect(std::move(PassPA));
|
|
|
|
F.getContext().yield();
|
|
}
|
|
|
|
if (DebugPM)
|
|
dbgs() << "Finished function pass manager run.\n";
|
|
|
|
return PA;
|
|
}
|
|
|
|
bool FunctionAnalysisManager::empty() const {
|
|
assert(FunctionAnalysisResults.empty() ==
|
|
FunctionAnalysisResultLists.empty() &&
|
|
"The storage and index of analysis results disagree on how many there "
|
|
"are!");
|
|
return FunctionAnalysisResults.empty();
|
|
}
|
|
|
|
void FunctionAnalysisManager::clear() {
|
|
FunctionAnalysisResults.clear();
|
|
FunctionAnalysisResultLists.clear();
|
|
}
|
|
|
|
FunctionAnalysisManager::ResultConceptT &
|
|
FunctionAnalysisManager::getResultImpl(void *PassID, Function &F) {
|
|
FunctionAnalysisResultMapT::iterator RI;
|
|
bool Inserted;
|
|
std::tie(RI, Inserted) = FunctionAnalysisResults.insert(std::make_pair(
|
|
std::make_pair(PassID, &F), FunctionAnalysisResultListT::iterator()));
|
|
|
|
// If we don't have a cached result for this function, look up the pass and
|
|
// run it to produce a result, which we then add to the cache.
|
|
if (Inserted) {
|
|
auto &P = lookupPass(PassID);
|
|
if (DebugPM)
|
|
dbgs() << "Running function analysis: " << P.name() << "\n";
|
|
FunctionAnalysisResultListT &ResultList = FunctionAnalysisResultLists[&F];
|
|
ResultList.emplace_back(PassID, P.run(F, this));
|
|
RI->second = std::prev(ResultList.end());
|
|
}
|
|
|
|
return *RI->second->second;
|
|
}
|
|
|
|
FunctionAnalysisManager::ResultConceptT *
|
|
FunctionAnalysisManager::getCachedResultImpl(void *PassID, Function &F) const {
|
|
FunctionAnalysisResultMapT::const_iterator RI =
|
|
FunctionAnalysisResults.find(std::make_pair(PassID, &F));
|
|
return RI == FunctionAnalysisResults.end() ? nullptr : &*RI->second->second;
|
|
}
|
|
|
|
void FunctionAnalysisManager::invalidateImpl(void *PassID, Function &F) {
|
|
FunctionAnalysisResultMapT::iterator RI =
|
|
FunctionAnalysisResults.find(std::make_pair(PassID, &F));
|
|
if (RI == FunctionAnalysisResults.end())
|
|
return;
|
|
|
|
if (DebugPM)
|
|
dbgs() << "Invalidating function analysis: " << lookupPass(PassID).name()
|
|
<< "\n";
|
|
FunctionAnalysisResultLists[&F].erase(RI->second);
|
|
}
|
|
|
|
void FunctionAnalysisManager::invalidateImpl(Function &F,
|
|
const PreservedAnalyses &PA) {
|
|
if (DebugPM)
|
|
dbgs() << "Invalidating all non-preserved analyses for function: "
|
|
<< F.getName() << "\n";
|
|
|
|
// Clear all the invalidated results associated specifically with this
|
|
// function.
|
|
SmallVector<void *, 8> InvalidatedPassIDs;
|
|
FunctionAnalysisResultListT &ResultsList = FunctionAnalysisResultLists[&F];
|
|
for (FunctionAnalysisResultListT::iterator I = ResultsList.begin(),
|
|
E = ResultsList.end();
|
|
I != E;)
|
|
if (I->second->invalidate(F, PA)) {
|
|
if (DebugPM)
|
|
dbgs() << "Invalidating function analysis: "
|
|
<< lookupPass(I->first).name() << "\n";
|
|
|
|
InvalidatedPassIDs.push_back(I->first);
|
|
I = ResultsList.erase(I);
|
|
} else {
|
|
++I;
|
|
}
|
|
while (!InvalidatedPassIDs.empty())
|
|
FunctionAnalysisResults.erase(
|
|
std::make_pair(InvalidatedPassIDs.pop_back_val(), &F));
|
|
if (ResultsList.empty())
|
|
FunctionAnalysisResultLists.erase(&F);
|
|
}
|
|
|
|
char FunctionAnalysisManagerModuleProxy::PassID;
|
|
|
|
FunctionAnalysisManagerModuleProxy::Result
|
|
FunctionAnalysisManagerModuleProxy::run(Module &M) {
|
|
assert(FAM->empty() && "Function analyses ran prior to the module proxy!");
|
|
return Result(*FAM);
|
|
}
|
|
|
|
FunctionAnalysisManagerModuleProxy::Result::~Result() {
|
|
// Clear out the analysis manager if we're being destroyed -- it means we
|
|
// didn't even see an invalidate call when we got invalidated.
|
|
FAM->clear();
|
|
}
|
|
|
|
bool FunctionAnalysisManagerModuleProxy::Result::invalidate(
|
|
Module &M, const PreservedAnalyses &PA) {
|
|
// If this proxy isn't marked as preserved, then we can't even invalidate
|
|
// individual function analyses, there may be an invalid set of Function
|
|
// objects in the cache making it impossible to incrementally preserve them.
|
|
// Just clear the entire manager.
|
|
if (!PA.preserved(ID()))
|
|
FAM->clear();
|
|
|
|
// Return false to indicate that this result is still a valid proxy.
|
|
return false;
|
|
}
|
|
|
|
char ModuleAnalysisManagerFunctionProxy::PassID;
|