Index: include/llvm/CodeGen/TargetPassConfig.h =================================================================== --- include/llvm/CodeGen/TargetPassConfig.h +++ include/llvm/CodeGen/TargetPassConfig.h @@ -108,6 +108,18 @@ 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 @@ 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); } Index: include/llvm/Target/TargetMachine.h =================================================================== --- include/llvm/Target/TargetMachine.h +++ include/llvm/Target/TargetMachine.h @@ -25,6 +25,7 @@ namespace llvm { class GlobalValue; +class MachineModuleInfo; class Mangler; class MCAsmInfo; class MCContext; @@ -222,11 +223,12 @@ /// 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 MMISave is an optional parameter that, if set to non-nullptr, + /// will contain the MachineModuloInfo created for this PM. + virtual bool addPassesToEmitFile(PassManagerBase &, raw_pwrite_stream &, + CodeGenFileType, + bool /*DisableVerify*/ = true, + MachineModuleInfo **MMI = nullptr) { return true; } @@ -270,6 +272,7 @@ CodeModel::Model CM, CodeGenOpt::Level OL); void initAsmInfo(); + public: /// \brief Get a TargetIRAnalysis implementation for the target. /// @@ -283,11 +286,11 @@ /// 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 MMISave is an optional parameter that, if set to non-nullptr, + /// will contain the MachineModuloInfo created for this PM. + bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out, + CodeGenFileType FileType, bool DisableVerify = true, + MachineModuleInfo **MMISave = 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 Index: lib/CodeGen/LLVMTargetMachine.cpp =================================================================== --- lib/CodeGen/LLVMTargetMachine.cpp +++ lib/CodeGen/LLVMTargetMachine.cpp @@ -92,24 +92,26 @@ /// 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 **MMISave) { // 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 (MMISave) + *MMISave = MMI; PM.add(MMI); if (PassConfig->addISelPasses()) return nullptr; PassConfig->addMachinePasses(); PassConfig->setInitialized(); + if (!WillCompleteCodeGenPipeline) + PM.add(createPrintMIRPass(Out)); return &MMI->getContext(); } @@ -185,23 +187,20 @@ 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 +215,13 @@ 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); Index: lib/CodeGen/TargetPassConfig.cpp =================================================================== --- lib/CodeGen/TargetPassConfig.cpp +++ lib/CodeGen/TargetPassConfig.cpp @@ -153,6 +153,34 @@ 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 + StartAfterOpt(StringRef(StartAfterOptName), + cl::desc("Resume compilation after a specific pass"), + cl::value_desc("pass-name"), cl::init("")); + +static cl::opt + StartBeforeOpt(StringRef(StartBeforeOptName), + cl::desc("Resume compilation before a specific pass"), + cl::value_desc("pass-name"), cl::init("")); + +static cl::opt + StopAfterOpt(StringRef(StopAfterOptName), + cl::desc("Stop compilation after a specific pass"), + cl::value_desc("pass-name"), cl::init("")); + +static cl::opt + 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 @@ 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 @@ if (TM.Options.EnableIPRA) setRequiresCodeGenSCCOrder(); + + setStartStopPasses(); } CodeGenOpt::Level TargetPassConfig::getOptLevel() const { @@ -339,6 +400,30 @@ "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 *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"); Index: test/CodeGen/Generic/llc-start-stop.ll =================================================================== --- test/CodeGen/Generic/llc-start-stop.ll +++ test/CodeGen/Generic/llc-start-stop.ll @@ -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! Index: tools/llc/llc.cpp =================================================================== --- tools/llc/llc.cpp +++ tools/llc/llc.cpp @@ -126,22 +126,6 @@ cl::desc("Discard names from Value (other than GlobalValue)."), cl::init(false), cl::Hidden); -static cl::opt StopBefore("stop-before", - cl::desc("Stop compilation before a specific pass"), - cl::value_desc("pass-name"), cl::init("")); - -static cl::opt StopAfter("stop-after", - cl::desc("Stop compilation after a specific pass"), - cl::value_desc("pass-name"), cl::init("")); - -static cl::opt StartBefore("start-before", - cl::desc("Resume compilation before a specific pass"), - cl::value_desc("pass-name"), cl::init("")); - -static cl::opt StartAfter("start-after", - cl::desc("Resume compilation after a specific pass"), - cl::value_desc("pass-name"), cl::init("")); - static cl::list IncludeDirs("I", cl::desc("include search path")); static cl::opt PassRemarksWithHotness( @@ -389,20 +373,6 @@ 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,68 +507,47 @@ } 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"; - return 1; - } + MachineModuleInfo *MMI = nullptr; - if (MIR) { - // Construct a custom pass pipeline that starts after instruction - // selection. + // 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; + } LLVMTargetMachine &LLVMTM = static_cast(*Target); 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); - MachineModuleInfo *MMI = new MachineModuleInfo(&LLVMTM); - if (MIR->parseMachineFunctions(*M, *MMI)) - return 1; + MMI = new MachineModuleInfo(&LLVMTM); 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"; + for (const std::string &RunPassName : *RunPassNames) { + if (addPass(PM, argv0, RunPassName, TPC)) 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(createPrintMIRPass(*OS)); PM.add(createFreeMachineFunctionPass()); - } else if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify, - StartBeforeID, StartAfterID, - StopBeforeID, StopAfterID)) { + } else if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify, &MMI)) { errs() << argv0 << ": target does not support generation of this" - << " file type!\n"; + << " file type!\n"; return 1; } + if (MIR) { + assert(MMI && "addPassesToEmitFile didn't set MMI"); + if (MIR->parseMachineFunctions(*M, *MMI)) + return 1; + } + // Before executing passes, print the final values of the LLVM options. cl::PrintOptionValues();