diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -41,7 +41,7 @@ #include "llvm/MC/TargetRegistry.h" #include "llvm/Object/OffloadBinary.h" #include "llvm/Passes/PassBuilder.h" -#include "llvm/Passes/PassPlugin.h" +#include "llvm/Passes/PassPluginRegistry.h" #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/BuryPointer.h" #include "llvm/Support/CommandLine.h" @@ -800,15 +800,9 @@ CodeGenOpts.DIBugsReportFilePath); Debugify.registerCallbacks(PIC); } - // Attempt to load pass plugins and register their callbacks with PB. - for (auto &PluginFN : CodeGenOpts.PassPlugins) { - auto PassPlugin = PassPlugin::Load(PluginFN); - if (PassPlugin) { - PassPlugin->registerPassBuilderCallbacks(PB); - } else { - Diags.Report(diag::err_fe_unable_to_load_plugin) - << PluginFN << toString(PassPlugin.takeError()); - } + // Register loaded pass plugins' callbacks with PB. + for (auto const &Plugin : PassPluginRegistry::getPlugins()) { + Plugin.registerPassBuilderCallbacks(PB); } #define HANDLE_EXTENSION(Ext) \ get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB); diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt --- a/clang/lib/Frontend/CMakeLists.txt +++ b/clang/lib/Frontend/CMakeLists.txt @@ -4,6 +4,7 @@ BitReader BitstreamReader Option + Passes ProfileData Support ) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -39,6 +39,8 @@ #include "clang/Serialization/InMemoryModuleCache.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Passes/PassPluginRegistry.h" #include "llvm/Support/BuryPointer.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Errc.h" @@ -1096,6 +1098,17 @@ << Path << Error; } + // Load the pass plugins right away, so that they can register their options. + for (auto &PluginPath : getCodeGenOpts().PassPlugins) { + auto LoadedPassPlugin = llvm::PassPlugin::Load(PluginPath); + if (LoadedPassPlugin) { + llvm::PassPluginRegistry::addPlugin(std::move(LoadedPassPlugin.get())); + } else { + getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) + << PluginPath << toString(LoadedPassPlugin.takeError()); + } + } + // Check if any of the loaded plugins replaces the main AST action for (const FrontendPluginRegistry::entry &Plugin : FrontendPluginRegistry::entries()) { diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -145,7 +145,6 @@ llvm::SmallVector versionDefinitions; llvm::SmallVector auxiliaryList; llvm::SmallVector filterList; - llvm::SmallVector passPlugins; llvm::SmallVector searchPaths; llvm::SmallVector symbolOrderingFile; llvm::SmallVector thinLTOModulesToCompile; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -50,6 +50,8 @@ #include "llvm/Config/llvm-config.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/Archive.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Passes/PassPluginRegistry.h" #include "llvm/Remarks/HotnessThresholdParser.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" @@ -1342,7 +1344,15 @@ error(arg->getSpelling() + ": unknown plugin option '" + arg->getValue() + "'"); - config->passPlugins = args::getStrings(args, OPT_load_pass_plugins); + for (StringRef pluginPath : args::getStrings(args, OPT_load_pass_plugins)) { + auto plugin = PassPlugin::Load(std::string(pluginPath)); + if (!plugin) { + lld::errs() << "Failed to load passes from '" << pluginPath + << "'. Request ignored.\n"; + continue; + } + PassPluginRegistry::addPlugin(std::move(plugin.get())); + } // Parse -mllvm options. for (auto *arg : args.filtered(OPT_mllvm)) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -146,8 +146,6 @@ c.StatsFile = std::string(config->optStatsFilename); c.SampleProfile = std::string(config->ltoSampleProfile); - for (StringRef pluginFn : config->passPlugins) - c.PassPlugins.push_back(std::string(pluginFn)); c.DebugPassManager = config->ltoDebugPassManager; c.DwoDir = std::string(config->dwoDir); diff --git a/lld/test/ELF/lto/ltopasses-extension.ll b/lld/test/ELF/lto/ltopasses-extension.ll --- a/lld/test/ELF/lto/ltopasses-extension.ll +++ b/lld/test/ELF/lto/ltopasses-extension.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86, plugins, examples ; UNSUPPORTED: windows ; RUN: opt -module-summary %s -o %t.o -; RUN: ld.lld -%loadnewpmbye --lto-newpm-passes="goodbye" -mllvm=%loadbye -mllvm=-wave-goodbye %t.o -o /dev/null 2>&1 | FileCheck %s +; RUN: ld.lld -%loadnewpmbye --lto-newpm-passes="goodbye" -mllvm=-wave-goodbye %t.o -o /dev/null 2>&1 | FileCheck %s ; CHECK: Bye target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py --- a/lld/test/lit.cfg.py +++ b/lld/test/lit.cfg.py @@ -126,12 +126,8 @@ config.available_features.add('examples') if config.linked_bye_extension: - config.substitutions.append(('%loadbye', '')) config.substitutions.append(('%loadnewpmbye', '')) else: - config.substitutions.append(('%loadbye', - '-load={}/Bye{}'.format(config.llvm_shlib_dir, - config.llvm_shlib_ext))) config.substitutions.append(('%loadnewpmbye', '-load-pass-plugin={}/Bye{}' .format(config.llvm_shlib_dir, diff --git a/llvm/include/llvm/LTO/Config.h b/llvm/include/llvm/LTO/Config.h --- a/llvm/include/llvm/LTO/Config.h +++ b/llvm/include/llvm/LTO/Config.h @@ -47,7 +47,6 @@ std::string CPU; TargetOptions Options; std::vector MAttrs; - std::vector PassPlugins; /// For adding passes that run right before codegen. std::function PreCodeGenPassesHook; Optional RelocModel = Reloc::PIC_; diff --git a/llvm/include/llvm/Passes/PassPluginLoader.h b/llvm/include/llvm/Passes/PassPluginLoader.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Passes/PassPluginLoader.h @@ -0,0 +1,32 @@ +//===-- llvm/Passes/PassPluginLoader.h - Pass Plugin Loader -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// + +#ifndef LLVM_PASSES_PASSPLUGINLOADER_H +#define LLVM_PASSES_PASSPLUGINLOADER_H + +#ifndef DONT_GET_PASS_PLUGIN_LOADER_OPTION +#include "llvm/Support/CommandLine.h" +#endif + +#include + +namespace llvm { +struct PassPluginLoader { + void operator=(const std::string &Filename); +}; +#ifndef DONT_GET_PASS_PLUGIN_LOADER_OPTION +// This causes operator= above to be invoked for every -load option. +static cl::opt> + PassPlugins("load-pass-plugin", cl::ZeroOrMore, + cl::value_desc("passpluginfilename"), + cl::desc("Load the specified pass plugin")); +#endif +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Passes/PassPluginRegistry.h b/llvm/include/llvm/Passes/PassPluginRegistry.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Passes/PassPluginRegistry.h @@ -0,0 +1,33 @@ +//===- llvm/Passes/PassPluginRegistry.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Registry of pass plugins used by opt/clang +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PASSES_PASSPLUGINREGISTRY_H +#define LLVM_PASSES_PASSPLUGINREGISTRY_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Support/Registry.h" + +namespace llvm { + +/// The pass plugin registry. +struct PassPluginRegistry { + static const SmallVector &getPlugins(); + static void addPlugin(PassPlugin &&PP); + +private: + SmallVector Plugins; +}; + +} // namespace llvm + +#endif // LLVM_PASSES_PASSPLUGINREGISTRY_H diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -29,7 +29,7 @@ #include "llvm/MC/TargetRegistry.h" #include "llvm/Object/ModuleSymbolTable.h" #include "llvm/Passes/PassBuilder.h" -#include "llvm/Passes/PassPlugin.h" +#include "llvm/Passes/PassPluginRegistry.h" #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" @@ -180,22 +180,14 @@ llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); #include "llvm/Support/Extension.def" -static void RegisterPassPlugins(ArrayRef PassPlugins, - PassBuilder &PB) { +static void RegisterPassPlugins(PassBuilder &PB) { #define HANDLE_EXTENSION(Ext) \ get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB); #include "llvm/Support/Extension.def" - // Load requested pass plugins and let them register pass builder callbacks - for (auto &PluginFN : PassPlugins) { - auto PassPlugin = PassPlugin::Load(PluginFN); - if (!PassPlugin) { - errs() << "Failed to load passes from '" << PluginFN - << "'. Request ignored.\n"; - continue; - } - - PassPlugin->registerPassBuilderCallbacks(PB); + // Let loaded pass plugins register pass builder callbacks + for (auto const &Plugin : PassPluginRegistry::getPlugins()) { + Plugin.registerPassBuilderCallbacks(PB); } } @@ -260,7 +252,7 @@ SI.registerCallbacks(PIC, &FAM); PassBuilder PB(TM, Conf.PTO, PGOOpt, &PIC); - RegisterPassPlugins(Conf.PassPlugins, PB); + RegisterPassPlugins(PB); std::unique_ptr TLII( new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()))); diff --git a/llvm/lib/Passes/CMakeLists.txt b/llvm/lib/Passes/CMakeLists.txt --- a/llvm/lib/Passes/CMakeLists.txt +++ b/llvm/lib/Passes/CMakeLists.txt @@ -4,6 +4,8 @@ PassBuilderBindings.cpp PassBuilderPipelines.cpp PassPlugin.cpp + PassPluginLoader.cpp + PassPluginRegistry.cpp StandardInstrumentations.cpp ADDITIONAL_HEADER_DIRS diff --git a/llvm/lib/Passes/PassPluginLoader.cpp b/llvm/lib/Passes/PassPluginLoader.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Passes/PassPluginLoader.cpp @@ -0,0 +1,32 @@ +//===-- PassPluginLoader.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#define DONT_GET_PASS_PLUGIN_LOADER_OPTION +#include "llvm/Passes/PassPluginLoader.h" +#include "llvm/Passes/PassPluginRegistry.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { +ManagedStatic> PluginsLock; +} // namespace + +void PassPluginLoader::operator=(const std::string &Filename) { + sys::SmartScopedLock Lock(*PluginsLock); + auto PassPlugin = PassPlugin::Load(Filename); + + if (!PassPlugin) { + errs() << "Failed to load passes from '" << Filename + << "'. Request ignored.\n"; + return; + } + PassPluginRegistry::addPlugin(std::move(PassPlugin.get())); +} diff --git a/llvm/lib/Passes/PassPluginRegistry.cpp b/llvm/lib/Passes/PassPluginRegistry.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Passes/PassPluginRegistry.cpp @@ -0,0 +1,23 @@ +//===- lib/Passes/PassPluginRegistry.cpp - Pass Plugins registry ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Passes/PassPluginRegistry.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; + +static ManagedStatic PassPluginRegistryObj; + +const SmallVector &PassPluginRegistry::getPlugins() { + return PassPluginRegistryObj->Plugins; +} + +void PassPluginRegistry::addPlugin(PassPlugin &&PP) { + PassPluginRegistryObj->Plugins.push_back(std::move(PP)); +} diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp --- a/llvm/tools/llvm-lto2/llvm-lto2.cpp +++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -20,7 +20,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/LTO.h" -#include "llvm/Passes/PassPlugin.h" +#include "llvm/Passes/PassPluginLoader.h" #include "llvm/Remarks/HotnessThresholdParser.h" #include "llvm/Support/Caching.h" #include "llvm/Support/CommandLine.h" @@ -179,10 +179,6 @@ static cl::opt StatsFile("stats-file", cl::desc("Filename to write statistics to")); -static cl::list - PassPlugins("load-pass-plugin", - cl::desc("Load passes from plugin library")); - static cl::opt EnableFreestanding( "lto-freestanding", cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"), @@ -305,8 +301,6 @@ Conf.OptLevel = OptLevel - '0'; Conf.Freestanding = EnableFreestanding; - for (auto &PluginFN : PassPlugins) - Conf.PassPlugins.push_back(PluginFN); switch (CGOptLevel) { case '0': Conf.CGOptLevel = CodeGenOpt::None; diff --git a/llvm/tools/opt/NewPMDriver.h b/llvm/tools/opt/NewPMDriver.h --- a/llvm/tools/opt/NewPMDriver.h +++ b/llvm/tools/opt/NewPMDriver.h @@ -25,7 +25,6 @@ namespace llvm { class StringRef; class Module; -class PassPlugin; class TargetMachine; class ToolOutputFile; class TargetLibraryInfoImpl; @@ -72,8 +71,7 @@ TargetLibraryInfoImpl *TLII, ToolOutputFile *Out, ToolOutputFile *ThinLinkOut, ToolOutputFile *OptRemarkFile, StringRef PassPipeline, ArrayRef PassInfos, - ArrayRef PassPlugins, opt_tool::OutputKind OK, - opt_tool::VerifierKind VK, + opt_tool::OutputKind OK, opt_tool::VerifierKind VK, bool ShouldPreserveAssemblyUseListOrder, bool ShouldPreserveBitcodeUseListOrder, bool EmitSummaryIndex, bool EmitModuleHash, diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp --- a/llvm/tools/opt/NewPMDriver.cpp +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -27,7 +27,7 @@ #include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" #include "llvm/Passes/PassBuilder.h" -#include "llvm/Passes/PassPlugin.h" +#include "llvm/Passes/PassPluginRegistry.h" #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ToolOutputFile.h" @@ -288,7 +288,6 @@ ToolOutputFile *ThinLTOLinkOut, ToolOutputFile *OptRemarkFile, StringRef PassPipeline, ArrayRef Passes, - ArrayRef PassPlugins, OutputKind OK, VerifierKind VK, bool ShouldPreserveAssemblyUseListOrder, bool ShouldPreserveBitcodeUseListOrder, @@ -373,7 +372,7 @@ registerEPCallbacks(PB); // For any loaded plugins, let them register pass builder callbacks. - for (auto &PassPlugin : PassPlugins) + for (auto &PassPlugin : PassPluginRegistry::getPlugins()) PassPlugin.registerPassBuilderCallbacks(PB); PB.registerPipelineParsingCallback( diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp --- a/llvm/tools/opt/opt.cpp +++ b/llvm/tools/opt/opt.cpp @@ -39,7 +39,8 @@ #include "llvm/LinkAllPasses.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/MC/TargetRegistry.h" -#include "llvm/Passes/PassPlugin.h" +#include "llvm/Passes/PassPluginLoader.h" +#include "llvm/Passes/PassPluginRegistry.h" #include "llvm/Remarks/HotnessThresholdParser.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" @@ -278,10 +279,6 @@ cl::desc("The format used for serializing remarks (default: YAML)"), cl::value_desc("format"), cl::init("yaml")); -static cl::list - PassPlugins("load-pass-plugin", - cl::desc("Load passes from plugin library")); - namespace llvm { cl::opt PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden, @@ -533,17 +530,6 @@ initializeExampleIRTransforms(Registry); #endif - SmallVector PluginList; - PassPlugins.setCallback([&](const std::string &PluginPath) { - auto Plugin = PassPlugin::Load(PluginPath); - if (!Plugin) { - errs() << "Failed to load passes from '" << PluginPath - << "'. Request ignored.\n"; - return; - } - PluginList.emplace_back(Plugin.get()); - }); - cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .bc modular optimizer and analysis printer\n"); @@ -556,7 +542,7 @@ const bool UseNPM = (EnableNewPassManager && !shouldForceLegacyPM()) || PassPipeline.getNumOccurrences() > 0; - if (!UseNPM && PluginList.size()) { + if (!UseNPM && PassPluginRegistry::getPlugins().size()) { errs() << argv[0] << ": " << PassPlugins.ArgStr << " specified with legacy PM.\n"; return 1; @@ -781,7 +767,7 @@ // layer. return runPassPipeline(argv[0], *M, TM.get(), &TLII, Out.get(), ThinLinkOut.get(), RemarksFile.get(), Pipeline, - Passes, PluginList, OK, VK, PreserveAssemblyUseListOrder, + Passes, OK, VK, PreserveAssemblyUseListOrder, PreserveBitcodeUseListOrder, EmitSummaryIndex, EmitModuleHash, EnableDebugify, VerifyDebugInfoPreserve)