[flang-commits] [clang] [flang] [lld] [llvm] Test entry-points for pass-plugins with Bye in clang, flang and lld (PR #172463)
via flang-commits
flang-commits at lists.llvm.org
Tue Dec 16 03:36:47 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld
Author: Stefan Gränitz (weliveindetail)
<details>
<summary>Changes</summary>
LLVM pass-plugins are loaded into various tools. Plugins can register passes at different stages of the pipeline, called entry-points. Depending on the pipeline's configuration, different entry-points will be exercised. AFAIK there is no documentation on which entry-points are supposed to be exercised under which conditions. This patch adds regression tests for the status quo in the major consumers of pass-plugins.
---
Full diff: https://github.com/llvm/llvm-project/pull/172463.diff
10 Files Affected:
- (modified) clang/test/CMakeLists.txt (+6)
- (added) clang/test/CodeGen/pass-plugins-entrypoints.c (+66)
- (added) clang/test/Interpreter/pass-plugins.cpp (+9)
- (modified) clang/test/lit.cfg.py (+2)
- (modified) clang/test/lit.site.cfg.py.in (+1)
- (added) flang/test/Integration/pass-plugins-entrypoints.f90 (+64)
- (modified) flang/test/lit.cfg.py (+3-2)
- (modified) flang/test/lit.site.cfg.py.in (+1-1)
- (modified) lld/test/ELF/lto/ltopasses-extension.ll (+36-1)
- (modified) llvm/examples/Bye/Bye.cpp (+101-15)
``````````diff
diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt
index bcb6bd68fafc2..05b0ee42da42b 100644
--- a/clang/test/CMakeLists.txt
+++ b/clang/test/CMakeLists.txt
@@ -134,6 +134,12 @@ if(CLANG_BUILD_EXAMPLES AND CLANG_PLUGIN_SUPPORT)
)
endif ()
+if(LLVM_BUILD_EXAMPLES AND NOT WIN32)
+ list(APPEND CLANG_TEST_DEPS
+ Bye
+ )
+endif()
+
if(LLVM_INCLUDE_SPIRV_TOOLS_TESTS)
list(APPEND CLANG_TEST_DEPS
spirv-dis
diff --git a/clang/test/CodeGen/pass-plugins-entrypoints.c b/clang/test/CodeGen/pass-plugins-entrypoints.c
new file mode 100644
index 0000000000000..90182961b8057
--- /dev/null
+++ b/clang/test/CodeGen/pass-plugins-entrypoints.c
@@ -0,0 +1,66 @@
+// REQUIRES: plugins, llvm-examples
+
+// Entry-points in default and -O0 pipeline
+//
+// RUN: %clang -fpass-plugin=%llvmshlibdir/Bye%pluginext \
+// RUN: -Xclang -load -Xclang %llvmshlibdir/Bye%pluginext \
+// RUN: -mllvm -print-ep-callbacks -o /dev/null -S -emit-llvm %s | FileCheck --check-prefix=EP %s
+//
+// RUN: %clang -fpass-plugin=%llvmshlibdir/Bye%pluginext -flto=full -O0 \
+// RUN: -Xclang -load -Xclang %llvmshlibdir/Bye%pluginext \
+// RUN: -mllvm -print-ep-callbacks -o /dev/null -S -emit-llvm %s | FileCheck --check-prefix=EP %s
+//
+// RUN: %clang -fpass-plugin=%llvmshlibdir/Bye%pluginext -flto=thin -O0 \
+// RUN: -Xclang -load -Xclang %llvmshlibdir/Bye%pluginext \
+// RUN: -mllvm -print-ep-callbacks -o /dev/null -S -emit-llvm %s | FileCheck --check-prefix=EP %s
+//
+// EP: PipelineStart
+// EP: PipelineEarlySimplification
+// EP-NOT: Peephole
+// EP-NOT: ScalarOptimizerLate
+// EP-NOT: Peephole
+// EP: OptimizerEarly
+// EP-NOT: Vectorizer
+// EP: OptimizerLast
+
+// Entry-points in optimizer pipeline
+//
+// RUN: %clang -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 \
+// RUN: -Xclang -load -Xclang %llvmshlibdir/Bye%pluginext \
+// RUN: -mllvm -print-ep-callbacks -o /dev/null -S -emit-llvm %s | FileCheck --check-prefix=EP-OPT %s
+//
+// RUN: %clang -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 -flto=full \
+// RUN: -Xclang -load -Xclang %llvmshlibdir/Bye%pluginext \
+// RUN: -mllvm -print-ep-callbacks -o /dev/null -S -emit-llvm %s | FileCheck --check-prefix=EP-OPT %s
+//
+// RUN: %clang -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 -ffat-lto-objects \
+// RUN: -Xclang -load -Xclang %llvmshlibdir/Bye%pluginext \
+// RUN: -mllvm -print-ep-callbacks -o /dev/null -S -emit-llvm %s | FileCheck --check-prefix=EP-OPT %s
+//
+// EP-OPT: PipelineStart
+// EP-OPT: PipelineEarlySimplification
+// EP-OPT: Peephole
+// EP-OPT: ScalarOptimizerLate
+// EP-OPT: Peephole
+// EP-OPT: OptimizerEarly
+// EP-OPT: VectorizerStart
+// EP-OPT: VectorizerEnd
+// EP-OPT: OptimizerLast
+
+// FIXME: Thin-LTO does not invoke vectorizer callbacks
+//
+// RUN: %clang -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 -flto=thin \
+// RUN: -Xclang -load -Xclang %llvmshlibdir/Bye%pluginext \
+// RUN: -mllvm -print-ep-callbacks -o /dev/null -S -emit-llvm %s | FileCheck --check-prefix=EP-LTO-THIN %s
+//
+// EP-LTO-THIN: PipelineStart
+// EP-LTO-THIN: PipelineEarlySimplification
+// EP-LTO-THIN: Peephole
+// EP-LTO-THIN: ScalarOptimizerLate
+// EP-LTO-THIN: OptimizerEarly
+// EP-LTO-THIN-NOT: Vectorizer
+// EP-LTO-THIN: OptimizerLast
+
+int f(int x) {
+ return x;
+}
diff --git a/clang/test/Interpreter/pass-plugins.cpp b/clang/test/Interpreter/pass-plugins.cpp
new file mode 100644
index 0000000000000..4d445807c3d70
--- /dev/null
+++ b/clang/test/Interpreter/pass-plugins.cpp
@@ -0,0 +1,9 @@
+// RUN: cat %s | clang-repl -Xcc -fpass-plugin=%plugindir/pypass-plugin%pluginext \
+// RUN: -Xcc -load=%plugindir/pypass-plugin%pluginext \
+// RUN: -Xcc -Xclang -Xcc -mllvm -Xcc -wave-goodbye | FileCheck %s
+// REQUIRES: plugins, llvm-examples
+
+int i = 10;
+%quit
+
+// CHECK: Bye
diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py
index 52b275c095475..a622f5335354a 100644
--- a/clang/test/lit.cfg.py
+++ b/clang/test/lit.cfg.py
@@ -126,6 +126,8 @@
if config.clang_examples:
config.available_features.add("examples")
+if config.llvm_examples:
+ config.available_features.add("llvm-examples")
def have_host_out_of_process_jit_feature_support():
diff --git a/clang/test/lit.site.cfg.py.in b/clang/test/lit.site.cfg.py.in
index f50953a93a412..8e0ecdbe07805 100644
--- a/clang/test/lit.site.cfg.py.in
+++ b/clang/test/lit.site.cfg.py.in
@@ -28,6 +28,7 @@ config.clang_staticanalyzer_z3 = @LLVM_WITH_Z3@
config.clang_staticanalyzer_z3_mock = @TEST_WITH_Z3_MOCK@
config.clang_enable_cir = @CLANG_ENABLE_CIR@
config.clang_examples = @CLANG_BUILD_EXAMPLES@
+config.llvm_examples = @LLVM_BUILD_EXAMPLES@
config.enable_shared = @ENABLE_SHARED@
config.enable_backtrace = @ENABLE_BACKTRACES@
config.enable_threads = @LLVM_ENABLE_THREADS@
diff --git a/flang/test/Integration/pass-plugins-entrypoints.f90 b/flang/test/Integration/pass-plugins-entrypoints.f90
new file mode 100644
index 0000000000000..6bbb3421f2dc4
--- /dev/null
+++ b/flang/test/Integration/pass-plugins-entrypoints.f90
@@ -0,0 +1,64 @@
+! REQUIRES: plugins, examples
+
+! Entry-points in default and -O0 pipeline
+!
+! RUN: %flang -fpass-plugin=%llvmshlibdir/Bye%pluginext \
+! RUN: -Xflang -load -Xflang %llvmshlibdir/Bye%pluginext \
+! RUN: -mllvm -print-ep-callbacks -o /dev/null -S %s | FileCheck --check-prefix=EP %s
+!
+! RUN: %flang -fpass-plugin=%llvmshlibdir/Bye%pluginext -flto=full -O0 \
+! RUN: -Xflang -load -Xflang %llvmshlibdir/Bye%pluginext \
+! RUN: -mllvm -print-ep-callbacks -o /dev/null -S %s | FileCheck --check-prefix=EP %s
+!
+! RUN: %flang -fpass-plugin=%llvmshlibdir/Bye%pluginext -flto=thin -O0 \
+! RUN: -Xflang -load -Xflang %llvmshlibdir/Bye%pluginext \
+! RUN: -mllvm -print-ep-callbacks -o /dev/null -S %s | FileCheck --check-prefix=EP %s
+!
+! EP: PipelineStart
+! EP: PipelineEarlySimplification
+! EP-NOT: Peephole
+! EP: ScalarOptimizerLate
+! EP-NOT: Peephole
+! EP: OptimizerEarly
+! EP: VectorizerStart
+! EP: VectorizerEnd
+! EP: OptimizerLast
+
+! Entry-points in optimizer pipeline
+!
+! RUN: %flang -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 \
+! RUN: -Xflang -load -Xflang %llvmshlibdir/Bye%pluginext \
+! RUN: -mllvm -print-ep-callbacks -o /dev/null -S %s | FileCheck --check-prefix=EP-OPT %s
+!
+! RUN: %flang -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 -flto=full \
+! RUN: -Xflang -load -Xflang %llvmshlibdir/Bye%pluginext \
+! RUN: -mllvm -print-ep-callbacks -o /dev/null -S %s | FileCheck --check-prefix=EP-OPT %s
+!
+! EP-OPT: PipelineStart
+! EP-OPT: PipelineEarlySimplification
+! EP-OPT: Peephole
+! EP-OPT: ScalarOptimizerLate
+! EP-OPT: Peephole
+! EP-OPT: OptimizerEarly
+! EP-OPT: VectorizerStart
+! EP-OPT: VectorizerEnd
+! EP-OPT: OptimizerLast
+
+! FIXME: Thin-LTO does not invoke vectorizer callbacks
+!
+! RUN: %flang -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 -flto=thin \
+! RUN: -Xflang -load -Xflang %llvmshlibdir/Bye%pluginext \
+! RUN: -mllvm -print-ep-callbacks -o /dev/null -S %s | FileCheck --check-prefix=EP-LTO-THIN %s
+!
+! EP-LTO-THIN: PipelineStart
+! EP-LTO-THIN: PipelineEarlySimplification
+! EP-LTO-THIN: Peephole
+! EP-LTO-THIN: ScalarOptimizerLate
+! EP-LTO-THIN: OptimizerEarly
+! EP-LTO-THIN-NOT: Vectorizer
+! EP-LTO-THIN: OptimizerLast
+
+INTEGER FUNCTION f(x)
+ INTEGER, INTENT(IN) :: x
+ f = x
+END FUNCTION f
diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py
index 4221354df34a2..1d8a1704e6838 100644
--- a/flang/test/lit.cfg.py
+++ b/flang/test/lit.cfg.py
@@ -90,8 +90,9 @@
# directories.
config.excludes = ["Inputs", "CMakeLists.txt", "README.txt", "LICENSE.txt"]
-# If the flang examples are built, add examples to the config
-if config.flang_examples:
+# Some tests depend on examples, mark them as available in the config. This
+# setting includes examples from both, flang and llvm.
+if config.build_examples:
config.available_features.add("examples")
# Plugins (loadable modules)
diff --git a/flang/test/lit.site.cfg.py.in b/flang/test/lit.site.cfg.py.in
index cc1f4fa6cc9c5..1422cc36232cb 100644
--- a/flang/test/lit.site.cfg.py.in
+++ b/flang/test/lit.site.cfg.py.in
@@ -17,7 +17,7 @@ config.flang_intrinsic_modules_dir = "@FLANG_INTRINSIC_MODULES_DIR@"
config.flang_headers_dir = "@HEADER_BINARY_DIR@"
config.flang_llvm_tools_dir = "@CMAKE_BINARY_DIR@/bin"
config.flang_test_triple = "@FLANG_TEST_TARGET_TRIPLE@"
-config.flang_examples = @LLVM_BUILD_EXAMPLES@
+config.build_examples = @LLVM_BUILD_EXAMPLES@
config.python_executable = "@PYTHON_EXECUTABLE@"
config.flang_standalone_build = @FLANG_STANDALONE_BUILD@
config.has_plugins = @LLVM_ENABLE_PLUGINS@
diff --git a/lld/test/ELF/lto/ltopasses-extension.ll b/lld/test/ELF/lto/ltopasses-extension.ll
index db8edbb8e087d..ce92176d07249 100644
--- a/lld/test/ELF/lto/ltopasses-extension.ll
+++ b/lld/test/ELF/lto/ltopasses-extension.ll
@@ -1,9 +1,44 @@
; REQUIRES: x86, plugins, examples
; UNSUPPORTED: target={{.*windows.*}}
-; RUN: opt -module-summary %s -o %t.o
+; RUN: opt %s -o %t.o
+; RUN: opt -module-summary %s -o %t_thin.o
+
; RUN: ld.lld -%loadnewpmbye --lto-newpm-passes="goodbye" -mllvm=%loadbye -mllvm=-wave-goodbye %t.o -o /dev/null 2>&1 | FileCheck %s
; CHECK: Bye
+; Entry-points in pipeline for regular/monolithic LTO
+;
+; RUN: ld.lld -%loadnewpmbye -mllvm=%loadbye -mllvm=-print-ep-callbacks %t.o \
+; RUN: -shared -o /dev/null | FileCheck --check-prefix=REGULAR %s
+;
+; REGULAR-NOT: PipelineStart
+; REGULAR-NOT: PipelineEarlySimplification
+; REGULAR-NOT: Peephole
+; REGULAR-NOT: ScalarOptimizerLate
+; REGULAR-NOT: Vectorizer
+; REGULAR-NOT: Optimizer
+;
+; REGULAR: FullLinkTimeOptimizationEarly
+; REGULAR: FullLinkTimeOptimizationLast
+
+; Entry-points in Thin-LTO pipeline
+;
+; RUN: ld.lld -%loadnewpmbye -mllvm=%loadbye -mllvm=-print-ep-callbacks %t_thin.o \
+; RUN: -shared -o /dev/null | FileCheck --check-prefix=THIN %s
+;
+; THIN-NOT: FullLinkTimeOptimizationEarly
+; THIN-NOT: FullLinkTimeOptimizationLast
+; THIN-NOT: PipelineStart
+;
+; THIN: PipelineEarlySimplification
+; THIN: Peephole
+; THIN: ScalarOptimizerLate
+; THIN: Peephole
+; THIN: OptimizerEarly
+; THIN: VectorizerStart
+; THIN: VectorizerEnd
+; THIN: OptimizerLast
+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@junk = global i32 0
diff --git a/llvm/examples/Bye/Bye.cpp b/llvm/examples/Bye/Bye.cpp
index d88bf9e490e9c..5108cf4b3d0c0 100644
--- a/llvm/examples/Bye/Bye.cpp
+++ b/llvm/examples/Bye/Bye.cpp
@@ -11,6 +11,10 @@ using namespace llvm;
static cl::opt<bool> Wave("wave-goodbye", cl::init(false),
cl::desc("wave good bye"));
+static cl::opt<bool> PrintEntryPointCallbacks(
+ "print-ep-callbacks", cl::init(false),
+ cl::desc("Print names of all entry-points upon callback"));
+
namespace {
bool runBye(Function &F) {
@@ -35,6 +39,102 @@ struct Bye : PassInfoMixin<Bye> {
}
};
+struct PrintStage : PassInfoMixin<Bye> {
+ PrintStage(std::string Name) : Name(std::move(Name)) {}
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
+ outs() << Name << "\n";
+ return PreservedAnalyses::none();
+ }
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
+ outs() << Name << "\n";
+ return PreservedAnalyses::none();
+ }
+
+private:
+ std::string Name;
+};
+
+void registerPassBuilderCallbacks(PassBuilder &PB) {
+ PB.registerVectorizerStartEPCallback(
+ [](llvm::FunctionPassManager &PM, OptimizationLevel Level) {
+ PM.addPass(Bye());
+ });
+ PB.registerPipelineParsingCallback(
+ [](StringRef Name, llvm::FunctionPassManager &PM,
+ ArrayRef<llvm::PassBuilder::PipelineElement>) {
+ if (Name == "goodbye") {
+ PM.addPass(Bye());
+ return true;
+ }
+ return false;
+ });
+
+ if (PrintEntryPointCallbacks) {
+ PB.registerPipelineStartEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel Opt) {
+ MPM.addPass(PrintStage("PipelineStart"));
+ return true;
+ });
+
+ PB.registerPipelineEarlySimplificationEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel Opt,
+ ThinOrFullLTOPhase Phase) {
+ MPM.addPass(PrintStage("PipelineEarlySimplification"));
+ return true;
+ });
+
+ PB.registerOptimizerEarlyEPCallback([](ModulePassManager &MPM,
+ OptimizationLevel Opt,
+ ThinOrFullLTOPhase Phase) {
+ MPM.addPass(PrintStage("OptimizerEarly"));
+ return true;
+ });
+
+ PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
+ OptimizationLevel Opt,
+ ThinOrFullLTOPhase Phase) {
+ MPM.addPass(PrintStage("OptimizerLast"));
+ return true;
+ });
+
+ PB.registerPeepholeEPCallback(
+ [](FunctionPassManager &FPM, OptimizationLevel Opt) {
+ FPM.addPass(PrintStage("Peephole"));
+ return true;
+ });
+
+ PB.registerScalarOptimizerLateEPCallback(
+ [](FunctionPassManager &FPM, OptimizationLevel Opt) {
+ FPM.addPass(PrintStage("ScalarOptimizerLate"));
+ return true;
+ });
+
+ PB.registerVectorizerStartEPCallback(
+ [](FunctionPassManager &FPM, OptimizationLevel Opt) {
+ FPM.addPass(PrintStage("VectorizerStart"));
+ return true;
+ });
+
+ PB.registerVectorizerEndEPCallback(
+ [](FunctionPassManager &FPM, OptimizationLevel Opt) {
+ FPM.addPass(PrintStage("VectorizerEnd"));
+ return true;
+ });
+
+ PB.registerFullLinkTimeOptimizationEarlyEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel Opt) {
+ MPM.addPass(PrintStage("FullLinkTimeOptimizationEarly"));
+ return true;
+ });
+
+ PB.registerFullLinkTimeOptimizationLastEPCallback(
+ [](ModulePassManager &MPM, OptimizationLevel Opt) {
+ MPM.addPass(PrintStage("FullLinkTimeOptimizationLast"));
+ return true;
+ });
+ }
+}
+
} // namespace
char LegacyBye::ID = 0;
@@ -46,21 +146,7 @@ static RegisterPass<LegacyBye> X("goodbye", "Good Bye World Pass",
/* New PM Registration */
llvm::PassPluginLibraryInfo getByePluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "Bye", LLVM_VERSION_STRING,
- [](PassBuilder &PB) {
- PB.registerVectorizerStartEPCallback(
- [](llvm::FunctionPassManager &PM, OptimizationLevel Level) {
- PM.addPass(Bye());
- });
- PB.registerPipelineParsingCallback(
- [](StringRef Name, llvm::FunctionPassManager &PM,
- ArrayRef<llvm::PassBuilder::PipelineElement>) {
- if (Name == "goodbye") {
- PM.addPass(Bye());
- return true;
- }
- return false;
- });
- }};
+ registerPassBuilderCallbacks};
}
#ifndef LLVM_BYE_LINK_INTO_TOOLS
``````````
</details>
https://github.com/llvm/llvm-project/pull/172463
More information about the flang-commits
mailing list