Skip to content

Reland "[Clang] Load pass plugins before parsing LLVM options" (#171868)#173287

Merged
aengelke merged 1 commit into
mainfrom
users/aengelke/spr/reland-clang-load-pass-plugins-before-parsing-llvm-options-171868
Dec 22, 2025
Merged

Reland "[Clang] Load pass plugins before parsing LLVM options" (#171868)#173287
aengelke merged 1 commit into
mainfrom
users/aengelke/spr/reland-clang-load-pass-plugins-before-parsing-llvm-options-171868

Conversation

@aengelke
Copy link
Copy Markdown
Contributor

This permits pass plugins to use llvm::cl::opt. Additionally, add a test
of -fpass-plugin, this was previously not tested at all.

I'm not sure whether using the LLVM Bye.so in the tests is possible this
way (e.g., if Clang is built standalone).

Reland after #173279.

Created using spr 1.3.5-bogner
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Dec 22, 2025
@aengelke aengelke added skip-precommit-approval PR for CI feedback, not intended for review and removed clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Dec 22, 2025
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Dec 22, 2025

@llvm/pr-subscribers-clang

Author: Alexis Engelke (aengelke)

Changes

This permits pass plugins to use llvm::cl::opt. Additionally, add a test
of -fpass-plugin, this was previously not tested at all.

I'm not sure whether using the LLVM Bye.so in the tests is possible this
way (e.g., if Clang is built standalone).

Reland after #173279.


Full diff: https://github.com/llvm/llvm-project/pull/173287.diff

8 Files Affected:

  • (modified) clang/include/clang/Frontend/CompilerInstance.h (+12)
  • (modified) clang/lib/CodeGen/BackendUtil.cpp (+3-10)
  • (modified) clang/lib/Frontend/CMakeLists.txt (+1)
  • (modified) clang/lib/Frontend/CompilerInstance.cpp (+11)
  • (modified) clang/test/CMakeLists.txt (+7-1)
  • (added) clang/test/CodeGen/pass-plugins.c (+10)
  • (modified) clang/test/lit.cfg.py (+2)
  • (modified) clang/test/lit.site.cfg.py.in (+1)
diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index a8e8461b9b5a9..ded5f55d180aa 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -36,6 +36,7 @@
 
 namespace llvm {
 class raw_fd_ostream;
+class PassPlugin;
 class Timer;
 class TimerGroup;
 }
@@ -131,6 +132,9 @@ class CompilerInstance : public ModuleLoader {
   /// The semantic analysis object.
   std::unique_ptr<Sema> TheSema;
 
+  /// Back-end pass plugins.
+  std::vector<std::unique_ptr<llvm::PassPlugin>> PassPlugins;
+
   /// The frontend timer group.
   std::unique_ptr<llvm::TimerGroup> timerGroup;
 
@@ -644,6 +648,14 @@ class CompilerInstance : public ModuleLoader {
   /// the compiler instance takes ownership of \p Value.
   void setCodeCompletionConsumer(CodeCompleteConsumer *Value);
 
+  /// }
+  /// @name Back-end Pass Plugins
+  /// @{
+
+  llvm::ArrayRef<std::unique_ptr<llvm::PassPlugin>> getPassPlugins() const {
+    return PassPlugins;
+  }
+
   /// @}
   /// @name Frontend timer
   /// @{
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index a014b5e982cc3..f365fa03cd930 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1019,16 +1019,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
     }
 #endif
   }
-  // Attempt to load pass plugins and register their callbacks with PB.
-  for (auto &PluginFN : CodeGenOpts.PassPlugins) {
-    auto PassPlugin = PassPlugin::Load(PluginFN);
-    if (PassPlugin) {
-      PassPlugin->registerPassBuilderCallbacks(PB);
-    } else {
-      Diags.Report(diag::err_fe_unable_to_load_plugin)
-          << PluginFN << toString(PassPlugin.takeError());
-    }
-  }
+  // Register plugin callbacks with PB.
+  for (const std::unique_ptr<PassPlugin> &Plugin : CI.getPassPlugins())
+    Plugin->registerPassBuilderCallbacks(PB);
   for (const auto &PassCallback : CodeGenOpts.PassBuilderCallbacks)
     PassCallback(PB);
 #define HANDLE_EXTENSION(Ext)                                                  \
diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt
index 634f239933605..c40baa3657fe1 100644
--- a/clang/lib/Frontend/CMakeLists.txt
+++ b/clang/lib/Frontend/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
   BitReader
   BitstreamReader
   Option
+  Plugins
   ProfileData
   Support
   TargetParser
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 5db3c8fa16988..39e20f371dcab 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -46,6 +46,7 @@
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Config/llvm-config.h"
+#include "llvm/Plugins/PassPlugin.h"
 #include "llvm/Support/AdvisoryLock.h"
 #include "llvm/Support/BuryPointer.h"
 #include "llvm/Support/CrashRecoveryContext.h"
@@ -1076,6 +1077,16 @@ void CompilerInstance::LoadRequestedPlugins() {
           << Path << Error;
   }
 
+  // Load and store pass plugins for the back-end.
+  for (const std::string &Path : getCodeGenOpts().PassPlugins) {
+    if (auto PassPlugin = llvm::PassPlugin::Load(Path)) {
+      PassPlugins.emplace_back(std::make_unique<llvm::PassPlugin>(*PassPlugin));
+    } else {
+      getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
+          << Path << toString(PassPlugin.takeError());
+    }
+  }
+
   // Check if any of the loaded plugins replaces the main AST action
   for (const FrontendPluginRegistry::entry &Plugin :
        FrontendPluginRegistry::entries()) {
diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt
index bcb6bd68fafc2..3faf3d7d5f2aa 100644
--- a/clang/test/CMakeLists.txt
+++ b/clang/test/CMakeLists.txt
@@ -13,7 +13,6 @@ llvm_canonicalize_cmake_booleans(
   CLANG_ENABLE_OBJC_REWRITER
   CLANG_LINK_CLANG_DYLIB
   ENABLE_BACKTRACES
-  LLVM_BUILD_EXAMPLES
   LLVM_BYE_LINK_INTO_TOOLS
   LLVM_ENABLE_PLUGINS
   LLVM_ENABLE_ZLIB
@@ -21,6 +20,7 @@ llvm_canonicalize_cmake_booleans(
   LLVM_ENABLE_PER_TARGET_RUNTIME_DIR
   LLVM_ENABLE_THREADS
   LLVM_ENABLE_REVERSE_ITERATION
+  LLVM_INCLUDE_EXAMPLES
   LLVM_LINK_LLVM_DYLIB
   LLVM_WITH_Z3
   PPC_LINUX_DEFAULT_IEEELONGDOUBLE
@@ -134,6 +134,12 @@ if(CLANG_BUILD_EXAMPLES AND CLANG_PLUGIN_SUPPORT)
     )
 endif ()
 
+if(LLVM_INCLUDE_EXAMPLES AND NOT WIN32 AND NOT CYGWIN)
+  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.c b/clang/test/CodeGen/pass-plugins.c
new file mode 100644
index 0000000000000..9a8ca7b49dff4
--- /dev/null
+++ b/clang/test/CodeGen/pass-plugins.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -S < %s -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 2>&1 | FileCheck %s --check-prefix=CHECK-INACTIVE
+// RUN: %clang_cc1 -S < %s -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 -mllvm -wave-goodbye 2>&1 | FileCheck %s --check-prefix=CHECK-ACTIVE
+// REQUIRES: plugins, llvm-examples
+// UNSUPPORTED: target={{.*windows.*}}
+// CHECK-INACTIVE-NOT: Bye
+// CHECK-ACTIVE: Bye: f
+
+int f(int x) {
+  return x;
+}
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..3bdff42262164 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_INCLUDE_EXAMPLES@
 config.enable_shared = @ENABLE_SHARED@
 config.enable_backtrace = @ENABLE_BACKTRACES@
 config.enable_threads = @LLVM_ENABLE_THREADS@

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Dec 22, 2025

@llvm/pr-subscribers-clang-codegen

Author: Alexis Engelke (aengelke)

Changes

This permits pass plugins to use llvm::cl::opt. Additionally, add a test
of -fpass-plugin, this was previously not tested at all.

I'm not sure whether using the LLVM Bye.so in the tests is possible this
way (e.g., if Clang is built standalone).

Reland after #173279.


Full diff: https://github.com/llvm/llvm-project/pull/173287.diff

8 Files Affected:

  • (modified) clang/include/clang/Frontend/CompilerInstance.h (+12)
  • (modified) clang/lib/CodeGen/BackendUtil.cpp (+3-10)
  • (modified) clang/lib/Frontend/CMakeLists.txt (+1)
  • (modified) clang/lib/Frontend/CompilerInstance.cpp (+11)
  • (modified) clang/test/CMakeLists.txt (+7-1)
  • (added) clang/test/CodeGen/pass-plugins.c (+10)
  • (modified) clang/test/lit.cfg.py (+2)
  • (modified) clang/test/lit.site.cfg.py.in (+1)
diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index a8e8461b9b5a9..ded5f55d180aa 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -36,6 +36,7 @@
 
 namespace llvm {
 class raw_fd_ostream;
+class PassPlugin;
 class Timer;
 class TimerGroup;
 }
@@ -131,6 +132,9 @@ class CompilerInstance : public ModuleLoader {
   /// The semantic analysis object.
   std::unique_ptr<Sema> TheSema;
 
+  /// Back-end pass plugins.
+  std::vector<std::unique_ptr<llvm::PassPlugin>> PassPlugins;
+
   /// The frontend timer group.
   std::unique_ptr<llvm::TimerGroup> timerGroup;
 
@@ -644,6 +648,14 @@ class CompilerInstance : public ModuleLoader {
   /// the compiler instance takes ownership of \p Value.
   void setCodeCompletionConsumer(CodeCompleteConsumer *Value);
 
+  /// }
+  /// @name Back-end Pass Plugins
+  /// @{
+
+  llvm::ArrayRef<std::unique_ptr<llvm::PassPlugin>> getPassPlugins() const {
+    return PassPlugins;
+  }
+
   /// @}
   /// @name Frontend timer
   /// @{
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index a014b5e982cc3..f365fa03cd930 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1019,16 +1019,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
     }
 #endif
   }
-  // Attempt to load pass plugins and register their callbacks with PB.
-  for (auto &PluginFN : CodeGenOpts.PassPlugins) {
-    auto PassPlugin = PassPlugin::Load(PluginFN);
-    if (PassPlugin) {
-      PassPlugin->registerPassBuilderCallbacks(PB);
-    } else {
-      Diags.Report(diag::err_fe_unable_to_load_plugin)
-          << PluginFN << toString(PassPlugin.takeError());
-    }
-  }
+  // Register plugin callbacks with PB.
+  for (const std::unique_ptr<PassPlugin> &Plugin : CI.getPassPlugins())
+    Plugin->registerPassBuilderCallbacks(PB);
   for (const auto &PassCallback : CodeGenOpts.PassBuilderCallbacks)
     PassCallback(PB);
 #define HANDLE_EXTENSION(Ext)                                                  \
diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt
index 634f239933605..c40baa3657fe1 100644
--- a/clang/lib/Frontend/CMakeLists.txt
+++ b/clang/lib/Frontend/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
   BitReader
   BitstreamReader
   Option
+  Plugins
   ProfileData
   Support
   TargetParser
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 5db3c8fa16988..39e20f371dcab 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -46,6 +46,7 @@
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Config/llvm-config.h"
+#include "llvm/Plugins/PassPlugin.h"
 #include "llvm/Support/AdvisoryLock.h"
 #include "llvm/Support/BuryPointer.h"
 #include "llvm/Support/CrashRecoveryContext.h"
@@ -1076,6 +1077,16 @@ void CompilerInstance::LoadRequestedPlugins() {
           << Path << Error;
   }
 
+  // Load and store pass plugins for the back-end.
+  for (const std::string &Path : getCodeGenOpts().PassPlugins) {
+    if (auto PassPlugin = llvm::PassPlugin::Load(Path)) {
+      PassPlugins.emplace_back(std::make_unique<llvm::PassPlugin>(*PassPlugin));
+    } else {
+      getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
+          << Path << toString(PassPlugin.takeError());
+    }
+  }
+
   // Check if any of the loaded plugins replaces the main AST action
   for (const FrontendPluginRegistry::entry &Plugin :
        FrontendPluginRegistry::entries()) {
diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt
index bcb6bd68fafc2..3faf3d7d5f2aa 100644
--- a/clang/test/CMakeLists.txt
+++ b/clang/test/CMakeLists.txt
@@ -13,7 +13,6 @@ llvm_canonicalize_cmake_booleans(
   CLANG_ENABLE_OBJC_REWRITER
   CLANG_LINK_CLANG_DYLIB
   ENABLE_BACKTRACES
-  LLVM_BUILD_EXAMPLES
   LLVM_BYE_LINK_INTO_TOOLS
   LLVM_ENABLE_PLUGINS
   LLVM_ENABLE_ZLIB
@@ -21,6 +20,7 @@ llvm_canonicalize_cmake_booleans(
   LLVM_ENABLE_PER_TARGET_RUNTIME_DIR
   LLVM_ENABLE_THREADS
   LLVM_ENABLE_REVERSE_ITERATION
+  LLVM_INCLUDE_EXAMPLES
   LLVM_LINK_LLVM_DYLIB
   LLVM_WITH_Z3
   PPC_LINUX_DEFAULT_IEEELONGDOUBLE
@@ -134,6 +134,12 @@ if(CLANG_BUILD_EXAMPLES AND CLANG_PLUGIN_SUPPORT)
     )
 endif ()
 
+if(LLVM_INCLUDE_EXAMPLES AND NOT WIN32 AND NOT CYGWIN)
+  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.c b/clang/test/CodeGen/pass-plugins.c
new file mode 100644
index 0000000000000..9a8ca7b49dff4
--- /dev/null
+++ b/clang/test/CodeGen/pass-plugins.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -S < %s -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 2>&1 | FileCheck %s --check-prefix=CHECK-INACTIVE
+// RUN: %clang_cc1 -S < %s -fpass-plugin=%llvmshlibdir/Bye%pluginext -O2 -mllvm -wave-goodbye 2>&1 | FileCheck %s --check-prefix=CHECK-ACTIVE
+// REQUIRES: plugins, llvm-examples
+// UNSUPPORTED: target={{.*windows.*}}
+// CHECK-INACTIVE-NOT: Bye
+// CHECK-ACTIVE: Bye: f
+
+int f(int x) {
+  return x;
+}
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..3bdff42262164 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_INCLUDE_EXAMPLES@
 config.enable_shared = @ENABLE_SHARED@
 config.enable_backtrace = @ENABLE_BACKTRACES@
 config.enable_threads = @LLVM_ENABLE_THREADS@

@aengelke aengelke merged commit c3678c4 into main Dec 22, 2025
14 checks passed
@aengelke aengelke deleted the users/aengelke/spr/reland-clang-load-pass-plugins-before-parsing-llvm-options-171868 branch December 22, 2025 18:34
llvm-sync Bot pushed a commit to arm/arm-toolchain that referenced this pull request Dec 22, 2025
…ons" (#171868)

This permits pass plugins to use llvm::cl::opt. Additionally, add a test
of -fpass-plugin, this was previously not tested at all.

I'm not sure whether using the LLVM Bye.so in the tests is possible this
way (e.g., if Clang is built standalone).

Reland after #173279.

Pull Request: llvm/llvm-project#173287
aengelke added a commit to aengelke/llvm-project that referenced this pull request Dec 30, 2025
- Pass plugins can use LLVM options, matching llvm#173287.
- Pass plugins can run a hook before codegen, matching llvm#171872.
- Pass plugins are now tested whenever they can be built, matching llvm#171998.
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jan 6, 2026
…171868)

This permits pass plugins to use llvm::cl::opt. Additionally, add a test
of -fpass-plugin, this was previously not tested at all.

I'm not sure whether using the LLVM Bye.so in the tests is possible this
way (e.g., if Clang is built standalone).

Reland after llvm#173279.

Pull Request: llvm#173287
aengelke added a commit that referenced this pull request Jan 7, 2026
- 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.

Plugins currently don't work on AIX, tracked in #172203.
navaneethshan pushed a commit to qualcomm/cpullvm-toolchain that referenced this pull request Jan 9, 2026
This permits pass plugins to use llvm::cl::opt. Additionally, add a test
of -fpass-plugin, this was previously not tested at all.

I'm not sure whether using the LLVM Bye.so in the tests is possible this
way (e.g., if Clang is built standalone).

Reland after #173279.

Pull Request: llvm/llvm-project#173287

(cherry picked from commit c3678c4)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-precommit-approval PR for CI feedback, not intended for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants