https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/226773
A pass plugin's cl::opt is global, so opt, llc, and clang-linker-wrapper load plugins from a cl::opt callback while parsing argv, so that the plugin's options later on the command line are recognized. Accept `-load-pass-plugin=plugin.so,-opt1,-opt2`: the plugin loads after cl::ParseCommandLineOptions and its options are parsed after it loads. A plugin's options elsewhere on the command line are rejected. Rename PassPlugin::Load to PassPlugin::load, which accepts "<file>[,<option>...]". Polly's tests pass `-polly-*` options after `%loadNPMPolly`. When Polly is not linked into tools, also load LLVMPolly with -load, which registers its options while parsing. cl::callback will be removed to enable migration to TableGen based representation https://discourse.llvm.org/t/rfc-declare-library-command-line-options-in-tablegen-one-struct-per-library/91877/5 LLM-aided >From 2dac70bbc0b5f91f79a7ca096ceed50234b443a4 Mon Sep 17 00:00:00 2001 From: Fangrui Song <[email protected]> Date: Sun, 27 Sep 2026 00:02:07 -0700 Subject: [PATCH] [Plugins] Pass options to a pass plugin in -load-pass-plugin A pass plugin's cl::opt is global, so opt, llc, and clang-linker-wrapper load plugins from a cl::opt callback while parsing argv, so that the plugin's options later on the command line are recognized. Accept `-load-pass-plugin=plugin.so,-opt1,-opt2`: the plugin loads after cl::ParseCommandLineOptions and its options are parsed after it loads. A plugin's options elsewhere on the command line are rejected. Rename PassPlugin::Load to PassPlugin::load, which accepts "<file>[,<option>...]". Polly's tests pass `-polly-*` options after `%loadNPMPolly`. When Polly is not linked into tools, also load LLVMPolly with -load, which registers its options while parsing. cl::callback will be removed to enable migration to TableGen based representation https://discourse.llvm.org/t/rfc-declare-library-command-line-options-in-tablegen-one-struct-per-library/91877/5 LLM-aided --- clang/docs/InternalsManual.md | 2 +- clang/lib/Frontend/CompilerInstance.cpp | 2 +- .../linker-wrapper-llvm-help.c | 2 +- .../ClangLinkerWrapper.cpp | 18 +++++----- .../ExecuteCompilerInvocation.cpp | 2 +- llvm/docs/NewPassManager.md | 5 +-- llvm/docs/ReleaseNotes.md | 6 ++++ llvm/docs/WritingAnLLVMNewPMPass.md | 2 +- llvm/include/llvm/Plugins/PassPlugin.h | 9 ++--- llvm/lib/LTO/LTOBackend.cpp | 2 +- llvm/lib/Plugins/PassPlugin.cpp | 19 +++++++++- .../tut-simplify-cfg-blockaddress.ll | 6 ++-- .../SimplifyCFG/tut-simplify-cfg1.ll | 6 ++-- .../tut-simplify-cfg2-dead-block-order.ll | 6 ++-- .../SimplifyCFG/tut-simplify-cfg3-phis.ll | 6 ++-- ...ify-cfg4-multiple-duplicate-cfg-updates.ll | 6 ++-- ...t-simplify-cfg5-del-phis-for-dead-block.ll | 6 ++-- .../tut-simplify-cfg6-dead-self-loop.ll | 6 ++-- llvm/test/Feature/codegen-plugin-passes.mir | 2 +- llvm/test/Feature/codegen-plugin.ll | 4 +-- llvm/test/Feature/load_extension.ll | 2 +- llvm/test/lit.cfg.py | 35 +++++++++---------- llvm/tools/llc/lib/llcdriver.cpp | 23 ++++++------ llvm/tools/opt/optdriver.cpp | 24 +++++++------ .../PluginInlineAdvisorAnalysisTest.cpp | 2 +- .../PluginInlineOrderAnalysisTest.cpp | 2 +- llvm/unittests/Passes/Plugins/PluginsTest.cpp | 10 +++--- polly/test/lit.site.cfg.in | 7 ++-- 28 files changed, 125 insertions(+), 97 deletions(-) diff --git a/clang/docs/InternalsManual.md b/clang/docs/InternalsManual.md index 8d5549cb168be..53144018be55e 100644 --- a/clang/docs/InternalsManual.md +++ b/clang/docs/InternalsManual.md @@ -883,7 +883,7 @@ desired. void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(/*...*/) { // ... + for (auto &PluginFN : CodeGenOpts.PassPlugins) -+ if (auto PassPlugin = PassPlugin::Load(PluginFN)) ++ if (auto PassPlugin = PassPlugin::load(PluginFN)) + PassPlugin->registerPassBuilderCallbacks(PB); } ``` diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 87abcd38c1a92..28f61b7cff9f6 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1115,7 +1115,7 @@ void CompilerInstance::LoadRequestedPlugins() { // Load and store pass plugins for the back-end. for (const std::string &Path : getCodeGenOpts().PassPlugins) { - if (auto PassPlugin = llvm::PassPlugin::Load(Path)) { + if (auto PassPlugin = llvm::PassPlugin::load(Path)) { PassPlugins.emplace_back(std::make_unique<llvm::PassPlugin>(*PassPlugin)); } else { getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) diff --git a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-llvm-help.c b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-llvm-help.c index ffd1cf78bcd9a..a4a65a81bb892 100644 --- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-llvm-help.c +++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-llvm-help.c @@ -7,4 +7,4 @@ // Look for a few options supported only after -mllvm and --offload-opt. // CHECK: OPTIONS: // CHECK-DAG: --passes=<string> -// CHECK-DAG: --load-pass-plugin=<string> +// CHECK-DAG: --load-pass-plugin=<file[,option...]> diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index a5ebd7d2ad06b..33e10ba797691 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -91,9 +91,11 @@ static cl::opt<std::string> RemarksFormat( cl::desc("The format used for serializing remarks (default: YAML)"), cl::value_desc("format"), cl::init("yaml")); -static cl::list<std::string> - PassPlugins("load-pass-plugin", - cl::desc("Load passes from plugin library")); +static cl::list<std::string> PassPlugins( + "load-pass-plugin", + cl::desc("Load passes from plugin library. The plugin's options follow " + "its file name, separated by commas"), + cl::value_desc("file[,option...]")); static cl::opt<std::string> PassPipeline( "passes", @@ -1532,14 +1534,10 @@ int main(int Argc, char **Argv) { NewArgv.push_back(Arg->getValue()); for (const opt::Arg *Arg : Args.filtered(OPT_offload_opt_eq_minus)) NewArgv.push_back(Arg->getValue()); - SmallVector<PassPlugin, 1> PluginList; - PassPlugins.setCallback([&](const std::string &PluginPath) { - auto Plugin = PassPlugin::Load(PluginPath); - if (!Plugin) - reportFatalUsageError(Plugin.takeError()); - PluginList.emplace_back(Plugin.get()); - }); cl::ParseCommandLineOptions(NewArgv.size(), &NewArgv[0]); + for (const std::string &Spec : PassPlugins) + if (Error E = PassPlugin::load(Spec).takeError()) + reportFatalUsageError(std::move(E)); Verbose = Args.hasArg(OPT_verbose); DryRun = Args.hasArg(OPT_dry_run); diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 0396889fc57a4..aa06cc6ebb036 100644 --- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -182,7 +182,7 @@ bool executeCompilerInvocation(CompilerInstance *flang) { for (const std::string &path : flang->getInvocation().getCodeGenOpts().LLVMPassPlugins) { if (llvm::Expected<llvm::PassPlugin> passPlugin = - llvm::PassPlugin::Load(path)) { + llvm::PassPlugin::load(path)) { flang->addPassPlugin(std::make_unique<llvm::PassPlugin>(*passPlugin)); } else { unsigned diagID = flang->getDiagnostics().getCustomDiagID( diff --git a/llvm/docs/NewPassManager.md b/llvm/docs/NewPassManager.md index f9b819c2591c8..78b88baf0dff9 100644 --- a/llvm/docs/NewPassManager.md +++ b/llvm/docs/NewPassManager.md @@ -174,8 +174,9 @@ backend adding passes to various parts of the pipeline. Pass plugins can also add passes into default pipelines. Different tools have different ways of loading dynamic pass plugins. For example, `opt --load-pass-plugin=path/to/plugin.so` loads a pass plugin into `opt`. For -information on writing a pass plugin, see {doc}`WritingAnLLVMNewPMPass`. +-load-pass-plugin=path/to/plugin.so` loads a pass plugin into `opt`, and +`-load-pass-plugin=path/to/plugin.so,-opt1,-opt2` also passes the plugin's +options `-opt1` and `-opt2`. For information on writing a pass plugin, see {doc}`WritingAnLLVMNewPMPass`. ## Using Analyses diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 41b2fa83d380f..ed5af868daa8f 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -330,6 +330,12 @@ Makes programs 10x faster by doing Special New Thing. ### Changes to the LLVM tools +* `opt`, `llc`, and `clang-linker-wrapper` accept + `-load-pass-plugin=plugin.so,-opt1,-opt2`, which passes options to the pass + plugin after it is loaded. A plugin's options elsewhere on the command line + are no longer accepted. `PassPlugin::Load` is renamed to `PassPlugin::load`, + which accepts the same specification. + * llvm-mca no longer defaults -mcpu to "native" * llvm-rc now supports `/showIncludes` to report header and resource-file diff --git a/llvm/docs/WritingAnLLVMNewPMPass.md b/llvm/docs/WritingAnLLVMNewPMPass.md index 065c6b5bb0238..4ea4578ae53b9 100644 --- a/llvm/docs/WritingAnLLVMNewPMPass.md +++ b/llvm/docs/WritingAnLLVMNewPMPass.md @@ -273,7 +273,7 @@ To make `PassBuilder` aware of dynamically linked pass plugins: ```c++ // Load plugin dynamically. -auto Plugin = PassPlugin::Load(PathToPlugin); +auto Plugin = PassPlugin::load(PathToPlugin); if (!Plugin) report_error(); // Register plugin extensions in PassBuilder. diff --git a/llvm/include/llvm/Plugins/PassPlugin.h b/llvm/include/llvm/Plugins/PassPlugin.h index e8da9c51c0a85..0f1fbb21b74ae 100644 --- a/llvm/include/llvm/Plugins/PassPlugin.h +++ b/llvm/include/llvm/Plugins/PassPlugin.h @@ -70,12 +70,13 @@ struct PassPluginLibraryInfo { /// its interface defined by the \c PassPluginLibraryInfo it exposes. class PassPlugin { public: - /// Attempts to load a pass plugin from a given file. + /// Attempts to load a pass plugin specified as "<file>[,<option>...]", then + /// parses the options, which the plugin defines as cl::opt. /// /// \returns Returns an error if either the library cannot be found or loaded, - /// there is no public entry point, or the plugin implements the wrong API - /// version. - LLVM_ABI static Expected<PassPlugin> Load(const std::string &Filename); + /// there is no public entry point, the plugin implements the wrong API + /// version, or an option is invalid. + LLVM_ABI static Expected<PassPlugin> load(StringRef Spec); /// Get the filename of the loaded plugin. StringRef getFilename() const { return Filename; } diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index d9a6551139d37..0d253647ae46c 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -207,7 +207,7 @@ static void RegisterPassPlugins(const Config &Conf, PassBuilder &PB) { // Load requested pass plugins and let them register pass builder callbacks for (auto &PluginFN : Conf.PassPluginFilenames) { - auto PassPlugin = PassPlugin::Load(PluginFN); + auto PassPlugin = PassPlugin::load(PluginFN); if (!PassPlugin) reportFatalUsageError(PassPlugin.takeError()); PassPlugin->registerPassBuilderCallbacks(PB); diff --git a/llvm/lib/Plugins/PassPlugin.cpp b/llvm/lib/Plugins/PassPlugin.cpp index 84d55fc513b78..f56f2d7d1b767 100644 --- a/llvm/lib/Plugins/PassPlugin.cpp +++ b/llvm/lib/Plugins/PassPlugin.cpp @@ -7,13 +7,19 @@ //===----------------------------------------------------------------------===// #include "llvm/Plugins/PassPlugin.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Support/raw_ostream.h" #include <cstdint> using namespace llvm; -Expected<PassPlugin> PassPlugin::Load(const std::string &Filename) { +Expected<PassPlugin> PassPlugin::load(StringRef Spec) { + SmallVector<StringRef, 0> Parts; + Spec.split(Parts, ','); + std::string Filename = Parts[0].str(); std::string Error; auto Library = sys::DynamicLibrary::getPermanentLibrary(Filename.c_str(), &Error); @@ -45,5 +51,16 @@ Expected<PassPlugin> PassPlugin::Load(const std::string &Filename) { Twine(LLVM_PLUGIN_API_VERSION) + ".", inconvertibleErrorCode()); + if (Parts.size() == 1) + return P; + BumpPtrAllocator Alloc; + StringSaver Saver(Alloc); + SmallVector<const char *, 0> Argv = {Filename.c_str()}; + for (StringRef Option : drop_begin(Parts)) + Argv.push_back(Saver.save(Option).data()); + std::string Msg; + raw_string_ostream OS(Msg); + if (!cl::ParseCommandLineOptions(Argv.size(), Argv.data(), "", &OS)) + return createStringError(StringRef(Msg).trim()); return P; } diff --git a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg-blockaddress.ll b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg-blockaddress.ll index f9cf6472a4c31..ef0ca4d6be37c 100644 --- a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg-blockaddress.ll +++ b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg-blockaddress.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v1 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v2 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v3 -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v1 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v2 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v3 -passes=tut-simplifycfg -S < %s | FileCheck %s define ptr @simp1(i32 %x) { ; CHECK-LABEL: @simp1( diff --git a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg1.ll b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg1.ll index 35dac1dba927b..9ea6661010c19 100644 --- a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg1.ll +++ b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg1.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v1 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v2 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v3 -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v1 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v2 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v3 -passes=tut-simplifycfg -S < %s | FileCheck %s define i32 @simp1() { ; CHECK-LABEL: @simp1( diff --git a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg2-dead-block-order.ll b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg2-dead-block-order.ll index aa078179d2e3b..d0e2e95ff79c8 100644 --- a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg2-dead-block-order.ll +++ b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg2-dead-block-order.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v1 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v2 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v3 -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v1 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v2 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v3 -passes=tut-simplifycfg -S < %s | FileCheck %s define i32 @remove_dead_blocks() { ; CHECK-LABEL: @remove_dead_blocks( diff --git a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg3-phis.ll b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg3-phis.ll index a4474d09df320..e50ba55f74bde 100644 --- a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg3-phis.ll +++ b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg3-phis.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v1 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v2 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v3 -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v1 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v2 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v3 -passes=tut-simplifycfg -S < %s | FileCheck %s define i32 @phi_cond_branch_eliminated() { ; CHECK-LABEL: @phi_cond_branch_eliminated( diff --git a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg4-multiple-duplicate-cfg-updates.ll b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg4-multiple-duplicate-cfg-updates.ll index 13ccb8b10dc41..5bae31e62e958 100644 --- a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg4-multiple-duplicate-cfg-updates.ll +++ b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg4-multiple-duplicate-cfg-updates.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v1 < %s -S -verify-dom-info | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v2 < %s -S -verify-dom-info | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v3 < %s -S -verify-dom-info | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v1 -passes=tut-simplifycfg < %s -S -verify-dom-info | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v2 -passes=tut-simplifycfg < %s -S -verify-dom-info | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v3 -passes=tut-simplifycfg < %s -S -verify-dom-info | FileCheck %s ; Check that we do not crash when we remove edges multiple times in ; the DomTreeUpdater. diff --git a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg5-del-phis-for-dead-block.ll b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg5-del-phis-for-dead-block.ll index 1f1c1016b3fc8..d0109a7537ead 100644 --- a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg5-del-phis-for-dead-block.ll +++ b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg5-del-phis-for-dead-block.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v1 < %s -S -verify-dom-info | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v2 < %s -S -verify-dom-info | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v3 < %s -S -verify-dom-info | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v1 -passes=tut-simplifycfg < %s -S -verify-dom-info | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v2 -passes=tut-simplifycfg < %s -S -verify-dom-info | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v3 -passes=tut-simplifycfg < %s -S -verify-dom-info | FileCheck %s define void @test() { ; CHECK-LABEL: @test( diff --git a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg6-dead-self-loop.ll b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg6-dead-self-loop.ll index e40076e6de3aa..ba190cdf10d07 100644 --- a/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg6-dead-self-loop.ll +++ b/llvm/test/Examples/IRTransforms/SimplifyCFG/tut-simplify-cfg6-dead-self-loop.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v1 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v2 -S < %s | FileCheck %s -; RUN: opt %loadexampleirtransforms -passes=tut-simplifycfg -tut-simplifycfg-version=v3 -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v1 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v2 -passes=tut-simplifycfg -S < %s | FileCheck %s +; RUN: opt %{loadexampleirtransforms,}-tut-simplifycfg-version=v3 -passes=tut-simplifycfg -S < %s | FileCheck %s define i32 @simp1() { ; CHECK-LABEL: @simp1( diff --git a/llvm/test/Feature/codegen-plugin-passes.mir b/llvm/test/Feature/codegen-plugin-passes.mir index 4b4ac5c54e59c..2de83968eeb79 100644 --- a/llvm/test/Feature/codegen-plugin-passes.mir +++ b/llvm/test/Feature/codegen-plugin-passes.mir @@ -4,7 +4,7 @@ # UNSUPPORTED: target={{.*windows.*}} # Plugins are currently broken on AIX, at least in the CI. # XFAIL: target={{.*}}-aix{{.*}} -# RUN: llc -mtriple=x86_64-- %loadnewpmbye -passes=goodbye -wave-goodbye %s -o /dev/null 2>&1 | FileCheck %s +# RUN: llc -mtriple=x86_64-- %{loadnewpmbye,}-wave-goodbye -passes=goodbye %s -o /dev/null 2>&1 | FileCheck %s # RUN: llc -mtriple=x86_64-- %loadnewpmbye -passes=goodbye --print-pipeline-passes -filetype=null %s | FileCheck %s --check-prefix=PIPELINE # CHECK: Bye: somefunk diff --git a/llvm/test/Feature/codegen-plugin.ll b/llvm/test/Feature/codegen-plugin.ll index cd36ef14d8ec3..74d4e1de3cc05 100644 --- a/llvm/test/Feature/codegen-plugin.ll +++ b/llvm/test/Feature/codegen-plugin.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86-registered-target ; RUN: llc < %s %loadnewpmbye | FileCheck %s --check-prefix=CHECK-ASM -; RUN: llc < %s %loadnewpmbye -last-words | FileCheck %s --check-prefix=CHECK-ACTIVE -; RUN: not llc < %s %loadnewpmbye -last-words -filetype=obj 2>&1 | FileCheck %s --check-prefix=CHECK-ERR +; RUN: llc < %s %{loadnewpmbye,}-last-words | FileCheck %s --check-prefix=CHECK-ACTIVE +; RUN: not llc < %s %{loadnewpmbye,}-last-words -filetype=obj 2>&1 | FileCheck %s --check-prefix=CHECK-ERR ; REQUIRES: plugins, examples ; UNSUPPORTED: target={{.*windows.*}} ; Plugins are currently broken on AIX, at least in the CI. diff --git a/llvm/test/Feature/load_extension.ll b/llvm/test/Feature/load_extension.ll index 6f99e99cb6345..6ceb9c2534f01 100644 --- a/llvm/test/Feature/load_extension.ll +++ b/llvm/test/Feature/load_extension.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86-registered-target ; RUN: opt %s %loadnewpmbye %loadbye -passes="goodbye" -wave-goodbye -disable-output 2>&1 | FileCheck %s -; RUN: opt %s %loadnewpmbye -passes="goodbye" -wave-goodbye -disable-output 2>&1 | FileCheck %s +; RUN: opt %s %{loadnewpmbye,}-wave-goodbye -passes="goodbye" -disable-output 2>&1 | FileCheck %s ; RUN: opt -module-summary %s -o %t.o ; RUN: llvm-lto2 run %t.o %loadbye %loadnewpmbye -wave-goodbye -o %t -r %t.o,somefunk,plx -r %t.o,junk,plx 2>&1 | FileCheck %s ; RUN: llvm-lto2 run %t.o %loadbye %loadnewpmbye -opt-pipeline="goodbye" -wave-goodbye -o %t -r %t.o,somefunk,plx -r %t.o,junk,plx 2>&1 | FileCheck %s diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py index d8913b1fbdc87..4758ed12a0b7c 100644 --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -536,7 +536,6 @@ def enable_ptxas(ptxas_executable): if config.linked_bye_extension: config.substitutions.append(("%llvmcheckext", "CHECK-EXT")) config.substitutions.append(("%loadbye", "")) - config.substitutions.append(("%loadnewpmbye", "")) else: config.substitutions.append(("%llvmcheckext", "CHECK-NOEXT")) config.substitutions.append( @@ -545,26 +544,24 @@ def enable_ptxas(ptxas_executable): "-load={}/Bye{}".format(config.llvm_shlib_dir, config.llvm_shlib_ext), ) ) - config.substitutions.append( - ( - "%loadnewpmbye", - "-load-pass-plugin={}/Bye{}".format( - config.llvm_shlib_dir, config.llvm_shlib_ext - ), - ) - ) -if config.linked_exampleirtransforms_extension: - config.substitutions.append(("%loadexampleirtransforms", "")) -else: - config.substitutions.append( - ( - "%loadexampleirtransforms", - "-load-pass-plugin={}/ExampleIRTransforms{}".format( - config.llvm_shlib_dir, config.llvm_shlib_ext - ), +# %{loadX,} is followed by one option of the extension, e.g. +# %{loadnewpmbye,}-wave-goodbye. +for name, lib, linked in [ + ("loadnewpmbye", "Bye", config.linked_bye_extension), + ( + "loadexampleirtransforms", + "ExampleIRTransforms", + config.linked_exampleirtransforms_extension, + ), +]: + load = "" + if not linked: + load = "-load-pass-plugin={}/{}{}".format( + config.llvm_shlib_dir, lib, config.llvm_shlib_ext ) - ) + config.substitutions.append(("%{" + name + ",}", load and load + ",")) + config.substitutions.append(("%" + name, load)) # Static libraries are not built if BUILD_SHARED_LIBS is ON. if not config.build_shared_libs and not config.link_llvm_dylib: diff --git a/llvm/tools/llc/lib/llcdriver.cpp b/llvm/tools/llc/lib/llcdriver.cpp index 7f0ee013cd947..b205743d15b80 100644 --- a/llvm/tools/llc/lib/llcdriver.cpp +++ b/llvm/tools/llc/lib/llcdriver.cpp @@ -213,8 +213,11 @@ static cl::opt<std::string> RemarksFormat( cl::desc("The format used for serializing remarks (default: YAML)"), cl::value_desc("format"), cl::init("yaml")); -static cl::list<std::string> PassPlugins("load-pass-plugin", - cl::desc("Load plugin library")); +static cl::list<std::string> PassPlugins( + "load-pass-plugin", + cl::desc("Load passes from plugin library. The plugin's options follow " + "its file name, separated by commas"), + cl::value_desc("file[,option...]")); static cl::opt<bool> EnableNewPassManager( "enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false)); @@ -394,14 +397,6 @@ extern "C" int llcMain(int argc, char **argv) { // Initialize debugging passes. initializeScavengerTestPass(*Registry); - SmallVector<PassPlugin, 1> PluginList; - PassPlugins.setCallback([&](const std::string &PluginPath) { - auto Plugin = PassPlugin::Load(PluginPath); - if (!Plugin) - reportFatalUsageError(Plugin.takeError()); - PluginList.emplace_back(Plugin.get()); - }); - // Register the Target and CPU printer for --version. cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU); // Register the target printer for --version. @@ -409,6 +404,14 @@ extern "C" int llcMain(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); + SmallVector<PassPlugin, 1> PluginList; + for (const std::string &Spec : PassPlugins) { + auto Plugin = PassPlugin::load(Spec); + if (!Plugin) + reportFatalUsageError(Plugin.takeError()); + PluginList.emplace_back(Plugin.get()); + } + if (!PassPipeline.empty() && !getRunPassNames().empty()) { errs() << "The `llc -run-pass=...` syntax for the new pass manager is " "not supported, please use `llc -passes=<pipeline>` (or the `-p` " diff --git a/llvm/tools/opt/optdriver.cpp b/llvm/tools/opt/optdriver.cpp index 46c6833515e18..a9456ef940dee 100644 --- a/llvm/tools/opt/optdriver.cpp +++ b/llvm/tools/opt/optdriver.cpp @@ -281,9 +281,11 @@ static cl::opt<std::string> RemarksFormat( cl::desc("The format used for serializing remarks (default: YAML)"), cl::value_desc("format"), cl::init("yaml")); -static cl::list<std::string> - PassPlugins("load-pass-plugin", - cl::desc("Load passes from plugin library")); +static cl::list<std::string> PassPlugins( + "load-pass-plugin", + cl::desc("Load passes from plugin library. The plugin's options follow " + "its file name, separated by commas"), + cl::value_desc("file[,option...]")); //===----------------------------------------------------------------------===// // CodeGen-related helper functions. @@ -443,20 +445,20 @@ optMain(int argc, char **argv, initializeReplaceWithVeclibLegacyPass(Registry); initializeJMCInstrumenterPass(Registry); - SmallVector<PassPlugin, 1> PluginList; - PassPlugins.setCallback([&](const std::string &PluginPath) { - auto Plugin = PassPlugin::Load(PluginPath); - if (!Plugin) - reportFatalUsageError(Plugin.takeError()); - PluginList.emplace_back(Plugin.get()); - }); - // Register the Target and CPU printer for --version. cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU); cl::ParseCommandLineOptions( argc, argv, "llvm .bc -> .bc modular optimizer and analysis printer\n"); + SmallVector<PassPlugin, 1> PluginList; + for (const std::string &Spec : PassPlugins) { + auto Plugin = PassPlugin::load(Spec); + if (!Plugin) + reportFatalUsageError(Plugin.takeError()); + PluginList.emplace_back(Plugin.get()); + } + LLVMContext Context; // TODO: remove shouldForceLegacyPM(). diff --git a/llvm/unittests/Analysis/PluginInlineAdvisorAnalysisTest.cpp b/llvm/unittests/Analysis/PluginInlineAdvisorAnalysisTest.cpp index 61ab1820373c3..34c6dce215f20 100644 --- a/llvm/unittests/Analysis/PluginInlineAdvisorAnalysisTest.cpp +++ b/llvm/unittests/Analysis/PluginInlineAdvisorAnalysisTest.cpp @@ -63,7 +63,7 @@ struct CompilerInstance { void setupPlugin() { auto PluginPath = libPath(); ASSERT_NE("", PluginPath); - Expected<PassPlugin> Plugin = PassPlugin::Load(PluginPath); + Expected<PassPlugin> Plugin = PassPlugin::load(PluginPath); ASSERT_TRUE(!!Plugin) << "Plugin path: " << PluginPath; Plugin->registerPassBuilderCallbacks(PB); } diff --git a/llvm/unittests/Analysis/PluginInlineOrderAnalysisTest.cpp b/llvm/unittests/Analysis/PluginInlineOrderAnalysisTest.cpp index e9e839904a2e6..f5431cd7fdc85 100644 --- a/llvm/unittests/Analysis/PluginInlineOrderAnalysisTest.cpp +++ b/llvm/unittests/Analysis/PluginInlineOrderAnalysisTest.cpp @@ -45,7 +45,7 @@ struct CompilerInstance { void setupPlugin() { auto PluginPath = libPath(); ASSERT_NE("", PluginPath); - Expected<PassPlugin> Plugin = PassPlugin::Load(PluginPath); + Expected<PassPlugin> Plugin = PassPlugin::load(PluginPath); ASSERT_TRUE(!!Plugin) << "Plugin path: " << PluginPath; Plugin->registerPassBuilderCallbacks(PB); } diff --git a/llvm/unittests/Passes/Plugins/PluginsTest.cpp b/llvm/unittests/Passes/Plugins/PluginsTest.cpp index d4d519eb52a53..c2ef01c14dc73 100644 --- a/llvm/unittests/Passes/Plugins/PluginsTest.cpp +++ b/llvm/unittests/Passes/Plugins/PluginsTest.cpp @@ -48,7 +48,7 @@ TEST(PluginsTests, LoadPlugin) { auto PluginPath = LibPath(); ASSERT_NE("", PluginPath); - Expected<PassPlugin> Plugin = PassPlugin::Load(PluginPath); + Expected<PassPlugin> Plugin = PassPlugin::load(PluginPath); ASSERT_TRUE(!!Plugin) << "Plugin path: " << PluginPath; ASSERT_EQ(TEST_PLUGIN_NAME, Plugin->getPluginName()); @@ -76,18 +76,18 @@ TEST(PluginsTests, LoadMultiplePlugins) { ASSERT_NE("", DoublerPluginPath); ASSERT_NE("", TestPluginPath); - Expected<PassPlugin> DoublerPlugin1 = PassPlugin::Load(DoublerPluginPath); + Expected<PassPlugin> DoublerPlugin1 = PassPlugin::load(DoublerPluginPath); ASSERT_TRUE(!!DoublerPlugin1) << "Plugin path: " << DoublerPlugin1->getFilename(); - Expected<PassPlugin> TestPlugin = PassPlugin::Load(TestPluginPath); + Expected<PassPlugin> TestPlugin = PassPlugin::load(TestPluginPath); ASSERT_TRUE(!!TestPlugin) << "Plugin path: " << TestPlugin->getFilename(); // If llvmGetPassPluginInfo is resolved as a weak symbol taking into account - // all loaded symbols, the second call to PassPlugin::Load will actually + // all loaded symbols, the second call to PassPlugin::load will actually // return the llvmGetPassPluginInfo from the most recently loaded plugin, in // this case TestPlugin. - Expected<PassPlugin> DoublerPlugin2 = PassPlugin::Load(DoublerPluginPath); + Expected<PassPlugin> DoublerPlugin2 = PassPlugin::load(DoublerPluginPath); ASSERT_TRUE(!!DoublerPlugin2) << "Plugin path: " << DoublerPlugin2->getFilename(); diff --git a/polly/test/lit.site.cfg.in b/polly/test/lit.site.cfg.in index 56448f27ba6dc..29c41671f053c 100644 --- a/polly/test/lit.site.cfg.in +++ b/polly/test/lit.site.cfg.in @@ -40,8 +40,11 @@ if config.llvm_polly_link_into_tools == '' or \ config.llvm_polly_link_into_tools.lower() == 'false' or \ config.llvm_polly_link_into_tools.lower() == 'notfound' or \ config.llvm_polly_link_into_tools.lower() == 'llvm_polly_link_into_tools-notfound': - config.substitutions.append(('%loadNPMPolly', '-load-pass-plugin ' - + config.polly_lib_dir + '/LLVMPolly@LLVM_SHLIBEXT@' + # -load registers Polly's options while opt parses the -polly-* options + # that follow; -load-pass-plugin registers its passes after parsing. + pollyLib = config.polly_lib_dir + '/LLVMPolly@LLVM_SHLIBEXT@' + config.substitutions.append(('%loadNPMPolly', '-load=' + pollyLib + + ' -load-pass-plugin=' + pollyLib + commonOpts )) else: config.substitutions.append(('%loadNPMPolly', commonOpts )) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
