[flang-commits] [flang] [Flang] Adjust pass plugin support to match Clang (PR #174006)
via flang-commits
flang-commits at lists.llvm.org
Tue Dec 30 08:59:14 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-driver
Author: Alexis Engelke (aengelke)
<details>
<summary>Changes</summary>
- Pass plugins can use LLVM options, matching #<!-- -->173287.
- Pass plugins can run a hook before codegen, matching #<!-- -->171872.
- Pass plugins are now tested whenever they can be built, matching #<!-- -->171998.
---
Full diff: https://github.com/llvm/llvm-project/pull/174006.diff
8 Files Affected:
- (modified) flang/include/flang/Frontend/CompilerInstance.h (+17-1)
- (modified) flang/lib/Frontend/FrontendActions.cpp (+45-21)
- (modified) flang/lib/FrontendTool/CMakeLists.txt (+1)
- (modified) flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp (+14)
- (modified) flang/test/CMakeLists.txt (+3-3)
- (added) flang/test/Driver/pass-plugin-codegen.f90 (+26)
- (modified) flang/test/Driver/pass-plugin.f90 (+3-3)
- (modified) flang/test/lit.site.cfg.py.in (+1-1)
``````````diff
diff --git a/flang/include/flang/Frontend/CompilerInstance.h b/flang/include/flang/Frontend/CompilerInstance.h
index 4234e13597cd7..0c54013881acd 100644
--- a/flang/include/flang/Frontend/CompilerInstance.h
+++ b/flang/include/flang/Frontend/CompilerInstance.h
@@ -20,6 +20,7 @@
#include "flang/Semantics/runtime-type-info.h"
#include "flang/Semantics/semantics.h"
#include "flang/Support/StringOstream.h"
+#include "llvm/Plugins/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
@@ -60,6 +61,9 @@ class CompilerInstance {
std::unique_ptr<llvm::TargetMachine> targetMachine;
+ /// Back-end pass plugins.
+ std::vector<std::unique_ptr<llvm::PassPlugin>> passPlugins;
+
/// The stream for diagnostics from Semantics
llvm::raw_ostream *semaOutputStream = &llvm::errs();
@@ -261,7 +265,19 @@ class CompilerInstance {
createDefaultOutputFile(bool binary = true, llvm::StringRef baseInput = "",
llvm::StringRef extension = "");
- /// {
+ /// }
+ /// @name Back-end Pass Plugins
+ /// @{
+
+ void addPassPlugin(std::unique_ptr<llvm::PassPlugin> plugin) {
+ passPlugins.emplace_back(std::move(plugin));
+ }
+
+ llvm::ArrayRef<std::unique_ptr<llvm::PassPlugin>> getPassPlugins() const {
+ return passPlugins;
+ }
+
+ /// }
/// @name Target Machine
/// {
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 5c0311ccab8fd..53e7cbfa13380 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -47,6 +47,7 @@
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
+#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Verifier.h"
@@ -882,15 +883,23 @@ getOutputStream(CompilerInstance &ci, llvm::StringRef inFile,
/// \param [in] llvmModule LLVM module to lower to assembly/machine-code
/// \param [in] codeGenOpts options configuring codegen pipeline
/// \param [out] os Output stream to emit the generated code to
-static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags,
- llvm::TargetMachine &tm,
- BackendActionTy act,
- llvm::Module &llvmModule,
- const CodeGenOptions &codeGenOpts,
- llvm::raw_pwrite_stream &os) {
+static void generateMachineCodeOrAssemblyImpl(
+ CompilerInstance &ci, clang::DiagnosticsEngine &diags,
+ llvm::TargetMachine &tm, BackendActionTy act, llvm::Module &llvmModule,
+ const CodeGenOptions &codeGenOpts, llvm::raw_pwrite_stream &os) {
assert(((act == BackendActionTy::Backend_EmitObj) ||
(act == BackendActionTy::Backend_EmitAssembly)) &&
"Unsupported action");
+ llvm::CodeGenFileType cgft = (act == BackendActionTy::Backend_EmitAssembly)
+ ? llvm::CodeGenFileType::AssemblyFile
+ : llvm::CodeGenFileType::ObjectFile;
+
+ // Invoke pre-codegen callback from plugin, which might want to take over the
+ // entire code generation itself.
+ for (const std::unique_ptr<llvm::PassPlugin> &plugin : ci.getPassPlugins()) {
+ if (plugin->invokePreCodeGenCallback(llvmModule, tm, cgft, os))
+ return;
+ }
// Set-up the pass manager, i.e create an LLVM code-gen pass pipeline.
// Currently only the legacy pass manager is supported.
@@ -907,9 +916,6 @@ static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags,
triple, tm.Options.ExceptionModel, tm.Options.FloatABIType,
tm.Options.EABIVersion, tm.Options.MCOptions.ABIName, tm.Options.VecLib));
- llvm::CodeGenFileType cgft = (act == BackendActionTy::Backend_EmitAssembly)
- ? llvm::CodeGenFileType::AssemblyFile
- : llvm::CodeGenFileType::ObjectFile;
std::unique_ptr<llvm::ToolOutputFile> dwoOS;
if (!codeGenOpts.SplitDwarfOutput.empty()) {
std::error_code ec;
@@ -943,7 +949,6 @@ static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags,
void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
CompilerInstance &ci = getInstance();
const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts();
- clang::DiagnosticsEngine &diags = ci.getDiagnostics();
llvm::OptimizationLevel level = mapToLevel(opts);
llvm::TargetMachine *targetMachine = &ci.getTargetMachine();
@@ -992,16 +997,9 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
llvm::PassBuilder pb(targetMachine, pto, pgoOpt, &pic);
- // Attempt to load pass plugins and register their callbacks with PB.
- for (auto &pluginFile : opts.LLVMPassPlugins) {
- auto passPlugin = llvm::PassPlugin::Load(pluginFile);
- if (passPlugin) {
- passPlugin->registerPassBuilderCallbacks(pb);
- } else {
- diags.Report(clang::diag::err_fe_unable_to_load_plugin)
- << pluginFile << passPlugin.takeError();
- }
- }
+ // Register plugin callbacks with PB.
+ for (const std::unique_ptr<llvm::PassPlugin> &plugin : ci.getPassPlugins())
+ plugin->registerPassBuilderCallbacks(pb);
// Register static plugin extensions.
#define HANDLE_EXTENSION(Ext) \
get##Ext##PluginInfo().RegisterPassBuilderCallbacks(pb);
@@ -1185,6 +1183,31 @@ class BackendRemarkConsumer : public llvm::DiagnosticHandler {
clang::diag::remark_fe_backend_optimization_remark_analysis);
}
+ void backendPluginHandler(const llvm::DiagnosticInfo &di) {
+ unsigned diagID;
+ switch (di.getSeverity()) {
+ case llvm::DS_Error:
+ diagID = clang::diag::err_fe_backend_plugin;
+ break;
+ case llvm::DS_Warning:
+ diagID = clang::diag::warn_fe_backend_plugin;
+ break;
+ case llvm::DS_Remark:
+ diagID = clang::diag::remark_fe_backend_plugin;
+ break;
+ case llvm::DS_Note:
+ diagID = clang::diag::note_fe_backend_plugin;
+ break;
+ }
+ std::string msg;
+ {
+ llvm::raw_string_ostream os(msg);
+ llvm::DiagnosticPrinterRawOStream diagPrinter(os);
+ di.print(diagPrinter);
+ }
+ diags.Report(diagID) << msg;
+ }
+
bool handleDiagnostics(const llvm::DiagnosticInfo &di) override {
switch (di.getKind()) {
case llvm::DK_OptimizationRemark:
@@ -1210,6 +1233,7 @@ class BackendRemarkConsumer : public llvm::DiagnosticHandler {
llvm::cast<llvm::MachineOptimizationRemarkAnalysis>(di));
break;
default:
+ backendPluginHandler(di);
break;
}
return true;
@@ -1438,7 +1462,7 @@ void CodeGenAction::executeAction() {
if (action == BackendActionTy::Backend_EmitAssembly ||
action == BackendActionTy::Backend_EmitObj) {
generateMachineCodeOrAssemblyImpl(
- diags, targetMachine, action, *llvmModule, codeGenOpts,
+ ci, diags, targetMachine, action, *llvmModule, codeGenOpts,
ci.isOutputStreamNull() ? *os : ci.getOutputStream());
if (timingMgr.isEnabled())
llvm::reportAndResetTimings(&ci.getTimingStreamCodeGen());
diff --git a/flang/lib/FrontendTool/CMakeLists.txt b/flang/lib/FrontendTool/CMakeLists.txt
index b69436c36d438..666fab1a6e2c0 100644
--- a/flang/lib/FrontendTool/CMakeLists.txt
+++ b/flang/lib/FrontendTool/CMakeLists.txt
@@ -11,6 +11,7 @@ add_flang_library(flangFrontendTool
LINK_COMPONENTS
Option
+ Plugins
Support
MLIR_LIBS
diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 7586be59ba01b..8de19822be510 100644
--- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -26,6 +26,7 @@
#include "clang/Options/Options.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
+#include "llvm/Plugins/PassPlugin.h"
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/CommandLine.h"
@@ -177,6 +178,19 @@ bool executeCompilerInvocation(CompilerInstance *flang) {
}
}
+ // Load and store pass plugins for the back-end.
+ for (const std::string &path :
+ flang->getInvocation().getCodeGenOpts().LLVMPassPlugins) {
+ if (auto passPlugin = llvm::PassPlugin::Load(path)) {
+ flang->addPassPlugin(std::make_unique<llvm::PassPlugin>(*passPlugin));
+ } else {
+ unsigned diagID = flang->getDiagnostics().getCustomDiagID(
+ clang::DiagnosticsEngine::Error, "unable to load plugin '%0': '%1'");
+ flang->getDiagnostics().Report(diagID)
+ << path << toString(passPlugin.takeError());
+ }
+ }
+
// Honor -mllvm. This should happen AFTER plugins have been loaded!
if (!flang->getFrontendOpts().llvmArgs.empty()) {
unsigned numArgs = flang->getFrontendOpts().llvmArgs.size();
diff --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt
index 8c8e92faa787a..d3da00c755cf8 100644
--- a/flang/test/CMakeLists.txt
+++ b/flang/test/CMakeLists.txt
@@ -4,9 +4,9 @@ add_subdirectory(lib)
llvm_canonicalize_cmake_booleans(
FLANG_STANDALONE_BUILD
- LLVM_BUILD_EXAMPLES
LLVM_BYE_LINK_INTO_TOOLS
LLVM_ENABLE_PLUGINS
+ LLVM_INCLUDE_EXAMPLES
)
set(FLANG_TOOLS_DIR ${FLANG_BINARY_DIR}/bin)
@@ -83,7 +83,7 @@ if (NOT FLANG_STANDALONE_BUILD)
)
endif ()
-if (LLVM_BUILD_EXAMPLES AND LLVM_ENABLE_PLUGINS AND NOT (WIN32 OR CYGWIN) AND NOT FLANG_STANDALONE_BUILD)
+if (LLVM_INCLUDE_EXAMPLES AND LLVM_ENABLE_PLUGINS AND NOT (WIN32 OR CYGWIN) AND NOT FLANG_STANDALONE_BUILD)
list(APPEND FLANG_TEST_DEPENDS Bye)
endif()
@@ -93,7 +93,7 @@ if (FLANG_INCLUDE_TESTS)
endif()
endif()
-if (LLVM_BUILD_EXAMPLES)
+if (LLVM_INCLUDE_EXAMPLES)
list(APPEND FLANG_TEST_DEPENDS
flangPrintFunctionNames
flangOmpReport
diff --git a/flang/test/Driver/pass-plugin-codegen.f90 b/flang/test/Driver/pass-plugin-codegen.f90
new file mode 100644
index 0000000000000..7f3e0eeca01f2
--- /dev/null
+++ b/flang/test/Driver/pass-plugin-codegen.f90
@@ -0,0 +1,26 @@
+! Verify that the static and dynamically loaded pass plugins work as expected.
+
+! UNSUPPORTED: system-windows
+
+! REQUIRES: plugins, shell, examples
+
+! RUN: %flang_fc1 -S %s -o - %loadbye \
+! RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-INACTIVE
+
+! RUN: %flang_fc1 -S %s -o - %loadbye -mllvm -last-words \
+! RUN: | FileCheck %s --check-prefix=CHECK-ACTIVE
+
+! RUN: %flang_fc1 -emit-llvm %s -o - %loadbye -mllvm -last-words \
+! RUN: | FileCheck %s --check-prefix=CHECK-LLVM
+
+! RUN: not %flang_fc1 -emit-obj %s -o - %loadbye -mllvm -last-words \
+! RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-ERR
+
+! CHECK-INACTIVE-NOT: Bye
+! CHECK-INACTIVE: empty_:
+! CHECK-ACTIVE: CodeGen Bye
+! CHECK-LLVM: define{{.*}} void @empty_
+! CHECK-ERR: error: last words unsupported for binary output
+
+subroutine empty
+end subroutine empty
diff --git a/flang/test/Driver/pass-plugin.f90 b/flang/test/Driver/pass-plugin.f90
index 8c8c4c70def86..9fae67b3d7fa4 100644
--- a/flang/test/Driver/pass-plugin.f90
+++ b/flang/test/Driver/pass-plugin.f90
@@ -4,14 +4,14 @@
! REQUIRES: plugins, shell, examples
-! RUN: %flang -S %s %loadbye -Xflang -fdebug-pass-manager -o /dev/null \
+! RUN: %flang -S %s %loadbye -mllvm -wave-goodbye -o /dev/null \
! RUN: 2>&1 | FileCheck %s
-! RUN: %flang_fc1 -S %s %loadbye -fdebug-pass-manager -o /dev/null \
+! RUN: %flang_fc1 -S %s %loadbye -mllvm -wave-goodbye -o /dev/null \
! RUN: 2>&1 | FileCheck %s
-! CHECK: Running pass: {{.*}}Bye on empty_
+! CHECK: Bye: empty_
subroutine empty
end subroutine empty
diff --git a/flang/test/lit.site.cfg.py.in b/flang/test/lit.site.cfg.py.in
index cc1f4fa6cc9c5..2b66dd64b8c13 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.flang_examples = @LLVM_INCLUDE_EXAMPLES@
config.python_executable = "@PYTHON_EXECUTABLE@"
config.flang_standalone_build = @FLANG_STANDALONE_BUILD@
config.has_plugins = @LLVM_ENABLE_PLUGINS@
``````````
</details>
https://github.com/llvm/llvm-project/pull/174006
More information about the flang-commits
mailing list