[llvm] r329273 - [Plugins] Add a slim plugin API to work together with the new PM

Philip Pfaffe via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 5 04:29:37 PDT 2018


Author: pfaffe
Date: Thu Apr  5 04:29:37 2018
New Revision: 329273

URL: http://llvm.org/viewvc/llvm-project?rev=329273&view=rev
Log:
[Plugins] Add a slim plugin API to work together with the new PM

Summary:
Add a new plugin API. This closes the gap between pass registration and out-of-tree passes for the new PassManager.

Unlike with the existing API, interaction with a plugin is always
initiated from the tools perspective. I.e., when a plugin is loaded, it
resolves and calls a well-known symbol `llvmGetPassPluginInfo` to obtain
details about the plugin. The fundamental motivation is to get rid of as
many global constructors as possible.  The API exposed by the plugin
info is kept intentionally minimal.

Reviewers: chandlerc

Reviewed By: chandlerc

Subscribers: bollu, grosser, lksbhm, mgorny, llvm-commits

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

Added:
    llvm/trunk/include/llvm/Passes/PassPlugin.h
    llvm/trunk/lib/Passes/PassPlugin.cpp
    llvm/trunk/unittests/Passes/
    llvm/trunk/unittests/Passes/CMakeLists.txt
    llvm/trunk/unittests/Passes/PluginsTest.cpp
    llvm/trunk/unittests/Passes/TestPlugin.cxx
    llvm/trunk/unittests/Passes/TestPlugin.h
Modified:
    llvm/trunk/include/llvm/Demangle/Compiler.h
    llvm/trunk/include/llvm/Support/Compiler.h
    llvm/trunk/lib/Passes/CMakeLists.txt
    llvm/trunk/tools/opt/NewPMDriver.cpp
    llvm/trunk/unittests/CMakeLists.txt

