Reland "[CodeGen] Expose the extensibility of PassConfig to plugins (#139059)"

Add missing dependencies to unittest target
Original patch broke BUILD_SHARED bots and required revert #147947
This commit is contained in:
Tcc100 2025-07-10 15:06:18 +02:00 committed by Stefan Gränitz
parent 896575eb74
commit 7daa1defd2
13 changed files with 344 additions and 0 deletions

View File

@ -442,6 +442,28 @@ 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 debugger), so it should only be used to enhance debug output, it should not be
depended on. 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++
RegisterTargetPassConfigCallback X{[](auto &TM, auto &PM, auto *TPC) {
TPC->insertPass(/* ... */);
TPC->substitutePass(/* ... */);
}};
Note that passes still have to be registered:
.. code-block:: c++
__attribute__((constructor)) static void initCodeGenPlugin() {
initializeExamplePass(*PassRegistry::getPassRegistry());
}
.. _writing-an-llvm-pass-interaction: .. _writing-an-llvm-pass-interaction:
Specifying interactions between passes Specifying interactions between passes

View File

@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// This file contains the registry for PassConfigCallbacks that enable changes
/// to the TargetPassConfig during the initialization of TargetMachine.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_TARGET_REGISTERTARGETPASSCONFIGCALLBACK_H
#define LLVM_TARGET_REGISTERTARGETPASSCONFIGCALLBACK_H
#include "TargetMachine.h"
namespace llvm {
using PassConfigCallback =
std::function<void(TargetMachine &, PassManagerBase &, TargetPassConfig *)>;
class RegisterTargetPassConfigCallback {
public:
PassConfigCallback Callback;
explicit RegisterTargetPassConfigCallback(PassConfigCallback &&C);
~RegisterTargetPassConfigCallback();
};
void invokeGlobalTargetPassConfigCallbacks(TargetMachine &TM,
PassManagerBase &PM,
TargetPassConfig *PassConfig);
} // namespace llvm
#endif // LLVM_TARGET_REGISTERTARGETPASSCONFIGCALLBACK_H

View File

