https://github.com/weliveindetail updated https://github.com/llvm/llvm-project/pull/231516
From fd90348d281d2297f6942b1f01cbf69bdbb10bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Mon, 21 Sep 2026 15:57:03 +0200 Subject: [PATCH 1/2] [LTO] Support PreCodeGenCallback for pass-plugins in lld and clang Co-Authored-By: Claude Opus 5.5 <[email protected]> --- clang/test/CodeGen/codegen-plugins-thinlto.c | 21 ++++++++++ lld/test/ELF/lto/pre-codegen-plugin.ll | 28 +++++++++++++ llvm/lib/LTO/LTOBackend.cpp | 44 +++++++++++++++----- llvm/test/Feature/codegen-plugin.ll | 10 +++++ 4 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 clang/test/CodeGen/codegen-plugins-thinlto.c create mode 100644 lld/test/ELF/lto/pre-codegen-plugin.ll diff --git a/clang/test/CodeGen/codegen-plugins-thinlto.c b/clang/test/CodeGen/codegen-plugins-thinlto.c new file mode 100644 index 00000000000000..9f5fae5c1c65b4 --- /dev/null +++ b/clang/test/CodeGen/codegen-plugins-thinlto.c @@ -0,0 +1,21 @@ +// REQUIRES: plugins, llvm-examples +// UNSUPPORTED: target={{.*windows.*}} +// Plugins are currently broken on AIX, at least in the CI. +// XFAIL: target={{.*}}-aix{{.*}} + +// RUN: %clang_cc1 -O2 -flto=thin -emit-llvm-bc %s -o %t.o +// RUN: llvm-lto -thinlto -o %t %t.o +// RUN: %clang_cc1 -O2 -x ir %t.o -fthinlto-index=%t.thinlto.bc -S -o - -fpass-plugin=%llvmshlibdir/Bye%pluginext 2>&1 | FileCheck %s --check-prefix=CHECK-INACTIVE +// RUN: %clang_cc1 -O2 -x ir %t.o -fthinlto-index=%t.thinlto.bc -S -o - -fpass-plugin=%llvmshlibdir/Bye%pluginext -mllvm -last-words | FileCheck %s --check-prefix=CHECK-ACTIVE +// RUN: %clang_cc1 -O2 -x ir %t.o -fthinlto-index=%t.thinlto.bc -emit-llvm -o - -fpass-plugin=%llvmshlibdir/Bye%pluginext -mllvm -last-words | FileCheck %s --check-prefix=CHECK-LLVM +// RUN: not %clang_cc1 -O2 -x ir %t.o -fthinlto-index=%t.thinlto.bc -emit-obj -o - -fpass-plugin=%llvmshlibdir/Bye%pluginext -mllvm -last-words 2>&1 | FileCheck %s --check-prefix=CHECK-ERR + +// CHECK-INACTIVE-NOT: Bye +// CHECK-INACTIVE: f: +// CHECK-ACTIVE: CodeGen Bye +// CHECK-LLVM: define{{.*}} i32 @f +// CHECK-ERR: error: last words unsupported for binary output + +int f(int x) { + return x; +} diff --git a/lld/test/ELF/lto/pre-codegen-plugin.ll b/lld/test/ELF/lto/pre-codegen-plugin.ll new file mode 100644 index 00000000000000..880d422adff9d0 --- /dev/null +++ b/lld/test/ELF/lto/pre-codegen-plugin.ll @@ -0,0 +1,28 @@ +; REQUIRES: x86, plugins, examples +; UNSUPPORTED: target={{.*windows.*}} +; Plugins are currently broken on AIX, at least in the CI. +; XFAIL: target={{.*}}-aix{{.*}} + +; RUN: opt %s -o %t.o +; RUN: ld.lld -shared --lto-emit-asm -%loadnewpmbye %t.o -o %t.inactive 2>&1 | count 0 +; RUN: FileCheck %s --check-prefix=INACTIVE < %t.inactive.lto.s +; RUN: ld.lld -shared --lto-emit-asm -%loadnewpmbye -mllvm=%loadbye -mllvm=-last-words %t.o -o %t.active +; RUN: FileCheck %s --check-prefix=ACTIVE < %t.active.lto.s +; RUN: not ld.lld -shared -%loadnewpmbye -mllvm=%loadbye -mllvm=-last-words %t.o -o %t.err 2>&1 | FileCheck %s --check-prefix=ERR +; RUN: ld.lld -shared --lto-emit-asm --lto-partitions=2 -%loadnewpmbye -mllvm=%loadbye -mllvm=-last-words %t.o -o %t.parallel +; RUN: FileCheck %s --check-prefix=PARALLEL0 < %t.parallel.lto.s +; RUN: FileCheck %s --check-prefix=PARALLEL1 < %t.parallel.lto.1.s + +; INACTIVE-NOT: Bye +; INACTIVE: f: +; ACTIVE: CodeGen Bye +; ERR: error: last words unsupported for binary output +; PARALLEL0: CodeGen Bye +; PARALLEL1: CodeGen Bye + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i32 @f(i32 %x) { + ret i32 %x +} diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 13b5e6e93335dc..3be710a7864bb4 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -199,23 +199,34 @@ Error Config::addSaveTemps(std::string OutputFileName, bool UseInputModulePath, #include "llvm/Support/Extension.def" #undef HANDLE_EXTENSION +// Obtain dynamic pass-plugins in registration order: the ones requested by file +// name followed by those pre-loaded in the host application +static SmallVector<PassPlugin *, 2> +getPassPlugins(const Config &Conf, SmallVectorImpl<PassPlugin> &Storage) { + for (const std::string &PluginFN : Conf.PassPluginFilenames) { + Expected<PassPlugin> Plugin = PassPlugin::load(PluginFN); + if (!Plugin) + reportFatalUsageError(Plugin.takeError()); + Storage.push_back(std::move(*Plugin)); + } + + SmallVector<PassPlugin *, 2> Plugins(make_pointer_range(Storage)); + append_range(Plugins, Conf.LoadedPassPlugins); + return Plugins; +} + +// Call pass builder registration callbacks for all pass-plugins static void RegisterPassPlugins(const Config &Conf, PassBuilder &PB) { + // Static built-in plugins #define HANDLE_EXTENSION(Ext) \ get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB); #include "llvm/Support/Extension.def" #undef HANDLE_EXTENSION - // Load requested pass plugins and let them register pass builder callbacks - for (auto &PluginFN : Conf.PassPluginFilenames) { - auto PassPlugin = PassPlugin::load(PluginFN); - if (!PassPlugin) - reportFatalUsageError(PassPlugin.takeError()); - PassPlugin->registerPassBuilderCallbacks(PB); - } - - // Register already loaded plugins - for (auto *LoadedPlugin : Conf.LoadedPassPlugins) - LoadedPlugin->registerPassBuilderCallbacks(PB); + // Dynamic plugins + SmallVector<PassPlugin, 2> Storage; + for (const PassPlugin *Plugin : getPassPlugins(Conf, Storage)) + Plugin->registerPassBuilderCallbacks(PB); } static std::unique_ptr<TargetMachine> @@ -479,6 +490,17 @@ static void codegen(const Config &Conf, TargetMachine *TM, std::unique_ptr<CachedFileStream> &Stream = *StreamOrErr; TM->Options.ObjectFilenameForDebug = Stream->ObjectPathName; + // Allow plugins to handle or even take over code generation entirely. + SmallVector<PassPlugin, 2> PluginStorage; + for (PassPlugin *Plugin : getPassPlugins(Conf, PluginStorage)) { + if (Plugin->invokePreCodeGenCallback(Mod, *TM, Conf.CGFileType, + *Stream->OS)) { + if (Error Err = Stream->commit()) + reportFatalUsageError(std::move(Err)); + return; + } + } + // Create the codegen pipeline in its own scope so it gets deleted before // Stream->commit() is called. The commit function of CacheStream deletes // the raw stream, which is too early as streamers (e.g. MCAsmStreamer) diff --git a/llvm/test/Feature/codegen-plugin.ll b/llvm/test/Feature/codegen-plugin.ll index 571c7e348520e9..bdbca8723c3afb 100644 --- a/llvm/test/Feature/codegen-plugin.ll +++ b/llvm/test/Feature/codegen-plugin.ll @@ -2,6 +2,15 @@ ; RUN: llc < %s %loadnewpmbye | FileCheck %s --check-prefix=CHECK-ASM ; RUN: llc < %s %loadnewpmbye -plugin-arg=Bye,-last-words | FileCheck %s --check-prefix=CHECK-ACTIVE ; RUN: not llc < %s %loadnewpmbye -plugin-arg=Bye,-last-words -filetype=obj 2>&1 | FileCheck %s --check-prefix=CHECK-ERR + +; LTO tools do not support -plugin-arg yet, so load Bye early to register its options +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-lto2 run %t.bc -o %t.inactive -r %t.bc,somefunk,plx -r %t.bc,junk,plx -filetype=asm %loadnewpmbye +; RUN: FileCheck %s --check-prefix=CHECK-ASM < %t.inactive.0 +; RUN: llvm-lto2 run %t.bc -o %t.active -r %t.bc,somefunk,plx -r %t.bc,junk,plx -filetype=asm %loadbye %loadnewpmbye -last-words +; RUN: FileCheck %s --check-prefix=CHECK-ACTIVE < %t.active.0 +; RUN: not llvm-lto2 run %t.bc -o %t.err -r %t.bc,somefunk,plx -r %t.bc,junk,plx -filetype=obj %loadbye %loadnewpmbye -last-words 2>&1 | FileCheck %s --check-prefix=CHECK-LTO2-ERR + ; REQUIRES: plugins, examples ; UNSUPPORTED: target={{.*windows.*}} ; Plugins are currently broken on AIX, at least in the CI. @@ -9,6 +18,7 @@ ; CHECK-ASM: somefunk: ; CHECK-ACTIVE: CodeGen Bye ; CHECK-ERR: error: last words unsupported for binary output +; CHECK-LTO2-ERR: last words unsupported for binary output target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" From 230a6d89d6f659c47bbbd7fe9a1d828de115a344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Thu, 15 Oct 2026 00:49:44 +0200 Subject: [PATCH 2/2] Switch getPassPlugins() to PassPluginLibraryInfos --- llvm/lib/LTO/LTOBackend.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 3be710a7864bb4..4b818f08eb6518 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -201,17 +201,17 @@ Error Config::addSaveTemps(std::string OutputFileName, bool UseInputModulePath, // Obtain dynamic pass-plugins in registration order: the ones requested by file // name followed by those pre-loaded in the host application -static SmallVector<PassPlugin *, 2> -getPassPlugins(const Config &Conf, SmallVectorImpl<PassPlugin> &Storage) { +static SmallVector<PassPluginLibraryInfo, 0> +getPassPlugins(const Config &Conf) { + SmallVector<PassPluginLibraryInfo, 0> Plugins; for (const std::string &PluginFN : Conf.PassPluginFilenames) { Expected<PassPlugin> Plugin = PassPlugin::load(PluginFN); if (!Plugin) reportFatalUsageError(Plugin.takeError()); - Storage.push_back(std::move(*Plugin)); + Plugins.push_back(Plugin->getInfo()); } - - SmallVector<PassPlugin *, 2> Plugins(make_pointer_range(Storage)); - append_range(Plugins, Conf.LoadedPassPlugins); + for (const PassPlugin *Plugin : Conf.LoadedPassPlugins) + Plugins.push_back(Plugin->getInfo()); return Plugins; } @@ -224,9 +224,9 @@ static void RegisterPassPlugins(const Config &Conf, PassBuilder &PB) { #undef HANDLE_EXTENSION // Dynamic plugins - SmallVector<PassPlugin, 2> Storage; - for (const PassPlugin *Plugin : getPassPlugins(Conf, Storage)) - Plugin->registerPassBuilderCallbacks(PB); + for (const PassPluginLibraryInfo &Plugin : getPassPlugins(Conf)) + if (Plugin.RegisterPassBuilderCallbacks) + Plugin.RegisterPassBuilderCallbacks(PB); } static std::unique_ptr<TargetMachine> @@ -491,10 +491,9 @@ static void codegen(const Config &Conf, TargetMachine *TM, TM->Options.ObjectFilenameForDebug = Stream->ObjectPathName; // Allow plugins to handle or even take over code generation entirely. - SmallVector<PassPlugin, 2> PluginStorage; - for (PassPlugin *Plugin : getPassPlugins(Conf, PluginStorage)) { - if (Plugin->invokePreCodeGenCallback(Mod, *TM, Conf.CGFileType, - *Stream->OS)) { + for (const PassPluginLibraryInfo &Plugin : getPassPlugins(Conf)) { + if (Plugin.PreCodeGenCallback && + Plugin.PreCodeGenCallback(Mod, *TM, Conf.CGFileType, *Stream->OS)) { if (Error Err = Stream->commit()) reportFatalUsageError(std::move(Err)); return; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
