[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