@ -30,6 +30,7 @@
#include "llvm/MC/TargetRegistry.h" #include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h" #include "llvm/Support/FormattedStream.h"
#include "llvm/Target/RegisterTargetPassConfigCallback.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetOptions.h"
using namespace llvm; using namespace llvm;
@ -122,6 +123,7 @@ addPassesToGenerateCode(CodeGenTargetMachineImpl &TM, PassManagerBase &PM,
PassConfig->setDisableVerify(DisableVerify); PassConfig->setDisableVerify(DisableVerify);
PM.add(PassConfig); PM.add(PassConfig);
PM.add(&MMIWP); PM.add(&MMIWP);
invokeGlobalTargetPassConfigCallbacks(TM, PM, PassConfig);
if (PassConfig->addISelPasses()) if (PassConfig->addISelPasses())
return nullptr; return nullptr;

View File

@ -3,6 +3,7 @@ list(APPEND LLVM_COMMON_DEPENDS intrinsics_gen)
list(APPEND LLVM_TABLEGEN_FLAGS -I ${LLVM_MAIN_SRC_DIR}/lib/Target) list(APPEND LLVM_TABLEGEN_FLAGS -I ${LLVM_MAIN_SRC_DIR}/lib/Target)
add_llvm_component_library(LLVMTarget add_llvm_component_library(LLVMTarget
RegisterTargetPassConfigCallback.cpp
Target.cpp Target.cpp
TargetLoweringObjectFile.cpp TargetLoweringObjectFile.cpp
TargetMachine.cpp TargetMachine.cpp

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// This file contains the registry for PassConfigCallbacks that enable changes
/// to the TargetPassConfig during the initialization of TargetMachine.
///
//===----------------------------------------------------------------------===//
#include "llvm/Target/RegisterTargetPassConfigCallback.h"
namespace llvm {
// TargetPassConfig callbacks
static SmallVector<RegisterTargetPassConfigCallback *, 1>
TargetPassConfigCallbacks{};
void invokeGlobalTargetPassConfigCallbacks(TargetMachine &TM,
PassManagerBase &PM,
TargetPassConfig *PassConfig) {
for (const RegisterTargetPassConfigCallback *Reg : TargetPassConfigCallbacks)
Reg->Callback(TM, PM, PassConfig);
}
RegisterTargetPassConfigCallback::RegisterTargetPassConfigCallback(
PassConfigCallback &&C)
: Callback(std::move(C)) {
TargetPassConfigCallbacks.push_back(this);
}
RegisterTargetPassConfigCallback::~RegisterTargetPassConfigCallback() {
const auto &It = find(TargetPassConfigCallbacks, this);
if (It != TargetPassConfigCallbacks.end())
TargetPassConfigCallbacks.erase(It);
}
} // namespace llvm

View File

@ -0,0 +1,7 @@
; RUN: llc -load %llvmshlibdir/../unittests/CodeGen/CGPluginTest/CGTestPlugin%pluginext %s -o - | FileCheck %s
; REQUIRES: native, system-linux, llvm-dylib
; CHECK: CodeGen Test Pass running on main
define void @main() {
ret void
}

View File

@ -0,0 +1,20 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
Support
Core
MC
Target
TargetParser
CodeGen
)
add_llvm_unittest(CGPluginTest
PluginTest.cpp
Plugin/CodeGenTestPass.cpp
EXPORT_SYMBOLS
)
target_link_libraries(CGPluginTest PRIVATE LLVMTestingSupport)
unset(LLVM_LINK_COMPONENTS)
add_subdirectory(Plugin)

View File

@ -0,0 +1,17 @@
if (NOT WIN32 AND NOT CYGWIN)
unset(LLVM_LINK_COMPONENTS)
add_llvm_library(CGTestPlugin MODULE BUILDTREE_ONLY
CodeGenTestPass.cpp
Plugin.cpp
)
# Put PLUGIN next to the unit test executable.
set_output_directory(CGTestPlugin
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/../
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/../
)
set_target_properties(CGTestPlugin PROPERTIES FOLDER "Tests")
add_dependencies(CGTestPlugin intrinsics_gen vt_gen)
add_dependencies(CGPluginTest CGTestPlugin)
endif ()

View File

@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "CodeGenTestPass.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
using namespace llvm;
#define DEBUG_TYPE "codegen-test"
#define CODEGEN_TEST_NAME "CodeGen Test Pass"
CodeGenTest::CodeGenTest() : MachineFunctionPass(ID) {}
bool CodeGenTest::runOnMachineFunction(MachineFunction &MF) {
outs() << CODEGEN_TEST_NAME << " running on " << MF.getName()
<< "\n"; // used for the lit test
if (RunCallback)
RunCallback();
return true;
}
StringRef CodeGenTest::getPassName() const { return CODEGEN_TEST_NAME; }
char CodeGenTest::ID = 0;
std::function<void()> CodeGenTest::RunCallback;
INITIALIZE_PASS(CodeGenTest, DEBUG_TYPE, CODEGEN_TEST_NAME, false, false)

View File

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef CODEGEN_TEST_PASS
#define CODEGEN_TEST_PASS
#include <llvm/CodeGen/MachineFunctionPass.h>
using namespace llvm;
namespace llvm {
void initializeCodeGenTestPass(PassRegistry &);
} // namespace llvm
class CodeGenTest : public MachineFunctionPass {
public:
static char ID;
CodeGenTest();
bool runOnMachineFunction(MachineFunction &MF) override;
StringRef getPassName() const override;
static std::function<void()> RunCallback;
};
#endif // CODEGEN_TEST_PASS

View File

@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "CodeGenTestPass.h"
#include <llvm/CodeGen/Passes.h>
#include <llvm/CodeGen/TargetPassConfig.h>
#include <llvm/Target/RegisterTargetPassConfigCallback.h>
using namespace llvm;
namespace {
[[maybe_unused]] RegisterTargetPassConfigCallback X{
[](auto &TM, auto &PM, auto *TPC) {
TPC->insertPass(&GCLoweringID, &CodeGenTest::ID);
}};
} // namespace
__attribute__((constructor)) static void initCodeGenPlugin() {
initializeCodeGenTestPass(*PassRegistry::getPassRegistry());
}

View File

@ -0,0 +1,105 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "Plugin/CodeGenTestPass.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/Config/config.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/RegisterTargetPassConfigCallback.h"
#include "llvm/Target/TargetMachine.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
void anchor() {}
std::string libPath(const std::string &Name) {
const auto &Argvs = testing::internal::GetArgvs();
const char *Argv0 = Argvs.size() > 0 ? Argvs[0].c_str() : "CGPluginTest";
void *Ptr = (void *)(intptr_t)anchor;
std::string Path = sys::fs::getMainExecutable(Argv0, Ptr);
SmallString<256> Buf{sys::path::parent_path(Path)};
sys::path::append(Buf, (Name + LLVM_PLUGIN_EXT).c_str());
return std::string(Buf.str());
}
} // namespace
namespace llvm {
class CGPluginTests : public testing::Test {
protected:
static void SetUpTestCase() {
InitializeAllTargetMCs();
InitializeAllTargetInfos();
InitializeAllTargets();
}
};
} // namespace llvm
TEST_F(CGPluginTests, LoadPlugin) {
#if !defined(LLVM_ENABLE_PLUGINS)
// Skip the test if plugins are disabled.
GTEST_SKIP();
#endif
auto PluginPath = libPath("CGTestPlugin");
ASSERT_NE("", PluginPath);
std::string Error;
auto Library = sys::DynamicLibrary::getLibrary(PluginPath.c_str(), &Error);
ASSERT_TRUE(Library.isValid()) << Error;
sys::DynamicLibrary::closeLibrary(Library);
}
TEST_F(CGPluginTests, ExecuteCallback) {
#if !defined(LLVM_ENABLE_PLUGINS)
// Skip the test if plugins are disabled.
GTEST_SKIP();
#endif
volatile bool CallbackExecuted = false;
volatile bool MPassExecuted = false;
RegisterTargetPassConfigCallback X{[&](auto &TM, auto &PM, auto *TPC) {
CallbackExecuted = true;
TPC->insertPass(&GCLoweringID, &CodeGenTest::ID);
}};
CodeGenTest::RunCallback = [&] { MPassExecuted = true; };
TargetOptions Options;
std::unique_ptr<MCContext> MCC;
for (auto T : TargetRegistry::targets()) {
if (!T.hasTargetMachine())
continue;
Triple TT{T.getName(), "", ""};
auto *TM = T.createTargetMachine(TT, "", "", Options, std::nullopt,
std::nullopt, CodeGenOptLevel::Default);
ASSERT_TRUE(TM);
legacy::PassManager PM;
MCC.reset(new MCContext(TT, TM->getMCAsmInfo(), TM->getMCRegisterInfo(),
TM->getMCSubtargetInfo()));
auto *PtrMCC = MCC.get();
CallbackExecuted = false;
MPassExecuted = false;
if (TM->addPassesToEmitMC(PM, PtrMCC, outs()) == true)
continue;
ASSERT_TRUE(CallbackExecuted) << T.getName() << " callback failed";
ASSERT_TRUE(MPassExecuted) << T.getName() << " MachinePass failed";
}
}

View File

@ -51,5 +51,6 @@ add_llvm_unittest(CodeGenTests
) )
add_subdirectory(GlobalISel) add_subdirectory(GlobalISel)
add_subdirectory(CGPluginTest)
target_link_libraries(CodeGenTests PRIVATE LLVMTestingSupport) target_link_libraries(CodeGenTests PRIVATE LLVMTestingSupport)