Index: include/llvm/IR/LegacyPassNameParser.h =================================================================== --- include/llvm/IR/LegacyPassNameParser.h +++ include/llvm/IR/LegacyPassNameParser.h @@ -6,21 +6,14 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// -// This file contains the PassNameParser and FilteredPassNameParser<> classes, -// which are used to add command line arguments to a utility for all of the -// passes that have been registered into the system. -// -// The PassNameParser class adds ALL passes linked into the system (that are -// creatable) as command line arguments to the tool (when instantiated with the -// appropriate command line option template). The FilteredPassNameParser<> -// template is used for the same purposes as PassNameParser, except that it only -// includes passes that have a PassType that are compatible with the filter -// (which is the template argument). -// -// Note that this is part of the legacy pass manager infrastructure and will be -// (eventually) going away. -// +/// +/// \file This file contains the PassNameParser and FilteredPassNameParser +/// class templates, which are used to parse option values which correspond +/// the names of (legacy) passes that have been registered into the system. +/// +/// Note that this is part of the legacy pass manager infrastructure and will be +/// (eventually) going away. +/// //===----------------------------------------------------------------------===// #ifndef LLVM_IR_LEGACYPASSNAMEPARSER_H @@ -35,23 +28,92 @@ namespace llvm { +namespace detail { + +struct PassNameParserValueType { + using LegacyPassType = const PassInfo *; + + LegacyPassType P; + std::string PassID; + + PassNameParserValueType(LegacyPassType P) + : P(P), PassID(P->getPassArgument()) {} + PassNameParserValueType(StringRef ID = StringRef()) + : P(nullptr), PassID(ID) {} + + operator std::string() const { return PassID; } + operator LegacyPassType() const { return P; } + bool operator!=(const PassNameParserValueType &x) const { + return PassID != x.PassID; + } +}; + +} // namespace detail + +template <> +struct cl::OptionValue final + : OptionValueCopy { + OptionValue() = default; + + OptionValue(const detail::PassNameParserValueType &V) { this->setValue(V); } + + OptionValue &operator=(const detail::PassNameParserValueType &V) { + setValue(V); + return *this; + } + +private: + void anchor() override; +}; + //===----------------------------------------------------------------------===// -// PassNameParser class - Make use of the pass registration mechanism to -// automatically add a command line argument to opt for each pass. -// +/// \class +/// This class template parses names of passes. +/// Makes use of the pass registration mechanism to automatically add a +/// command line argument to the Option for each legacy pass being registered. +/// +/// \p AllowArbitraryNames parameter when 'true' allows to skip error checking +/// and accept option value that does not match any of registered (legacy) +/// pass names. Currently used to allow new-pass-manager pass names. +/// +template class PassNameParser : public PassRegistrationListener, - public cl::parser { + public cl::parser { + public: + using ValueType = detail::PassNameParserValueType; + PassNameParser(cl::Option &O); ~PassNameParser() override; void initialize() { - cl::parser::initialize(); + this->parser::initialize(); // Add all of the passes to the map that got initialized before 'this' did. enumeratePasses(); } + // parse - Return true on error. + bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, ValueType &V) { + StringRef ArgVal; + if (this->Owner.hasArgStr()) + ArgVal = Arg; + else + ArgVal = ArgName; + + for (size_t i = 0, e = this->Values.size(); i != e; ++i) + if (this->Values[i].Name == ArgVal) { + V = this->Values[i].V.getValue(); + assert(V.P && "legacy passes should have PassInfo available"); + return false; + } + if (AllowArbitraryNames) { + V = ValueType(ArgVal.str()); + return false; + } + return O.error("Cannot find option named '" + ArgVal + "'!"); + } + // ignorablePassImpl - Can be overriden in subclasses to refine the list of // which passes we want to include. // @@ -68,12 +130,14 @@ // void passRegistered(const PassInfo *P) override { if (ignorablePass(P)) return; - if (findOption(P->getPassArgument().data()) != getNumOptions()) { + if (this->findOption(P->getPassArgument().data()) != + this->getNumOptions()) { errs() << "Two passes with the same argument (-" << P->getPassArgument() << ") attempted to be registered!\n"; llvm_unreachable(nullptr); } - addLiteralOption(P->getPassArgument().data(), P, P->getPassName().data()); + this->template addLiteralOption( + P->getPassArgument().data(), ValueType{P}, P->getPassName().data()); } void passEnumerate(const PassInfo *P) override { passRegistered(P); } @@ -81,26 +145,34 @@ // default implementation to sort the table before we print... void printOptionInfo(const cl::Option &O, size_t GlobalWidth) const override { PassNameParser *PNP = const_cast(this); - array_pod_sort(PNP->Values.begin(), PNP->Values.end(), ValCompare); - cl::parser::printOptionInfo(O, GlobalWidth); - } - -private: - // ValCompare - Provide a sorting comparator for Values elements... - static int ValCompare(const PassNameParser::OptionInfo *VT1, - const PassNameParser::OptionInfo *VT2) { - return VT1->Name.compare(VT2->Name); + // Comparison function to order records by name. + auto orderByName = [](const typename PassNameParser::OptionInfo &A, + const typename PassNameParser::OptionInfo &B) { + return A.Name < B.Name; + }; + llvm::sort(PNP->Values.begin(), PNP->Values.end(), orderByName); + + this->parser::printOptionInfo(O, GlobalWidth); } }; +extern template class PassNameParser; +extern template class PassNameParser; + ///===----------------------------------------------------------------------===// -/// FilteredPassNameParser class - Make use of the pass registration -/// mechanism to automatically add a command line argument to opt for -/// each pass that satisfies a filter criteria. Filter should return -/// true for passes to be registered as command-line options. /// -template -class FilteredPassNameParser : public PassNameParser { +/// This class template parses pass names according to a filtered list +/// of registered legacy passes. +/// +/// It only accepts pass names for passes that have their PassInfo compatible +/// with the filter \p Filter. Handling of legacy pass registration is performed +/// by its base class PassNameParser. +/// +/// \p Filter should return true for passes to be registered as values of +/// command line options. +/// +template +class FilteredPassNameParser : public PassNameParser { private: Filter filter; Index: lib/IR/LegacyPassManager.cpp =================================================================== --- lib/IR/LegacyPassManager.cpp +++ lib/IR/LegacyPassManager.cpp @@ -62,8 +62,7 @@ clEnumVal(Details , "print pass details when it is executed"))); namespace { -typedef llvm::cl::list -PassOptionList; +typedef llvm::cl::list> PassOptionList; } // Print IR out before/after specified passes. @@ -110,12 +109,9 @@ static bool ShouldPrintBeforeOrAfterPass(StringRef PassID, PassOptionList &PassesToPrint) { - for (auto *PassInf : PassesToPrint) { - if (PassInf) - if (PassInf->getPassArgument() == PassID) { - return true; - } - } + for (auto &PassInf : PassesToPrint) + if (PassInf == PassID) + return true; return false; } Index: lib/IR/Pass.cpp =================================================================== --- lib/IR/Pass.cpp +++ lib/IR/Pass.cpp @@ -244,15 +244,23 @@ PassRegistry::getPassRegistry()->enumerateWith(this); } -PassNameParser::PassNameParser(cl::Option &O) - : cl::parser(O) { +template +PassNameParser::PassNameParser(cl::Option &O) + : PassNameParser::parser(O) { PassRegistry::getPassRegistry()->addRegistrationListener(this); } // This only gets called during static destruction, in which case the // PassRegistry will have already been destroyed by llvm_shutdown(). So // attempting to remove the registration listener is an error. -PassNameParser::~PassNameParser() = default; +template +PassNameParser::~PassNameParser() = default; + +template class llvm::PassNameParser; +template class llvm::PassNameParser; +template class cl::parser; + +void cl::OptionValue::anchor() {} //===----------------------------------------------------------------------===// // AnalysisUsage Class Implementation Index: test/Other/loop-pass-printer.ll =================================================================== --- test/Other/loop-pass-printer.ll +++ test/Other/loop-pass-printer.ll @@ -5,19 +5,19 @@ ; RUN: -loop-deletion -print-before=loop-deletion \ ; RUN: | FileCheck %s -check-prefix=DEL ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes='loop(loop-deletion)' -print-before-all \ +; RUN: -passes='loop(loop-deletion)' -print-before=LoopDeletionPass \ ; RUN: | FileCheck %s -check-prefix=DEL ; RUN: opt < %s 2>&1 -disable-output \ ; RUN: -loop-unroll -print-after=loop-unroll -filter-print-funcs=bar \ ; RUN: | FileCheck %s -check-prefix=BAR -check-prefix=BAR-OLD ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes='require,loop(unroll-full)' -print-after-all -filter-print-funcs=bar \ +; RUN: -passes='require,loop(unroll-full)' -print-after=LoopFullUnrollPass -filter-print-funcs=bar \ ; RUN: | FileCheck %s -check-prefix=BAR ; RUN: opt < %s 2>&1 -disable-output \ ; RUN: -loop-unroll -print-after=loop-unroll -filter-print-funcs=foo -print-module-scope \ ; RUN: | FileCheck %s -check-prefix=FOO-MODULE -check-prefix=FOO-MODULE-OLD ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes='require,loop(unroll-full)' -print-after-all -filter-print-funcs=foo -print-module-scope \ +; RUN: -passes='require,loop(unroll-full)' -print-after=LoopFullUnrollPass -filter-print-funcs=foo -print-module-scope \ ; RUN: | FileCheck %s -check-prefix=FOO-MODULE ; DEL: IR Dump Before {{Delete dead loops|LoopDeletionPass}} Index: test/Other/print-module-scope.ll =================================================================== --- test/Other/print-module-scope.ll +++ test/Other/print-module-scope.ll @@ -7,13 +7,13 @@ ; RUN: -simplifycfg -print-after=simplifycfg -print-module-scope \ ; RUN: | FileCheck %s -check-prefix=CFG ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes=simplify-cfg -print-after-all -print-module-scope \ +; RUN: -passes=simplify-cfg -print-after=SimplifyCFGPass -print-module-scope \ ; RUN: | FileCheck %s -check-prefix=CFG ; RUN: opt < %s 2>&1 -disable-output \ ; RUN: -simplifycfg -print-after=simplifycfg -filter-print-funcs=foo -print-module-scope \ ; RUN: | FileCheck %s -check-prefix=FOO ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes=simplify-cfg -print-after-all -filter-print-funcs=foo -print-module-scope \ +; RUN: -passes=simplify-cfg -print-after=SimplifyCFGPass -filter-print-funcs=foo -print-module-scope \ ; RUN: | FileCheck %s -check-prefix=FOO ; CFG: IR Dump After {{Simplify the CFG|SimplifyCFGPass}} Index: test/Other/scc-deleted-printer.ll =================================================================== --- test/Other/scc-deleted-printer.ll +++ test/Other/scc-deleted-printer.ll @@ -1,7 +1,11 @@ ; RUN: opt < %s 2>&1 -disable-output \ ; RUN: -passes=inline -print-before-all -print-after-all | FileCheck %s -check-prefix=INL ; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=inline -print-before=InlinerPass -print-after=InlinerPass | FileCheck %s -check-prefix=INL +; RUN: opt < %s 2>&1 -disable-output \ ; RUN: -passes=inline -print-before-all -print-after-all -print-module-scope | FileCheck %s -check-prefix=INL-MOD +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=inline -print-before=InlinerPass -print-after=InlinerPass -print-module-scope | FileCheck %s -check-prefix=INL-MOD ; INL: IR Dump Before {{InlinerPass .*scc: .tester, foo}} ; INL-NOT: IR Dump After {{InlinerPass}} Index: test/Other/scc-pass-printer.ll =================================================================== --- test/Other/scc-pass-printer.ll +++ test/Other/scc-pass-printer.ll @@ -1,11 +1,19 @@ ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -inline -print-after-all | FileCheck %s -check-prefix=INL +; RUN: -inline -print-after-all | FileCheck %s -check-prefixes=INL,INL-ALL ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes=inline -print-after-all | FileCheck %s -check-prefix=INL +; RUN: -passes=inline -print-after-all | FileCheck %s -check-prefixes=INL,INL-ALL ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -inline -print-after-all -print-module-scope | FileCheck %s -check-prefix=INL-MOD +; RUN: -inline -print-after=inline | FileCheck %s -check-prefix=INL ; RUN: opt < %s 2>&1 -disable-output \ -; RUN: -passes=inline -print-after-all -print-module-scope | FileCheck %s -check-prefix=INL-MOD +; RUN: -passes=inline -print-after=InlinerPass | FileCheck %s -check-prefix=INL +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -inline -print-after-all -print-module-scope | FileCheck %s -check-prefixes=INL-MOD,INL-MOD-ALL +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=inline -print-after-all -print-module-scope | FileCheck %s -check-prefixes=INL-MOD,INL-MOD-ALL +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -inline -print-after=inline -print-module-scope | FileCheck %s -check-prefix=INL-MOD +; RUN: opt < %s 2>&1 -disable-output \ +; RUN: -passes=inline -print-after=InlinerPass -print-module-scope | FileCheck %s -check-prefix=INL-MOD ; INL: IR Dump After {{Function Integration/Inlining|InlinerPass .*scc: .bar, foo}} ; INL: define void @bar() @@ -15,7 +23,7 @@ ; INL: IR Dump After {{Function Integration/Inlining|InlinerPass .*scc: .tester}} ; INL: define void @tester() ; INL-NEXT: call void @foo() -; INL: IR Dump After +; INL-ALL: IR Dump After ; INL-MOD: IR Dump After {{Function Integration/Inlining|InlinerPass .*scc: .bar, foo}} ; INL-MOD-NEXT: ModuleID = @@ -35,10 +43,10 @@ ; INL-MOD-NEXT: call void @bar() ; INL-MOD: define void @bar() ; INL-MOD-NEXT: call void @foo() -; INL-MOD: IR Dump After -; INL-MOD-NEXT: ModuleID = -; INL-MOD-NEXT: source_filename = -; INL-MOD-NOT: Printing Function +; INL-MOD-ALL: IR Dump After +; INL-MOD-ALL-NEXT: ModuleID = +; INL-MOD-ALL-NEXT: source_filename = +; INL-MOD-ALL-NOT: Printing Function define void @tester() noinline { call void @foo() Index: test/Transforms/Inline/null-function.ll =================================================================== --- test/Transforms/Inline/null-function.ll +++ test/Transforms/Inline/null-function.ll @@ -1,9 +1,12 @@ -; RUN: opt -print-before=always-inline -always-inline < %s -o /dev/null 2>&1 | FileCheck %s +; RUN: opt -print-before=always-inline -always-inline < %s -o /dev/null 2>&1 | FileCheck %s -check-prefixes=COMMON,LEGACY +; RUN: opt -print-before=AlwaysInlinerPass -passes=always-inline < %s -o /dev/null 2>&1 | FileCheck %s -check-prefix=COMMON define i32 @main() #0 { entry: ret i32 0 } -; CHECK: *** IR Dump Before Inliner for always_inline functions *** -; CHECK: Printing Function +; COMMON:*** IR Dump Before {{Inliner for always_inline functions|AlwaysInlinerPass}} *** +; COMMON: define i32 @main +; LEGACY: *** IR Dump Before Inliner for always_inline functions *** +; LEGACY: Printing Function Index: tools/bugpoint/bugpoint.cpp =================================================================== --- tools/bugpoint/bugpoint.cpp +++ tools/bugpoint/bugpoint.cpp @@ -63,7 +63,7 @@ // The AnalysesList is automatically populated with registered Passes by the // PassNameParser. // -static cl::list +static cl::list> PassList(cl::desc("Passes available:"), cl::ZeroOrMore); static cl::opt Index: tools/opt/opt.cpp =================================================================== --- tools/opt/opt.cpp +++ tools/opt/opt.cpp @@ -64,8 +64,8 @@ // The OptimizationList is automatically populated with registered Passes by the // PassNameParser. // -static cl::list -PassList(cl::desc("Optimizations available:")); +static cl::list> + PassList(cl::desc("Optimizations available:")); // This flag specifies a textual description of the optimization pass pipeline // to run over the module. This flag switches opt to use the new pass manager