[llvm] r329293 - Re-land 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 08:04:13 PDT 2018


Author: pfaffe
Date: Thu Apr  5 08:04:13 2018
New Revision: 329293

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

Fix unittest: Do not link LLVM into the test plugin.
Additionally, remove an unrelated change that slipped in in r329273.

Added:
    llvm/trunk/include/llvm/Passes/PassPlugin.h
    llvm/trunk/lib/Passes/PassPlugin.cpp
    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/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=329293&r1=329292&r2=329293&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Demangle/Compiler.h (original)
+++ llvm/trunk/include/llvm/Demangle/Compiler.h Thu Apr  5 08:04:13 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=329293&view=auto
==============================================================================
--- llvm/trunk/include/llvm/Passes/PassPlugin.h (added)
+++ llvm/trunk/include/llvm/Passes/PassPlugin.h Thu Apr  5 08:04:13 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/lib/Passes/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/CMakeLists.txt?rev=329293&r1=329292&r2=329293&view=diff
==============================================================================
--- llvm/trunk/lib/Passes/CMakeLists.txt (original)
+++ llvm/trunk/lib/Passes/CMakeLists.txt Thu Apr  5 08:04:13 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=329293&view=auto
==============================================================================
--- llvm/trunk/lib/Passes/PassPlugin.cpp (added)
+++ llvm/trunk/lib/Passes/PassPlugin.cpp Thu Apr  5 08:04:13 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=329293&r1=329292&r2=329293&view=diff
==============================================================================
--- llvm/trunk/tools/opt/NewPMDriver.cpp (original)
+++ llvm/trunk/tools/opt/NewPMDriver.cpp Thu Apr  5 08:04:13 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=329293&r1=329292&r2=329293&view=diff
==============================================================================
--- llvm/trunk/unittests/CMakeLists.txt (original)
+++ llvm/trunk/unittests/CMakeLists.txt Thu Apr  5 08:04:13 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=329293&view=auto
==============================================================================
--- llvm/trunk/unittests/Passes/CMakeLists.txt (added)
+++ llvm/trunk/unittests/Passes/CMakeLists.txt Thu Apr  5 08:04:13 2018
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS Support Passes Core)
+
+add_llvm_unittest(PluginsTests PluginsTest.cpp)
+export_executable_symbols(PluginsTests)
+
+add_library(TestPlugin MODULE 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"
+  )
+
+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=329293&view=auto
==============================================================================
--- llvm/trunk/unittests/Passes/PluginsTest.cpp (added)
+++ llvm/trunk/unittests/Passes/PluginsTest.cpp Thu Apr  5 08:04:13 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=329293&view=auto
==============================================================================
--- llvm/trunk/unittests/Passes/TestPlugin.cxx (added)
+++ llvm/trunk/unittests/Passes/TestPlugin.cxx Thu Apr  5 08:04:13 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=329293&view=auto
==============================================================================
--- llvm/trunk/unittests/Passes/TestPlugin.h (added)
+++ llvm/trunk/unittests/Passes/TestPlugin.h Thu Apr  5 08:04:13 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