mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-26 23:29:22 +00:00
The primary motivation for this pass is to separate the call graph analysis used by the new pass manager's CGSCC pass management from the existing call graph analysis pass. That analysis pass is (somewhat unfortunately) over-constrained by the existing CallGraphSCCPassManager requirements. Those requirements make it *really* hard to cleanly layer the needed functionality for the new pass manager on top of the existing analysis. However, there are also a bunch of things that the pass manager would specifically benefit from doing differently from the existing call graph analysis, and this new implementation tries to address several of them: - Be lazy about scanning function definitions. The existing pass eagerly scans the entire module to build the initial graph. This new pass is significantly more lazy, and I plan to push this even further to maximize locality during CGSCC walks. - Don't use a single synthetic node to partition functions with an indirect call from functions whose address is taken. This node creates a huge choke-point which would preclude good parallelization across the fanout of the SCC graph when we got to the point of looking at such changes to LLVM. - Use a memory dense and lightweight representation of the call graph rather than value handles and tracking call instructions. This will require explicit update calls instead of some updates working transparently, but should end up being significantly more efficient. The explicit update calls ended up being needed in many cases for the existing call graph so we don't really lose anything. - Doesn't explicitly model SCCs and thus doesn't provide an "identity" for an SCC which is stable across updates. This is essential for the new pass manager to work correctly. - Only form the graph necessary for traversing all of the functions in an SCC friendly order. This is a much simpler graph structure and should be more memory dense. It does limit the ways in which it is appropriate to use this analysis. I wish I had a better name than "call graph". I've commented extensively this aspect. This is still very much a WIP, in fact it is really just the initial bits. But it is about the fourth version of the initial bits that I've implemented with each of the others running into really frustrating problms. This looks like it will actually work and I'd like to split the actual complexity across commits for the sake of my reviewers. =] The rest of the implementation along with lots of wiring will follow somewhat more rapidly now that there is a good path forward. Naturally, this doesn't impact any of the existing optimizer. This code is specific to the new pass manager. A bunch of thanks are deserved for the various folks that have helped with the design of this, especially Nick Lewycky who actually sat with me to go through the fundamentals of the final version here. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200903 91177308-0d34-0410-b5e6-96231b3b80d8
210 lines
6.7 KiB
C++
210 lines
6.7 KiB
C++
//===- Passes.cpp - Parsing, selection, and running of passes -------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
///
|
|
/// This file provides the infrastructure to parse and build a custom pass
|
|
/// manager based on a commandline flag. It also provides helpers to aid in
|
|
/// analyzing, debugging, and testing pass structures.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Passes.h"
|
|
#include "llvm/Analysis/LazyCallGraph.h"
|
|
#include "llvm/IR/IRPrintingPasses.h"
|
|
#include "llvm/IR/PassManager.h"
|
|
#include "llvm/IR/Verifier.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
/// \brief No-op module pass which does nothing.
|
|
struct NoOpModulePass {
|
|
PreservedAnalyses run(Module *M) { return PreservedAnalyses::all(); }
|
|
static StringRef name() { return "NoOpModulePass"; }
|
|
};
|
|
|
|
/// \brief No-op function pass which does nothing.
|
|
struct NoOpFunctionPass {
|
|
PreservedAnalyses run(Function *F) { return PreservedAnalyses::all(); }
|
|
static StringRef name() { return "NoOpFunctionPass"; }
|
|
};
|
|
|
|
} // End anonymous namespace.
|
|
|
|
// FIXME: Factor all of the parsing logic into a .def file that we include
|
|
// under different macros.
|
|
static bool isModulePassName(StringRef Name) {
|
|
if (Name == "no-op-module") return true;
|
|
if (Name == "print") return true;
|
|
if (Name == "print-cg") return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool isFunctionPassName(StringRef Name) {
|
|
if (Name == "no-op-function") return true;
|
|
if (Name == "print") return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool parseModulePassName(ModulePassManager &MPM, StringRef Name) {
|
|
if (Name == "no-op-module") {
|
|
MPM.addPass(NoOpModulePass());
|
|
return true;
|
|
}
|
|
if (Name == "print") {
|
|
MPM.addPass(PrintModulePass(dbgs()));
|
|
return true;
|
|
}
|
|
if (Name == "print-cg") {
|
|
MPM.addPass(LazyCallGraphPrinterPass(dbgs()));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name) {
|
|
if (Name == "no-op-function") {
|
|
FPM.addPass(NoOpFunctionPass());
|
|
return true;
|
|
}
|
|
if (Name == "print") {
|
|
FPM.addPass(PrintFunctionPass(dbgs()));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool parseFunctionPassPipeline(FunctionPassManager &FPM,
|
|
StringRef &PipelineText,
|
|
bool VerifyEachPass) {
|
|
for (;;) {
|
|
// Parse nested pass managers by recursing.
|
|
if (PipelineText.startswith("function(")) {
|
|
FunctionPassManager NestedFPM;
|
|
|
|
// Parse the inner pipeline inte the nested manager.
|
|
PipelineText = PipelineText.substr(strlen("function("));
|
|
if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) ||
|
|
PipelineText.empty())
|
|
return false;
|
|
assert(PipelineText[0] == ')');
|
|
PipelineText = PipelineText.substr(1);
|
|
|
|
// Add the nested pass manager with the appropriate adaptor.
|
|
FPM.addPass(NestedFPM);
|
|
} else {
|
|
// Otherwise try to parse a pass name.
|
|
size_t End = PipelineText.find_first_of(",)");
|
|
if (!parseFunctionPassName(FPM, PipelineText.substr(0, End)))
|
|
return false;
|
|
if (VerifyEachPass)
|
|
FPM.addPass(VerifierPass());
|
|
|
|
PipelineText = PipelineText.substr(End);
|
|
}
|
|
|
|
if (PipelineText.empty() || PipelineText[0] == ')')
|
|
return true;
|
|
|
|
assert(PipelineText[0] == ',');
|
|
PipelineText = PipelineText.substr(1);
|
|
}
|
|
}
|
|
|
|
static bool parseModulePassPipeline(ModulePassManager &MPM,
|
|
StringRef &PipelineText,
|
|
bool VerifyEachPass) {
|
|
for (;;) {
|
|
// Parse nested pass managers by recursing.
|
|
if (PipelineText.startswith("module(")) {
|
|
ModulePassManager NestedMPM;
|
|
|
|
// Parse the inner pipeline into the nested manager.
|
|
PipelineText = PipelineText.substr(strlen("module("));
|
|
if (!parseModulePassPipeline(NestedMPM, PipelineText, VerifyEachPass) ||
|
|
PipelineText.empty())
|
|
return false;
|
|
assert(PipelineText[0] == ')');
|
|
PipelineText = PipelineText.substr(1);
|
|
|
|
// Now add the nested manager as a module pass.
|
|
MPM.addPass(NestedMPM);
|
|
} else if (PipelineText.startswith("function(")) {
|
|
FunctionPassManager NestedFPM;
|
|
|
|
// Parse the inner pipeline inte the nested manager.
|
|
PipelineText = PipelineText.substr(strlen("function("));
|
|
if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) ||
|
|
PipelineText.empty())
|
|
return false;
|
|
assert(PipelineText[0] == ')');
|
|
PipelineText = PipelineText.substr(1);
|
|
|
|
// Add the nested pass manager with the appropriate adaptor.
|
|
MPM.addPass(createModuleToFunctionPassAdaptor(NestedFPM));
|
|
} else {
|
|
// Otherwise try to parse a pass name.
|
|
size_t End = PipelineText.find_first_of(",)");
|
|
if (!parseModulePassName(MPM, PipelineText.substr(0, End)))
|
|
return false;
|
|
if (VerifyEachPass)
|
|
MPM.addPass(VerifierPass());
|
|
|
|
PipelineText = PipelineText.substr(End);
|
|
}
|
|
|
|
if (PipelineText.empty() || PipelineText[0] == ')')
|
|
return true;
|
|
|
|
assert(PipelineText[0] == ',');
|
|
PipelineText = PipelineText.substr(1);
|
|
}
|
|
}
|
|
|
|
// Primary pass pipeline description parsing routine.
|
|
// FIXME: Should this routine accept a TargetMachine or require the caller to
|
|
// pre-populate the analysis managers with target-specific stuff?
|
|
bool llvm::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
|
|
bool VerifyEachPass) {
|
|
// Look at the first entry to figure out which layer to start parsing at.
|
|
if (PipelineText.startswith("module("))
|
|
return parseModulePassPipeline(MPM, PipelineText, VerifyEachPass) &&
|
|
PipelineText.empty();
|
|
if (PipelineText.startswith("function(")) {
|
|
FunctionPassManager FPM;
|
|
if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass) ||
|
|
!PipelineText.empty())
|
|
return false;
|
|
MPM.addPass(createModuleToFunctionPassAdaptor(FPM));
|
|
return true;
|
|
}
|
|
|
|
// This isn't a direct pass manager name, look for the end of a pass name.
|
|
StringRef FirstName =
|
|
PipelineText.substr(0, PipelineText.find_first_of(",)"));
|
|
if (isModulePassName(FirstName))
|
|
return parseModulePassPipeline(MPM, PipelineText, VerifyEachPass) &&
|
|
PipelineText.empty();
|
|
|
|
if (isFunctionPassName(FirstName)) {
|
|
FunctionPassManager FPM;
|
|
if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass) ||
|
|
!PipelineText.empty())
|
|
return false;
|
|
MPM.addPass(createModuleToFunctionPassAdaptor(FPM));
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|