[clang] [llvm] [CodeGen] Expose the extensibility of PassConfig to plugins (PR #139059)
arsenm wrote: > I don't think you can reasonably test this with a lit test, you have to add > this as a proper build target in llvm/examples similar to Bye. A lit test could then drive the load of that plugin, but the lit test can't contain the pass itself https://github.com/llvm/llvm-project/pull/139059 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [CodeGen] Expose the extensibility of PassConfig to plugins (PR #139059)
arsenm wrote: I don't think you can reasonably test this with a lit test, you have to add this as a proper build target in llvm/examples similar to Bye https://github.com/llvm/llvm-project/pull/139059 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [CodeGen] Expose the extensibility of PassConfig to plugins (PR #139059)
Tcc100 wrote: I added a test case and some docs, which tuned out to be more challenging than expected, since I couldn't find any test case for the plugin system. The lit test in this PR requires the current llvm headers, which are not provided by the lit system, thus, it currently only works if you provide the absolute path in your system. I'd appreciate any pointers on how to implement this correctly. https://github.com/llvm/llvm-project/pull/139059 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [CodeGen] Expose the extensibility of PassConfig to plugins (PR #139059)
@@ -72,6 +74,10 @@ namespace yaml { struct MachineFunctionInfo; } // namespace yaml +class TargetMachine; +using PassConfigCallback = +std::function; Tcc100 wrote: I think this should be a owning reference, similar to the other callback vectors. https://github.com/llvm/llvm-project/pull/139059 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [CodeGen] Expose the extensibility of PassConfig to plugins (PR #139059)
@@ -119,6 +119,9 @@ addPassesToGenerateCode(CodeGenTargetMachineImpl &TM, PassManagerBase &PM, PM.add(PassConfig); PM.add(&MMIWP); + for (auto& C : *TargetMachine::TargetPassConfigCallbacks) Tcc100 wrote: This is same syntax as most of the callbacks in the code base use. Do you think not using auto would be better in this case? https://github.com/llvm/llvm-project/pull/139059 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [CodeGen] Expose the extensibility of PassConfig to plugins (PR #139059)
llvmbot wrote: @llvm/pr-subscribers-clang Author: None (Tcc100) Changes This PR exposes the backend pass config to plugins via a callback. Plugin authors can register a callback that is being triggered before the target backend adds their passes to the pipeline. In the callback they then get access to the `TargetMachine`, the `PassManager`, and the `TargetPassConfig`. This allows plugins to call `TargetPassConfig::insertPass`, which is honored in the subsequent `addPass` of the main backend. We implemented this using the legacy pass manager as the backend is still using the old pass manager. The following example shows how plugin authors can use the callback. Since its a callback that is not doing anything without anybody registering it, there shouldn't be any potential harm to the compiler unless a plugin is present. ```cpp __attribute__((constructor)) static void initCodeGenPlugin() { initializeCodeGenTestPass(*PassRegistry::getPassRegistry()); TargetMachine::registerTargetPassConfigCallback([](auto &TM, auto &PM, auto *TPC) { TPC->insertPass(&GCLoweringID, &CodeGenTest::ID); }); } ``` --- Full diff: https://github.com/llvm/llvm-project/pull/139059.diff 5 Files Affected: - (added) clang/test/CodeGen/passconfighook.cpp (+56) - (modified) llvm/docs/WritingAnLLVMPass.rst (+17) - (modified) llvm/include/llvm/Target/TargetMachine.h (+14) - (modified) llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp (+3) - (modified) llvm/lib/Target/TargetMachine.cpp (+3) ``diff diff --git a/clang/test/CodeGen/passconfighook.cpp b/clang/test/CodeGen/passconfighook.cpp new file mode 100644 index 0..094df123f3de1 --- /dev/null +++ b/clang/test/CodeGen/passconfighook.cpp @@ -0,0 +1,56 @@ +// RUN: %clangxx -shared -fPIC -I??/install/include -L%llvmshlibdir %s -o %t.so +// RUN: %clangxx -O3 -DMAIN -Xclang -load -Xclang %t.so %s -o %t-main | FileCheck %s + +#ifndef MAIN + +#include +#include +#include +#include + +#define DEBUG_TYPE "codegen-test" +#define CODEGEN_TEST_NAME "CodeGen Test Pass" + +using namespace llvm; + +namespace llvm { +void initializeCodeGenTestPass(PassRegistry &); +} // namespace llvm + +class CodeGenTest : public MachineFunctionPass { +public: +static char ID; + +CodeGenTest(): MachineFunctionPass(ID) { +} + +bool runOnMachineFunction(MachineFunction &MF) override { +outs() << "[CodeGen] CodeGenTest::runOnMachineFunction" << "\n"; +return true; +} + +StringRef getPassName() const override { +return CODEGEN_TEST_NAME; +} +}; + +char CodeGenTest::ID = 0; +INITIALIZE_PASS(CodeGenTest, DEBUG_TYPE, CODEGEN_TEST_NAME, false, false) + +__attribute__((constructor)) static void initCodeGenPlugin() { +initializeCodeGenTestPass(*PassRegistry::getPassRegistry()); + +TargetMachine::registerTargetPassConfigCallback([](auto &TM, auto &PM, auto *TPC) { +outs() << "registerTargetPassConfigCallback\n"; +TPC->insertPass(&GCLoweringID, &CodeGenTest::ID); +}); +} + +#else + +// CHECK: CodeGenTest::runOnMachineFunction +int main(int argc, char **argv) { +return 0; +} + +#endif diff --git a/llvm/docs/WritingAnLLVMPass.rst b/llvm/docs/WritingAnLLVMPass.rst index 484227bac38b5..770f5f6acd115 100644 --- a/llvm/docs/WritingAnLLVMPass.rst +++ b/llvm/docs/WritingAnLLVMPass.rst @@ -442,6 +442,23 @@ in certain circumstances (such as calling the ``Pass::dump()`` from a debugger), so it should only be used to enhance debug output, it should not be depended on. +Scheduling a MachineFunctionPass + + +Backends create a ``TargetPassConfig`` and use ``addPass`` to schedule +``MachineFunctionPass``\ es. External plugins can register a callback to modify +and insert additional passes: + +.. code-block:: c++ + + TargetMachine::registerTargetPassConfigCallback( +[](TargetMachine &TM, PassManager &PM, TargetPassConfig *TPC) { + TPC->insertPass(/* ... */); + TPC->substitutePass(/* ... */); +} + ); + + .. _writing-an-llvm-pass-interaction: Specifying interactions between passes diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h index 906926729ed74..bcc1ce29b8282 100644 --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -20,10 +20,12 @@ #include "llvm/Support/CodeGen.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PGOOptions.h" #include "llvm/Target/CGPassBuilderOption.h" #include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/Triple.h" +#include #include #include #include @@ -72,6 +74,10 @@ namespace yaml { struct MachineFunctionInfo; } // namespace yaml +class TargetMachine; +using PassConfigCallback = +std::function; + //===--===// /// /// Primary in
[clang] [llvm] [CodeGen] Expose the extensibility of PassConfig to plugins (PR #139059)
https://github.com/Tcc100 updated https://github.com/llvm/llvm-project/pull/139059 >From 0b9f452fff11853207e0eab6108e47e8c7469295 Mon Sep 17 00:00:00 2001 From: T Date: Thu, 8 May 2025 11:56:00 +0200 Subject: [PATCH] [CodeGen] Expose the extensibility of PassConfig to plugins --- clang/test/CodeGen/passconfighook.cpp | 56 +++ llvm/docs/WritingAnLLVMPass.rst | 17 ++ llvm/include/llvm/Target/TargetMachine.h | 14 + llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp | 3 + llvm/lib/Target/TargetMachine.cpp | 3 + 5 files changed, 93 insertions(+) create mode 100644 clang/test/CodeGen/passconfighook.cpp diff --git a/clang/test/CodeGen/passconfighook.cpp b/clang/test/CodeGen/passconfighook.cpp new file mode 100644 index 0..094df123f3de1 --- /dev/null +++ b/clang/test/CodeGen/passconfighook.cpp @@ -0,0 +1,56 @@ +// RUN: %clangxx -shared -fPIC -I??/install/include -L%llvmshlibdir %s -o %t.so +// RUN: %clangxx -O3 -DMAIN -Xclang -load -Xclang %t.so %s -o %t-main | FileCheck %s + +#ifndef MAIN + +#include +#include +#include +#include + +#define DEBUG_TYPE "codegen-test" +#define CODEGEN_TEST_NAME "CodeGen Test Pass" + +using namespace llvm; + +namespace llvm { +void initializeCodeGenTestPass(PassRegistry &); +} // namespace llvm + +class CodeGenTest : public MachineFunctionPass { +public: +static char ID; + +CodeGenTest(): MachineFunctionPass(ID) { +} + +bool runOnMachineFunction(MachineFunction &MF) override { +outs() << "[CodeGen] CodeGenTest::runOnMachineFunction" << "\n"; +return true; +} + +StringRef getPassName() const override { +return CODEGEN_TEST_NAME; +} +}; + +char CodeGenTest::ID = 0; +INITIALIZE_PASS(CodeGenTest, DEBUG_TYPE, CODEGEN_TEST_NAME, false, false) + +__attribute__((constructor)) static void initCodeGenPlugin() { +initializeCodeGenTestPass(*PassRegistry::getPassRegistry()); + +TargetMachine::registerTargetPassConfigCallback([](auto &TM, auto &PM, auto *TPC) { +outs() << "registerTargetPassConfigCallback\n"; +TPC->insertPass(&GCLoweringID, &CodeGenTest::ID); +}); +} + +#else + +// CHECK: CodeGenTest::runOnMachineFunction +int main(int argc, char **argv) { +return 0; +} + +#endif diff --git a/llvm/docs/WritingAnLLVMPass.rst b/llvm/docs/WritingAnLLVMPass.rst index 484227bac38b5..770f5f6acd115 100644 --- a/llvm/docs/WritingAnLLVMPass.rst +++ b/llvm/docs/WritingAnLLVMPass.rst @@ -442,6 +442,23 @@ in certain circumstances (such as calling the ``Pass::dump()`` from a debugger), so it should only be used to enhance debug output, it should not be depended on. +Scheduling a MachineFunctionPass + + +Backends create a ``TargetPassConfig`` and use ``addPass`` to schedule +``MachineFunctionPass``\ es. External plugins can register a callback to modify +and insert additional passes: + +.. code-block:: c++ + + TargetMachine::registerTargetPassConfigCallback( +[](TargetMachine &TM, PassManager &PM, TargetPassConfig *TPC) { + TPC->insertPass(/* ... */); + TPC->substitutePass(/* ... */); +} + ); + + .. _writing-an-llvm-pass-interaction: Specifying interactions between passes diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h index 906926729ed74..bcc1ce29b8282 100644 --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -20,10 +20,12 @@ #include "llvm/Support/CodeGen.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PGOOptions.h" #include "llvm/Target/CGPassBuilderOption.h" #include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/Triple.h" +#include #include #include #include @@ -72,6 +74,10 @@ namespace yaml { struct MachineFunctionInfo; } // namespace yaml +class TargetMachine; +using PassConfigCallback = +std::function; + //===--===// /// /// Primary interface to the complete machine description for the target @@ -119,6 +125,9 @@ class TargetMachine { std::optional PGOOption; public: + static ManagedStatic> + TargetPassConfigCallbacks; + mutable TargetOptions Options; TargetMachine(const TargetMachine &) = delete; @@ -518,6 +527,11 @@ class TargetMachine { // MachineRegisterInfo callback function virtual void registerMachineRegisterInfoCallback(MachineFunction &MF) const {} + + // TargetPassConfig callback function + static void registerTargetPassConfigCallback(const PassConfigCallback &C) { +TargetPassConfigCallbacks->push_back(C); + } }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp b/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp index 4a3503a2da7db..336f1db776036 100644 --- a/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cp