[llvm] [Opt] Enable statically-linked plugin support (PR #79227)

William Moses via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 23 15:38:50 PST 2024


https://github.com/wsmoses created https://github.com/llvm/llvm-project/pull/79227

Companion PR to https://github.com/llvm/llvm-project/pull/70171 except now for opt rather than clang.

This PR enables using custom passes in plugins, when statically linked against opt.

See https://github.com/llvm/llvm-project/pull/79205 for a standalone bazel PR needed for this to be used in a different build system.

>From 1c9d5c6760a5d150e6c7c8478ae1fffe15741dcf Mon Sep 17 00:00:00 2001
From: "William S. Moses" <gh at wsmoses.com>
Date: Tue, 23 Jan 2024 15:17:10 -0500
Subject: [PATCH 1/2] [Bazel] Support opt-driver library, like clang-driver

---
 utils/bazel/llvm-project-overlay/llvm/BUILD.bazel | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
index b22ec01376be6d4..21466a79af61b53 100644
--- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
@@ -4808,8 +4808,8 @@ cc_binary(
     ],
 )
 
-cc_binary(
-    name = "opt",
+cc_library(
+    name = "opt-driver",
     srcs = glob([
         "tools/opt/*.cpp",
         "tools/opt/*.h",
@@ -4820,7 +4820,6 @@ cc_binary(
         "@platforms//os:macos": [],
         "//conditions:default": ["-Wl,--export-dynamic"],
     }),
-    stamp = 0,
     deps = [
         ":AllTargetsAsmParsers",
         ":AllTargetsCodeGens",
@@ -4847,6 +4846,12 @@ cc_binary(
     ],
 )
 
+cc_binary(
+    name = "opt",
+    stamp = 0,
+    deps = [":opt-driver"]
+)
+
 gentbl(
     name = "SancovOptsTableGen",
     strip_include_prefix = "tools/sancov",

>From 801e49cf01a460adb0a50109a42a347808a5e9dd Mon Sep 17 00:00:00 2001
From: "William S. Moses" <gh at wsmoses.com>
Date: Tue, 23 Jan 2024 18:33:53 -0500
Subject: [PATCH 2/2] [Opt] Enable support for statically linked plugins

---
 llvm/lib/Passes/PassPlugin.cpp            | 31 ++++++++---
 llvm/test/Feature/load_staticextension.ll | 15 ++++++
 llvm/tools/opt/CMakeLists.txt             | 14 +++++
 llvm/tools/opt/PrintPlugin.cpp            | 63 +++++++++++++++++++++++
 4 files changed, 116 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/Feature/load_staticextension.ll
 create mode 100644 llvm/tools/opt/PrintPlugin.cpp

diff --git a/llvm/lib/Passes/PassPlugin.cpp b/llvm/lib/Passes/PassPlugin.cpp
index 6182cbbb1fddd3a..9cdc27491a9bfb6 100644
--- a/llvm/lib/Passes/PassPlugin.cpp
+++ b/llvm/lib/Passes/PassPlugin.cpp
@@ -14,20 +14,37 @@
 using namespace llvm;
 
 Expected<PassPlugin> PassPlugin::Load(const std::string &Filename) {
+  // First, see if the plugin is available in the current executable, with the
+  // suffix of the symbol being given by the `Filename` otherwise, try loading
+  // the plugin via the file
   std::string Error;
-  auto Library =
-      sys::DynamicLibrary::getPermanentLibrary(Filename.c_str(), &Error);
+
+  auto Library = sys::DynamicLibrary::getPermanentLibrary(nullptr, &Error);
   if (!Library.isValid())
-    return make_error<StringError>(Twine("Could not load library '") +
-                                       Filename + "': " + Error,
+    return make_error<StringError>("Could not load current executable",
                                    inconvertibleErrorCode());
 
-  PassPlugin P{Filename, Library};
-
   // llvmGetPassPluginInfo should be resolved to the definition from the plugin
   // we are currently loading.
+  std::string symbolName = "llvmGetPassPluginInfo" + Filename;
   intptr_t getDetailsFn =
-      (intptr_t)Library.getAddressOfSymbol("llvmGetPassPluginInfo");
+      (intptr_t)Library.getAddressOfSymbol(symbolName.c_str());
+
+  if (!getDetailsFn) {
+    Library = sys::DynamicLibrary::getPermanentLibrary(
+        (Filename == "") ? nullptr : Filename.c_str(), &Error);
+    if (!Library.isValid())
+      return make_error<StringError>(Twine("Could not load library '") +
+                                         Filename + "': " + Error,
+                                     inconvertibleErrorCode());
+
+    // llvmGetPassPluginInfo should be resolved to the definition from the
+    // plugin we are currently loading.
+    getDetailsFn =
+        (intptr_t)Library.getAddressOfSymbol("llvmGetPassPluginInfo");
+  }
+
+  PassPlugin P{Filename, Library};
 
   if (!getDetailsFn)
     // If the symbol isn't found, this is probably a legacy plugin, which is an
diff --git a/llvm/test/Feature/load_staticextension.ll b/llvm/test/Feature/load_staticextension.ll
new file mode 100644
index 000000000000000..6a17de86c0d18d8
--- /dev/null
+++ b/llvm/test/Feature/load_staticextension.ll
@@ -0,0 +1,15 @@
+; REQUIRES: x86-registered-target
+; RUN: opt-printplugin %s -load-pass-plugin="PrintPlugin" -passes="printpass" -disable-output 2>&1 | FileCheck %s
+
+; REQUIRES: plugins
+
+; CHECK: [PrintPass] Found function: somefunk
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+ at junk = global i32 0
+
+define ptr @somefunk() {
+  ret ptr @junk
+}
+
diff --git a/llvm/tools/opt/CMakeLists.txt b/llvm/tools/opt/CMakeLists.txt
index 2cdb99e936287ca..16b7a7d3963faa5 100644
--- a/llvm/tools/opt/CMakeLists.txt
+++ b/llvm/tools/opt/CMakeLists.txt
@@ -30,6 +30,7 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_llvm_tool(opt
+    PARTIAL_SOURCES_INTENDED
   NewPMDriver.cpp
   opt.cpp
 
@@ -38,3 +39,16 @@ add_llvm_tool(opt
   SUPPORT_PLUGINS
   )
 export_executable_symbols_for_plugins(opt)
+
+if (LLVM_ENABLE_PLUGINS)
+add_llvm_tool(opt-printplugin
+  NewPMDriver.cpp
+  opt.cpp
+  PrintPlugin.cpp
+
+  DEPENDS
+  intrinsics_gen
+  SUPPORT_PLUGINS
+  )
+target_link_options(opt-printplugin PUBLIC -Wl,--export-dynamic-symbol=llvmGetPassPluginInfoPrintPlugin)
+endif()
diff --git a/llvm/tools/opt/PrintPlugin.cpp b/llvm/tools/opt/PrintPlugin.cpp
new file mode 100644
index 000000000000000..b0bbca87b0a54a7
--- /dev/null
+++ b/llvm/tools/opt/PrintPlugin.cpp
@@ -0,0 +1,63 @@
+//===- LLVMPrintFunctionNames.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Example opt plugin which simply prints the names of all the functions
+// within the generated LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/PassManager.h"
+#include "llvm/Passes/OptimizationLevel.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/PassPlugin.h"
+#include "llvm/Support/Registry.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace {
+
+class PrintPass final : public llvm::AnalysisInfoMixin<PrintPass> {
+  friend struct llvm::AnalysisInfoMixin<PrintPass>;
+
+private:
+  static llvm::AnalysisKey key;
+
+public:
+  using Result = llvm::PreservedAnalyses;
+
+  Result run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM) {
+    for (auto &F : M)
+      llvm::outs() << "[PrintPass] Found function: " << F.getName() << "\n";
+    return llvm::PreservedAnalyses::all();
+  }
+  static bool isRequired() { return true; }
+};
+
+} // namespace
+
+llvm::PassPluginLibraryInfo getPrintPluginInfo() {
+  return {LLVM_PLUGIN_API_VERSION, "PrintPlugin", LLVM_VERSION_STRING,
+          [](PassBuilder &PB) {
+            PB.registerPipelineParsingCallback(
+                [](StringRef Name, llvm::ModulePassManager &PM,
+                   ArrayRef<llvm::PassBuilder::PipelineElement>) {
+                  if (Name == "printpass") {
+                    PM.addPass(PrintPass());
+                    return true;
+                  }
+                  return false;
+                });
+          }};
+}
+
+extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
+llvmGetPassPluginInfoPrintPlugin() {
+  return getPrintPluginInfo();
+}



More information about the llvm-commits mailing list