[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