[TargetPassConfig] Feature generic options to setup start/stop-after/before

This patch refactors the code used in llc such that all the users of the
addPassesToEmitFile API have access to a homogeneous way of handling
start/stop-after/before options right out of the box.

In particular, just invoking addPassesToEmitFile will set the proper
pipeline without additional effort (modulo parsing a .mir file if the
start-before/after options are used.

NFC.

Differential Revision: https://reviews.llvm.org/D30913

llvm-svn: 309599
This commit is contained in:
Quentin Colombet 2017-07-31 18:24:07 +00:00
parent 222d912f69
commit 6d5f774fb6
6 changed files with 189 additions and 142 deletions

View File

@ -108,6 +108,18 @@ private:
bool Stopped = false;
bool AddingMachinePasses = false;
/// Set the StartAfter, StartBefore and StopAfter passes to allow running only
/// a portion of the normal code-gen pass sequence.
///
/// If the StartAfter and StartBefore pass ID is zero, then compilation will
/// begin at the normal point; otherwise, clear the Started flag to indicate
/// that passes should not be added until the starting pass is seen. If the
/// Stop pass ID is zero, then compilation will continue to the end.
///
/// This function expects that at least one of the StartAfter or the
/// StartBefore pass IDs is null.
void setStartStopPasses();
protected:
LLVMTargetMachine *TM;
PassConfigImpl *Impl = nullptr; // Internal data structures
@ -147,27 +159,25 @@ public:
CodeGenOpt::Level getOptLevel() const;
/// Set the StartAfter, StartBefore and StopAfter passes to allow running only
/// a portion of the normal code-gen pass sequence.
///
/// If the StartAfter and StartBefore pass ID is zero, then compilation will
/// begin at the normal point; otherwise, clear the Started flag to indicate
/// that passes should not be added until the starting pass is seen. If the
/// Stop pass ID is zero, then compilation will continue to the end.
///
/// This function expects that at least one of the StartAfter or the
/// StartBefore pass IDs is null.
void setStartStopPasses(AnalysisID StartBefore, AnalysisID StartAfter,
AnalysisID StopBefore, AnalysisID StopAfter) {
assert(!(StartBefore && StartAfter) &&
"Start after and start before passes are given");
assert(!(StopBefore && StopAfter) &&
"Stop after and stop before passed are given");
this->StartBefore = StartBefore;
this->StartAfter = StartAfter;
this->StopBefore = StopBefore;
this->StopAfter = StopAfter;
Started = (StartAfter == nullptr) && (StartBefore == nullptr);
/// Describe the status of the codegen
/// pipeline set by this target pass config.
/// Having a limited codegen pipeline means that options
/// have been used to restrict what codegen is doing.
/// In particular, that means that codegen won't emit
/// assembly code.
bool hasLimitedCodeGenPipeline() const;
/// If hasLimitedCodeGenPipeline is true, this method
/// returns a string with the name of the options, separated
/// by \p Separator that caused this pipeline to be limited.
std::string
getLimitedCodeGenPipelineReason(const char *Separator = "/") const;
/// Check if the codegen pipeline is limited in such a way that it
/// won't be complete. When the codegen pipeline is not complete,
/// this means it may not be possible to generate assembly from it.
bool willCompleteCodeGenPipeline() const {
return !hasLimitedCodeGenPipeline() || (!StopAfter && !StopBefore);
}
void setDisableVerify(bool Disable) { setOpt(DisableVerify, Disable); }

View File

@ -25,6 +25,7 @@
namespace llvm {
class GlobalValue;
class MachineModuleInfo;
class Mangler;
class MCAsmInfo;
class MCContext;
@ -222,11 +223,12 @@ public:
/// emitted. Typically this will involve several steps of code generation.
/// This method should return true if emission of this file type is not
/// supported, or false on success.
virtual bool addPassesToEmitFile(
PassManagerBase &, raw_pwrite_stream &, CodeGenFileType,
bool /*DisableVerify*/ = true, AnalysisID /*StartBefore*/ = nullptr,
AnalysisID /*StartAfter*/ = nullptr, AnalysisID /*StopBefore*/ = nullptr,
AnalysisID /*StopAfter*/ = nullptr) {
/// \p MMI is an optional parameter that, if set to non-nullptr,
/// will be used to set the MachineModuloInfo for this PM.
virtual bool addPassesToEmitFile(PassManagerBase &, raw_pwrite_stream &,
CodeGenFileType,
bool /*DisableVerify*/ = true,
MachineModuleInfo *MMI = nullptr) {
return true;
}
@ -270,6 +272,7 @@ protected: // Can only create subclasses.
CodeModel::Model CM, CodeGenOpt::Level OL);
void initAsmInfo();
public:
/// \brief Get a TargetIRAnalysis implementation for the target.
///
@ -283,11 +286,11 @@ public:
/// Add passes to the specified pass manager to get the specified file
/// emitted. Typically this will involve several steps of code generation.
bool addPassesToEmitFile(
PassManagerBase &PM, raw_pwrite_stream &Out, CodeGenFileType FileType,
bool DisableVerify = true, AnalysisID StartBefore = nullptr,
AnalysisID StartAfter = nullptr, AnalysisID StopBefore = nullptr,
AnalysisID StopAfter = nullptr) override;
/// \p MMI is an optional parameter that, if set to non-nullptr,
/// will be used to set the MachineModuloInfofor this PM.
bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out,
CodeGenFileType FileType, bool DisableVerify = true,
MachineModuleInfo *MMI = nullptr) override;
/// Add passes to the specified pass manager to get machine code emitted with
/// the MCJIT. This method returns true if machine code is not supported. It

View File

@ -92,24 +92,25 @@ TargetIRAnalysis LLVMTargetMachine::getTargetIRAnalysis() {
/// addPassesToX helper drives creation and initialization of TargetPassConfig.
static MCContext *
addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM,
bool DisableVerify, AnalysisID StartBefore,
AnalysisID StartAfter, AnalysisID StopBefore,
AnalysisID StopAfter) {
bool DisableVerify, bool &WillCompleteCodeGenPipeline,
raw_pwrite_stream &Out, MachineModuleInfo *MMI) {
// Targets may override createPassConfig to provide a target-specific
// subclass.
TargetPassConfig *PassConfig = TM->createPassConfig(PM);
PassConfig->setStartStopPasses(StartBefore, StartAfter, StopBefore,
StopAfter);
// Set PassConfig options provided by TargetMachine.
PassConfig->setDisableVerify(DisableVerify);
WillCompleteCodeGenPipeline = PassConfig->willCompleteCodeGenPipeline();
PM.add(PassConfig);
MachineModuleInfo *MMI = new MachineModuleInfo(TM);
if (!MMI)
MMI = new MachineModuleInfo(TM);
PM.add(MMI);
if (PassConfig->addISelPasses())
return nullptr;
PassConfig->addMachinePasses();
PassConfig->setInitialized();
if (!WillCompleteCodeGenPipeline)
PM.add(createPrintMIRPass(Out));
return &MMI->getContext();
}
@ -185,23 +186,20 @@ bool LLVMTargetMachine::addAsmPrinter(PassManagerBase &PM,
return false;
}
bool LLVMTargetMachine::addPassesToEmitFile(
PassManagerBase &PM, raw_pwrite_stream &Out, CodeGenFileType FileType,
bool DisableVerify, AnalysisID StartBefore, AnalysisID StartAfter,
AnalysisID StopBefore, AnalysisID StopAfter) {
bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
raw_pwrite_stream &Out,
CodeGenFileType FileType,
bool DisableVerify,
MachineModuleInfo *MMI) {
// Add common CodeGen passes.
MCContext *Context =
addPassesToGenerateCode(this, PM, DisableVerify, StartBefore, StartAfter,
StopBefore, StopAfter);
bool WillCompleteCodeGenPipeline = true;
MCContext *Context = addPassesToGenerateCode(
this, PM, DisableVerify, WillCompleteCodeGenPipeline, Out, MMI);
if (!Context)
return true;
if (StopBefore || StopAfter) {
PM.add(createPrintMIRPass(Out));
} else {
if (addAsmPrinter(PM, Out, FileType, *Context))
return true;
}
if (WillCompleteCodeGenPipeline && addAsmPrinter(PM, Out, FileType, *Context))
return true;
PM.add(createFreeMachineFunctionPass());
return false;
@ -216,10 +214,13 @@ bool LLVMTargetMachine::addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx,
raw_pwrite_stream &Out,
bool DisableVerify) {
// Add common CodeGen passes.
Ctx = addPassesToGenerateCode(this, PM, DisableVerify, nullptr, nullptr,
nullptr, nullptr);
bool WillCompleteCodeGenPipeline = true;
Ctx = addPassesToGenerateCode(this, PM, DisableVerify,
WillCompleteCodeGenPipeline, Out,
/*MachineModuleInfo*/ nullptr);
if (!Ctx)
return true;
assert(WillCompleteCodeGenPipeline && "CodeGen pipeline has been altered");
if (Options.MCOptions.MCSaveTempLabels)
Ctx->setAllowTemporaryLabels(false);

View File

@ -153,6 +153,34 @@ static cl::opt<CFLAAType> UseCFLAA(
clEnumValN(CFLAAType::Both, "both",
"Enable both variants of CFL-AA")));
/// Option names for limiting the codegen pipeline.
/// Those are used in error reporting and we didn't want
/// to duplicate their names all over the place.
const char *StartAfterOptName = "start-after";
const char *StartBeforeOptName = "start-before";
const char *StopAfterOptName = "stop-after";
const char *StopBeforeOptName = "stop-before";
static cl::opt<std::string>
StartAfterOpt(StringRef(StartAfterOptName),
cl::desc("Resume compilation after a specific pass"),
cl::value_desc("pass-name"), cl::init(""));
static cl::opt<std::string>
StartBeforeOpt(StringRef(StartBeforeOptName),
cl::desc("Resume compilation before a specific pass"),
cl::value_desc("pass-name"), cl::init(""));
static cl::opt<std::string>
StopAfterOpt(StringRef(StopAfterOptName),
cl::desc("Stop compilation after a specific pass"),
cl::value_desc("pass-name"), cl::init(""));
static cl::opt<std::string>
StopBeforeOpt(StringRef(StopBeforeOptName),
cl::desc("Stop compilation before a specific pass"),
cl::value_desc("pass-name"), cl::init(""));
/// Allow standard passes to be disabled by command line options. This supports
/// simple binary flags that either suppress the pass or do nothing.
/// i.e. -disable-mypass=false has no effect.
@ -282,6 +310,37 @@ TargetPassConfig::~TargetPassConfig() {
delete Impl;
}
static const PassInfo *getPassInfo(StringRef PassName) {
if (PassName.empty())
return nullptr;
const PassRegistry &PR = *PassRegistry::getPassRegistry();
const PassInfo *PI = PR.getPassInfo(PassName);
if (!PI)
report_fatal_error(Twine('\"') + Twine(PassName) +
Twine("\" pass is not registered."));
return PI;
}
static AnalysisID getPassIDFromName(StringRef PassName) {
const PassInfo *PI = getPassInfo(PassName);
return PI ? PI->getTypeInfo() : nullptr;
}
void TargetPassConfig::setStartStopPasses() {
StartBefore = getPassIDFromName(StartBeforeOpt);
StartAfter = getPassIDFromName(StartAfterOpt);
StopBefore = getPassIDFromName(StopBeforeOpt);
StopAfter = getPassIDFromName(StopAfterOpt);
if (StartBefore && StartAfter)
report_fatal_error(Twine(StartBeforeOptName) + Twine(" and ") +
Twine(StartAfterOptName) + Twine(" specified!"));
if (StopBefore && StopAfter)
report_fatal_error(Twine(StopBeforeOptName) + Twine(" and ") +
Twine(StopAfterOptName) + Twine(" specified!"));
Started = (StartAfter == nullptr) && (StartBefore == nullptr);
}
// Out of line constructor provides default values for pass options and
// registers all common codegen passes.
TargetPassConfig::TargetPassConfig(LLVMTargetMachine &TM, PassManagerBase &pm)
@ -305,6 +364,8 @@ TargetPassConfig::TargetPassConfig(LLVMTargetMachine &TM, PassManagerBase &pm)
if (TM.Options.EnableIPRA)
setRequiresCodeGenSCCOrder();
setStartStopPasses();
}
CodeGenOpt::Level TargetPassConfig::getOptLevel() const {
@ -339,6 +400,30 @@ TargetPassConfig::TargetPassConfig()
"triple set?");
}
bool TargetPassConfig::hasLimitedCodeGenPipeline() const {
return StartBefore || StartAfter || StopBefore || StopAfter;
}
std::string
TargetPassConfig::getLimitedCodeGenPipelineReason(const char *Separator) const {
if (!hasLimitedCodeGenPipeline())
return std::string();
std::string Res;
static cl::opt<std::string> *PassNames[] = {&StartAfterOpt, &StartBeforeOpt,
&StopAfterOpt, &StopBeforeOpt};
static const char *OptNames[] = {StartAfterOptName, StartBeforeOptName,
StopAfterOptName, StopBeforeOptName};
bool IsFirst = true;
for (int Idx = 0; Idx < 4; ++Idx)
if (!PassNames[Idx]->empty()) {
if (!IsFirst)
Res += Separator;
IsFirst = false;
Res += OptNames[Idx];
}
return Res;
}
// Helper to verify the analysis is really immutable.
void TargetPassConfig::setOpt(bool &Opt, bool Val) {
assert(!Initialized && "PassConfig is immutable");

View File

@ -27,12 +27,12 @@
; RUN: not llc < %s -stop-before=nonexistent -o /dev/null 2>&1 | FileCheck %s -check-prefix=NONEXISTENT-STOP-BEFORE
; RUN: not llc < %s -start-after=nonexistent -o /dev/null 2>&1 | FileCheck %s -check-prefix=NONEXISTENT-START-AFTER
; RUN: not llc < %s -stop-after=nonexistent -o /dev/null 2>&1 | FileCheck %s -check-prefix=NONEXISTENT-STOP-AFTER
; NONEXISTENT-START-BEFORE: start-before pass is not registered.
; NONEXISTENT-STOP-BEFORE: stop-before pass is not registered.
; NONEXISTENT-START-AFTER: start-after pass is not registered.
; NONEXISTENT-STOP-AFTER: stop-after pass is not registered.
; NONEXISTENT-START-BEFORE: "nonexistent" pass is not registered.
; NONEXISTENT-STOP-BEFORE: "nonexistent" pass is not registered.
; NONEXISTENT-START-AFTER: "nonexistent" pass is not registered.
; NONEXISTENT-STOP-AFTER: "nonexistent" pass is not registered.
; RUN: not llc < %s -start-before=loop-reduce -start-after=loop-reduce -o /dev/null 2>&1 | FileCheck %s -check-prefix=DOUBLE-START
; RUN: not llc < %s -stop-before=loop-reduce -stop-after=loop-reduce -o /dev/null 2>&1 | FileCheck %s -check-prefix=DOUBLE-STOP
; DOUBLE-START: -start-before and -start-after specified!
; DOUBLE-STOP: -stop-before and -stop-after specified!
; DOUBLE-START: start-before and start-after specified!
; DOUBLE-STOP: stop-before and stop-after specified!

View File

@ -126,22 +126,6 @@ static cl::opt<bool> DiscardValueNames(
cl::desc("Discard names from Value (other than GlobalValue)."),
cl::init(false), cl::Hidden);
static cl::opt<std::string> StopBefore("stop-before",
cl::desc("Stop compilation before a specific pass"),
cl::value_desc("pass-name"), cl::init(""));
static cl::opt<std::string> StopAfter("stop-after",
cl::desc("Stop compilation after a specific pass"),
cl::value_desc("pass-name"), cl::init(""));
static cl::opt<std::string> StartBefore("start-before",
cl::desc("Resume compilation before a specific pass"),
cl::value_desc("pass-name"), cl::init(""));
static cl::opt<std::string> StartAfter("start-after",
cl::desc("Resume compilation after a specific pass"),
cl::value_desc("pass-name"), cl::init(""));
static cl::list<std::string> IncludeDirs("I", cl::desc("include search path"));
static cl::opt<bool> PassRemarksWithHotness(
@ -389,20 +373,6 @@ static bool addPass(PassManagerBase &PM, const char *argv0,
return false;
}
static AnalysisID getPassID(const char *argv0, const char *OptionName,
StringRef PassName) {
if (PassName.empty())
return nullptr;
const PassRegistry &PR = *PassRegistry::getPassRegistry();
const PassInfo *PI = PR.getPassInfo(PassName);
if (!PI) {
errs() << argv0 << ": " << OptionName << " pass is not registered.\n";
exit(1);
}
return PI->getTypeInfo();
}
static int compileModule(char **argv, LLVMContext &Context) {
// Load the module to be compiled...
SMDiagnostic Err;
@ -537,66 +507,44 @@ static int compileModule(char **argv, LLVMContext &Context) {
}
const char *argv0 = argv[0];
AnalysisID StartBeforeID = getPassID(argv0, "start-before", StartBefore);
AnalysisID StartAfterID = getPassID(argv0, "start-after", StartAfter);
AnalysisID StopAfterID = getPassID(argv0, "stop-after", StopAfter);
AnalysisID StopBeforeID = getPassID(argv0, "stop-before", StopBefore);
if (StartBeforeID && StartAfterID) {
errs() << argv0 << ": -start-before and -start-after specified!\n";
return 1;
}
if (StopBeforeID && StopAfterID) {
errs() << argv0 << ": -stop-before and -stop-after specified!\n";
LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine&>(*Target);
MachineModuleInfo *MMI = new MachineModuleInfo(&LLVMTM);
// Construct a custom pass pipeline that starts after instruction
// selection.
if (!RunPassNames->empty()) {
if (!MIR) {
errs() << argv0 << ": run-pass is for .mir file only.\n";
return 1;
}
TargetPassConfig &TPC = *LLVMTM.createPassConfig(PM);
if (TPC.hasLimitedCodeGenPipeline()) {
errs() << argv0 << ": run-pass cannot be used with "
<< TPC.getLimitedCodeGenPipelineReason(" and ") << ".\n";
return 1;
}
TPC.setDisableVerify(NoVerify);
PM.add(&TPC);
PM.add(MMI);
TPC.printAndVerify("");
for (const std::string &RunPassName : *RunPassNames) {
if (addPass(PM, argv0, RunPassName, TPC))
return 1;
}
TPC.setInitialized();
PM.add(createPrintMIRPass(*OS));
PM.add(createFreeMachineFunctionPass());
} else if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify, MMI)) {
errs() << argv0 << ": target does not support generation of this"
<< " file type!\n";
return 1;
}
if (MIR) {
// Construct a custom pass pipeline that starts after instruction
// selection.
LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine&>(*Target);
TargetPassConfig &TPC = *LLVMTM.createPassConfig(PM);
TPC.setDisableVerify(NoVerify);
PM.add(&TPC);
MachineModuleInfo *MMI = new MachineModuleInfo(&LLVMTM);
assert(MMI && "addPassesToEmitFile didn't set MMI");
if (MIR->parseMachineFunctions(*M, *MMI))
return 1;
PM.add(MMI);
TPC.printAndVerify("");
if (!RunPassNames->empty()) {
if (!StartAfter.empty() || !StopAfter.empty() || !StartBefore.empty() ||
!StopBefore.empty()) {
errs() << argv0 << ": start-after and/or stop-after passes are "
"redundant when run-pass is specified.\n";
return 1;
}
for (const std::string &RunPassName : *RunPassNames) {
if (addPass(PM, argv0, RunPassName, TPC))
return 1;
}
} else {
TPC.setStartStopPasses(StartBeforeID, StartAfterID, StopBeforeID,
StopAfterID);
TPC.addISelPasses();
TPC.addMachinePasses();
}
TPC.setInitialized();
if (!StopBefore.empty() || !StopAfter.empty() || !RunPassNames->empty()) {
PM.add(createPrintMIRPass(*OS));
} else if (LLVMTM.addAsmPrinter(PM, *OS, FileType, MMI->getContext())) {
errs() << argv0 << ": target does not support generation of this"
<< " file type!\n";
return 1;
}
PM.add(createFreeMachineFunctionPass());
} else if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify,
StartBeforeID, StartAfterID,
StopBeforeID, StopAfterID)) {
errs() << argv0 << ": target does not support generation of this"
<< " file type!\n";
return 1;
}
// Before executing passes, print the final values of the LLVM options.