Modified: llvm/trunk/include/llvm/Demangle/Compiler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Demangle/Compiler.h?rev=329273&r1=329272&r2=329273&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Demangle/Compiler.h (original)
+++ llvm/trunk/include/llvm/Demangle/Compiler.h Thu Apr  5 04:29:37 2018
@@ -503,4 +503,22 @@ void AnnotateIgnoreWritesEnd(const char
 #define LLVM_ENABLE_EXCEPTIONS 1
 #endif
 
+/// \macro LLVM_PLUGIN_IMPORT
+/// \brief Used to import the well-known entry point for registering loaded pass
+/// plugins
+#ifdef WIN32
+#define LLVM_PLUGIN_IMPORT __declspec(dllimport)
+#else
+#define LLVM_PLUGIN_IMPORT
+#endif
+
+/// \macro LLVM_PLUGIN_EXPORT
+/// \brief Used to export the well-known entry point for registering loaded pass
+/// plugins
+#ifdef WIN32
+#define LLVM_PLUGIN_EXPORT __declspec(dllexport)
+#else
+#define LLVM_PLUGIN_EXPORT
+#endif
+
 #endif

Added: llvm/trunk/include/llvm/Passes/PassPlugin.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Passes/PassPlugin.h?rev=329273&view=auto
==============================================================================
--- llvm/trunk/include/llvm/Passes/PassPlugin.h (added)
+++ llvm/trunk/include/llvm/Passes/PassPlugin.h Thu Apr  5 04:29:37 2018
@@ -0,0 +1,114 @@
+//===- llvm/Passes/PassPlugin.h - Public Plugin API -----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines the public entry point for new-PM pass plugins.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_PASSES_PASSPLUGIN_H
+#define LLVM_PASSES_PASSPLUGIN_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <string>
+
+namespace llvm {
+class PassBuilder;
+
+/// \macro LLVM_PLUGIN_API_VERSION
+/// Identifies the API version understood by this plugin.
+///
+/// When a plugin is loaded, the driver will check it's supported plugin version
+/// against that of the plugin. A mismatch is an error. The supported version
+/// will be incremented for ABI-breaking changes to the \c PassPluginLibraryInfo
+/// struct, i.e. when callbacks are added, removed, or reordered.
+#define LLVM_PLUGIN_API_VERSION 1
+
+extern "C" {
+/// Information about the plugin required to load its passes
+///
+/// This struct defines the core interface for pass plugins and is supposed to
+/// be filled out by plugin implementors. LLVM-side users of a plugin are
+/// expected to use the \c PassPlugin class below to interface with it.
+struct PassPluginLibraryInfo {
+  /// The API version understood by this plugin, usually \c
+  /// LLVM_PLUGIN_API_VERSION
+  uint32_t APIVersion;
+  /// A meaningful name of the plugin.
+  const char *PluginName;
+  /// The version of the plugin.
+  const char *PluginVersion;
+
+  /// The callback for registering plugin passes with a \c PassBuilder
+  /// instance
+  void (*RegisterPassBuilderCallbacks)(PassBuilder &);
+};
+}
+
+/// A loaded pass plugin.
+///
+/// An instance of this class wraps a loaded pass plugin and gives access to
+/// its interface defined by the \c PassPluginLibraryInfo it exposes.
+class PassPlugin {
+public:
+  /// Attempts to load a pass plugin from a given file.
+  ///
+  /// \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.
+  static Expected<PassPlugin> Load(const std::string &Filename);
+
+  /// Get the filename of the loaded plugin.
+  StringRef getFilename() const { return Filename; }
+
+  /// Get the plugin name
+  StringRef getPluginName() const { return Info.PluginName; }
+
+  /// Get the plugin version
+  StringRef getPluginVersion() const { return Info.PluginVersion; }
+
+  /// Get the plugin API version
+  uint32_t getAPIVersion() const { return Info.APIVersion; }
+
+  /// Invoke the PassBuilder callback registration
+  void registerPassBuilderCallbacks(PassBuilder &PB) const {
+    Info.RegisterPassBuilderCallbacks(PB);
+  }
+
+private:
+  PassPlugin(const std::string &Filename, const sys::DynamicLibrary &Library)
+      : Filename(Filename), Library(Library), Info() {}
+
+  std::string Filename;
+  sys::DynamicLibrary Library;
+  PassPluginLibraryInfo Info;
+};
+}
+
+/// The public entry point for a pass plugin.
+///
+/// When a plugin is loaded by the driver, it will call this entry point to
+/// obtain information about this plugin and about how to register its passes.
+/// This function needs to be implemented by the plugin, see the example below:
+///
+/// ```
+/// extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
+/// LLVM_PLUGIN_EXPORT llvmGetPassPluginInfo() {
+///   return {
+///     LLVM_PLUGIN_API_VERSION, "MyPlugin", "v0.1", [](PassBuilder &PB) { ... }
+///   };
+/// }
+/// ```
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK LLVM_PLUGIN_IMPORT
+llvmGetPassPluginInfo();
+
+#endif /* LLVM_PASSES_PASSPLUGIN_H */

Modified: llvm/trunk/include/llvm/Support/Compiler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Compiler.h?rev=329273&r1=329272&r2=329273&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Compiler.h (original)
+++ llvm/trunk/include/llvm/Support/Compiler.h Thu Apr  5 04:29:37 2018
@@ -16,4 +16,5 @@
 //
 //===----------------------------------------------------------------------===//
 
+
 #include "llvm/Demangle/Compiler.h"

Modified: llvm/trunk/lib/Passes/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/CMakeLists.txt?rev=329273&r1=329272&r2=329273&view=diff
==============================================================================
--- llvm/trunk/lib/Passes/CMakeLists.txt (original)
+++ llvm/trunk/lib/Passes/CMakeLists.txt Thu Apr  5 04:29:37 2018
@@ -1,5 +1,6 @@
 add_llvm_library(LLVMPasses
   PassBuilder.cpp
+  PassPlugin.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/Passes

Added: llvm/trunk/lib/Passes/PassPlugin.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/PassPlugin.cpp?rev=329273&view=auto
==============================================================================
--- llvm/trunk/lib/Passes/PassPlugin.cpp (added)
+++ llvm/trunk/lib/Passes/PassPlugin.cpp Thu Apr  5 04:29:37 2018
@@ -0,0 +1,50 @@
+//===- lib/Passes/PassPluginLoader.cpp - Load Plugins for New PM Passes ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Passes/PassPlugin.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+Expected<PassPlugin> PassPlugin::Load(const std::string &Filename) {
+  std::string Error;
+  auto Library =
+      sys::DynamicLibrary::getPermanentLibrary(Filename.c_str(), &Error);
+  if (!Library.isValid())
+    return make_error<StringError>(Twine("Could not load library '") +
+                                       Filename + "': " + Error,
+                                   inconvertibleErrorCode());
+
+  PassPlugin P{Filename, Library};
+  auto *getDetailsFn =
+      Library.SearchForAddressOfSymbol("llvmGetPassPluginInfo");
+
+  if (!getDetailsFn)
+    // If the symbol isn't found, this is probably a legacy plugin, which is an
+    // error
+    return make_error<StringError>(Twine("Plugin entry point not found in '") +
+                                       Filename + "'. Is this a legacy plugin?",
+                                   inconvertibleErrorCode());
+
+  P.Info = reinterpret_cast<decltype(llvmGetPassPluginInfo) *>(getDetailsFn)();
+
+  if (P.Info.APIVersion != LLVM_PLUGIN_API_VERSION)
+    return make_error<StringError>(
+        Twine("Wrong API version on plugin '") + Filename + "'. Got version " +
+            Twine(P.Info.APIVersion) + ", supported version is " +
+            Twine(LLVM_PLUGIN_API_VERSION) + ".",
+        inconvertibleErrorCode());
+
+  if (!P.Info.RegisterPassBuilderCallbacks)
+    return make_error<StringError>(Twine("Empty entry callback in plugin '") +
+                                       Filename + "'.'",
+                                   inconvertibleErrorCode());
+
+  return P;
+}

Modified: llvm/trunk/tools/opt/NewPMDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/opt/NewPMDriver.cpp?rev=329273&r1=329272&r2=329273&view=diff
==============================================================================
--- llvm/trunk/tools/opt/NewPMDriver.cpp (original)
+++ llvm/trunk/tools/opt/NewPMDriver.cpp Thu Apr  5 04:29:37 2018
@@ -27,6 +27,7 @@
 #include "llvm/IR/PassManager.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/PassPlugin.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ToolOutputFile.h"
@@ -41,6 +42,10 @@ static cl::opt<bool>
     DebugPM("debug-pass-manager", cl::Hidden,
             cl::desc("Print pass management debugging information"));
 
+static cl::list<std::string>
+    PassPlugins("load-pass-plugin",
+                cl::desc("Load passes from plugin library"));
+
 // This flag specifies a textual description of the alias analysis pipeline to
 // use when querying for aliasing information. It only works in concert with
 // the "passes" flag above.
@@ -210,6 +215,18 @@ bool llvm::runPassPipeline(StringRef Arg
   PassBuilder PB(TM, P);
   registerEPCallbacks(PB, VerifyEachPass, DebugPM);
 
+  // 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);
+  }
+
   // Register a callback that creates the debugify passes as needed.
   PB.registerPipelineParsingCallback(
       [](StringRef Name, ModulePassManager &MPM,

Modified: llvm/trunk/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CMakeLists.txt?rev=329273&r1=329272&r2=329273&view=diff
==============================================================================
--- llvm/trunk/unittests/CMakeLists.txt (original)
+++ llvm/trunk/unittests/CMakeLists.txt Thu Apr  5 04:29:37 2018
@@ -22,6 +22,7 @@ add_subdirectory(Object)
 add_subdirectory(BinaryFormat)
 add_subdirectory(ObjectYAML)
 add_subdirectory(Option)
+add_subdirectory(Passes)
 add_subdirectory(ProfileData)
 add_subdirectory(Support)
 add_subdirectory(Target)

Added: llvm/trunk/unittests/Passes/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Passes/CMakeLists.txt?rev=329273&view=auto
==============================================================================
--- llvm/trunk/unittests/Passes/CMakeLists.txt (added)
+++ llvm/trunk/unittests/Passes/CMakeLists.txt Thu Apr  5 04:29:37 2018
@@ -0,0 +1,21 @@
+set(LLVM_LINK_COMPONENTS Support Passes Core)
+
+add_llvm_unittest(PluginsTests PluginsTest.cpp)
+export_executable_symbols(PluginsTests)
+
+add_library(TestPlugin SHARED TestPlugin.cxx)
+
+set_output_directory(TestPlugin
+  BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
+  LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
+  )
+
+set_target_properties(TestPlugin
+  PROPERTIES PREFIX ""
+  SUFFIX ".so"
+  )
+
+llvm_map_components_to_libnames(LLVMDependencies ${LLVM_LINK_COMPONENTS})
+target_link_libraries(TestPlugin ${LLVMDependencies})
+
+add_dependencies(PluginsTests TestPlugin)

Added: llvm/trunk/unittests/Passes/PluginsTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Passes/PluginsTest.cpp?rev=329273&view=auto
==============================================================================
--- llvm/trunk/unittests/Passes/PluginsTest.cpp (added)
+++ llvm/trunk/unittests/Passes/PluginsTest.cpp Thu Apr  5 04:29:37 2018
@@ -0,0 +1,53 @@
+//===- unittests/Passes/Plugins/PluginsTest.cpp ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/PassPlugin.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Transforms/Scalar/LoopPassManager.h"
+#include "gtest/gtest.h"
+
+#include "TestPlugin.h"
+
+using namespace llvm;
+
+void anchor() {}
+
+static std::string LibPath(const std::string Name = "TestPlugin") {
+  const std::vector<testing::internal::string> &Argvs =
+      testing::internal::GetArgvs();
+  const char *Argv0 = Argvs.size() > 0 ? Argvs[0].c_str() : "PluginsTests";
+  void *Ptr = (void *)anchor;
+  std::string Path = sys::fs::getMainExecutable(Argv0, Ptr);
+  llvm::SmallString<256> Buf{sys::path::parent_path(Path)};
+  sys::path::append(Buf, (Name + ".so").c_str());
+  return Buf.str();
+}
+
+TEST(PluginsTests, LoadPlugin) {
+  auto PluginPath = LibPath();
+  ASSERT_NE("", PluginPath);
+
+  Expected<PassPlugin> Plugin = PassPlugin::Load(PluginPath);
+  ASSERT_TRUE(!!Plugin) << "Plugin path: " << PluginPath;
+
+  ASSERT_EQ(TEST_PLUGIN_NAME, Plugin->getPluginName());
+  ASSERT_EQ(TEST_PLUGIN_VERSION, Plugin->getPluginVersion());
+
+  PassBuilder PB;
+  ModulePassManager PM;
+  ASSERT_FALSE(PB.parsePassPipeline(PM, "plugin-pass"));
+
+  Plugin->registerPassBuilderCallbacks(PB);
+  ASSERT_TRUE(PB.parsePassPipeline(PM, "plugin-pass"));
+}

Added: llvm/trunk/unittests/Passes/TestPlugin.cxx
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Passes/TestPlugin.cxx?rev=329273&view=auto
==============================================================================
--- llvm/trunk/unittests/Passes/TestPlugin.cxx (added)
+++ llvm/trunk/unittests/Passes/TestPlugin.cxx Thu Apr  5 04:29:37 2018
@@ -0,0 +1,39 @@
+//===- unittests/Passes/Plugins/Plugin.cxx --------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/PassPlugin.h"
+
+#include "TestPlugin.h"
+
+using namespace llvm;
+
+struct TestModulePass : public PassInfoMixin<TestModulePass> {
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
+    return PreservedAnalyses::all();
+  }
+};
+
+void registerCallbacks(PassBuilder &PB) {
+  PB.registerPipelineParsingCallback(
+      [](StringRef Name, ModulePassManager &PM,
+         ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
+        if (Name == "plugin-pass") {
+          PM.addPass(TestModulePass());
+          return true;
+        }
+        return false;
+      });
+}
+
+extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK LLVM_PLUGIN_EXPORT
+llvmGetPassPluginInfo() {
+  return {LLVM_PLUGIN_API_VERSION, TEST_PLUGIN_NAME, TEST_PLUGIN_VERSION,
+          registerCallbacks};
+}

Added: llvm/trunk/unittests/Passes/TestPlugin.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Passes/TestPlugin.h?rev=329273&view=auto
==============================================================================
--- llvm/trunk/unittests/Passes/TestPlugin.h (added)
+++ llvm/trunk/unittests/Passes/TestPlugin.h Thu Apr  5 04:29:37 2018
@@ -0,0 +1,2 @@
+#define TEST_PLUGIN_NAME "TestPlugin"
+#define TEST_PLUGIN_VERSION "0.1-unit"




More information about the llvm-commits mailing list