[clang] [PassBuilder] Add a mechanism for adding passbuilder callbacks for static builds (PR #70171)

William Moses via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 25 22:33:50 PDT 2023


https://github.com/wsmoses updated https://github.com/llvm/llvm-project/pull/70171

>From 227a494be06d8cb3b590c78f52f717bd781a8f0e Mon Sep 17 00:00:00 2001
From: "William S. Moses" <gh at wsmoses.com>
Date: Wed, 25 Oct 2023 02:10:32 -0500
Subject: [PATCH] [PassBuilder] Add a mechanism for adding passbuilder
 callbacks without an extension mechanism or dlopen of plugin

---
 clang/include/clang/Basic/CodeGenOptions.h    |  6 ++
 clang/lib/CodeGen/BackendUtil.cpp             |  3 +
 clang/test/CMakeLists.txt                     |  1 +
 clang/test/DriverPlugin/plugintest.c          |  6 ++
 clang/tools/CMakeLists.txt                    |  1 +
 .../clang-hello-plugin-test/CMakeLists.txt    | 59 +++++++++++++++++
 .../clang-hello-plugin-test/helloplugin.cpp   | 66 +++++++++++++++++++
 clang/tools/driver/cc1_main.cpp               |  9 +++
 llvm/include/llvm/Passes/PassBuilder.h        |  5 ++
 9 files changed, 156 insertions(+)
 create mode 100644 clang/test/DriverPlugin/plugintest.c
 create mode 100644 clang/tools/clang-hello-plugin-test/CMakeLists.txt
 create mode 100644 clang/tools/clang-hello-plugin-test/helloplugin.cpp

diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 12be4e0025a7054..c8e2544f891cc2b 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -26,6 +26,9 @@
 #include <string>
 #include <vector>
 
+namespace llvm {
+class PassBuilder;
+}
 namespace clang {
 
 /// Bitfields of CodeGenOptions, split out from CodeGenOptions to ensure
@@ -408,6 +411,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// List of dynamic shared object files to be loaded as pass plugins.
   std::vector<std::string> PassPlugins;
 
+  /// List of pass builder callbacks.
+  std::vector<std::function<void(llvm::PassBuilder &)>> PassBuilderCallbacks;
+
   /// Path to allowlist file specifying which objects
   /// (files, functions) should exclusively be instrumented
   /// by sanitizer coverage pass.
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 70accce456d3c07..a8db38fce6425fb 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -906,6 +906,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
           << PluginFN << toString(PassPlugin.takeError());
     }
   }
+  for (auto PassCallback : CodeGenOpts.PassBuilderCallbacks) {
+    PassCallback(PB);
+  }
 #define HANDLE_EXTENSION(Ext)                                                  \
   get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB);
 #include "llvm/Support/Extension.def"
diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt
index 31b494f39cce577..a64dfe467c43abc 100644
--- a/clang/test/CMakeLists.txt
+++ b/clang/test/CMakeLists.txt
@@ -62,6 +62,7 @@ list(APPEND CLANG_TEST_DEPS
   apinotes-test
   c-index-test
   clang
+  clang-hello-plugin-test
   clang-fuzzer-dictionary
   clang-resource-headers
   clang-format
diff --git a/clang/test/DriverPlugin/plugintest.c b/clang/test/DriverPlugin/plugintest.c
new file mode 100644
index 000000000000000..e80866f0d1dd2fe
--- /dev/null
+++ b/clang/test/DriverPlugin/plugintest.c
@@ -0,0 +1,6 @@
+// RUN: clang-hello-plugin-test %s -o /dev/null -S | FileCheck %s
+
+int myfunction() { return 0; }
+
+// CHECK: [HelloPass] Found function: myfunction
+
diff --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt
index f60db6ef0ba3454..9742e2a155a0d30 100644
--- a/clang/tools/CMakeLists.txt
+++ b/clang/tools/CMakeLists.txt
@@ -2,6 +2,7 @@ create_subdirectory_options(CLANG TOOL)
 
 add_clang_subdirectory(diagtool)
 add_clang_subdirectory(driver)
+add_clang_subdirectory(clang-hello-plugin-test)
 add_clang_subdirectory(apinotes-test)
 add_clang_subdirectory(clang-diff)
 add_clang_subdirectory(clang-format)
diff --git a/clang/tools/clang-hello-plugin-test/CMakeLists.txt b/clang/tools/clang-hello-plugin-test/CMakeLists.txt
new file mode 100644
index 000000000000000..2b951677542c217
--- /dev/null
+++ b/clang/tools/clang-hello-plugin-test/CMakeLists.txt
@@ -0,0 +1,59 @@
+set( LLVM_LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  Analysis
+  CodeGen
+  Core
+  IPO
+  AggressiveInstCombine
+  InstCombine
+  Instrumentation
+  MC
+  MCParser
+  ObjCARCOpts
+  Option
+  ScalarOpts
+  Support
+  TargetParser
+  TransformUtils
+  Vectorize
+  )
+
+# Support plugins.
+if(CLANG_PLUGIN_SUPPORT)
+  set(support_plugins SUPPORT_PLUGINS)
+endif()
+
+add_clang_tool(clang-hello-plugin-test
+  ../driver/driver.cpp
+  ../driver/cc1_main.cpp
+  ../driver/cc1as_main.cpp
+  ../driver/cc1gen_reproducer_main.cpp
+  helloplugin.cpp
+  DEPENDS
+  intrinsics_gen
+  ${support_plugins}
+  GENERATE_DRIVER
+  )
+
+clang_target_link_libraries(clang-hello-plugin-test
+  PRIVATE
+  clangBasic
+  clangCodeGen
+  clangDriver
+  clangFrontend
+  clangFrontendTool
+  clangSerialization
+  )
+
+if(WIN32 AND NOT CYGWIN)
+  # Prevent versioning if the buildhost is targeting for Win32.
+else()
+  set_target_properties(clang-hello-plugin-test PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
+endif()
+
+# Support plugins.
+if(CLANG_PLUGIN_SUPPORT)
+  export_executable_symbols_for_plugins(clang-hello-plugin-test)
+endif()
+
+add_dependencies(clang-hello-plugin-test clang-resource-headers)
diff --git a/clang/tools/clang-hello-plugin-test/helloplugin.cpp b/clang/tools/clang-hello-plugin-test/helloplugin.cpp
new file mode 100644
index 000000000000000..52551d12af0a350
--- /dev/null
+++ b/clang/tools/clang-hello-plugin-test/helloplugin.cpp
@@ -0,0 +1,66 @@
+//===-- helloplugin.cpp - Hello World test static link plugin ------------===//
+//
+// 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 is a test/example mechanism for statically adding functionality to Clang
+// Codegen without requiring a fork of Clang.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/LLVMDriver.h"
+
+#include <functional>
+
+using namespace llvm;
+
+extern SmallVector<std::function<void(llvm::PassBuilder &)>>
+    PassBuilderCallbacks;
+
+class StaticPlugin {
+public:
+  StaticPlugin(std::function<void(llvm::PassBuilder &)> f) {
+    PassBuilderCallbacks.push_back(f);
+  }
+};
+
+class HelloPass final : public llvm::AnalysisInfoMixin<HelloPass> {
+  friend struct llvm::AnalysisInfoMixin<HelloPass>;
+
+private:
+  static llvm::AnalysisKey Key;
+
+public:
+  using Result = llvm::PreservedAnalyses;
+
+  Result run(llvm::Module &M, llvm::ModuleAnalysisManager &MAM) {
+    for (auto &F : M)
+      llvm::outs() << "[HelloPass] Found function: " << F.getName() << "\n";
+    return PreservedAnalyses::all();
+  }
+
+  static bool isRequired() { return true; }
+};
+
+void HelloCallback(llvm::PassBuilder &PB) {
+  PB.registerPipelineStartEPCallback(
+      [](ModulePassManager &MPM, OptimizationLevel) {
+        MPM.addPass(HelloPass());
+      });
+}
+
+StaticPlugin P(HelloCallback);
+
+extern int clang_main(int Argc, char **Argv,
+                      const llvm::ToolContext &ToolContext);
+
+int clang_hello_plugin_main(int Argc, char **Argv,
+                            const llvm::ToolContext &ToolContext) {
+  return clang_main(Argc, Argv, ToolContext);
+}
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index e9d2c6aad371dbb..c409d5e170dd6cc 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -57,6 +57,11 @@
 using namespace clang;
 using namespace llvm::opt;
 
+//! List of pass builder callbacks to be applied, for adding additional
+//! functionality via static linking, without maintaining a separate fork of
+//! LLVM.
+SmallVector<std::function<void(llvm::PassBuilder &)>> PassBuilderCallbacks;
+
 //===----------------------------------------------------------------------===//
 // Main driver
 //===----------------------------------------------------------------------===//
@@ -227,6 +232,10 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   ensureSufficientStack();
 
   std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
+  for (auto PassCallback : PassBuilderCallbacks) {
+    Clang->getCodeGenOpts().PassBuilderCallbacks.push_back(PassCallback);
+  }
+
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 
   // Register the support for object-file-wrapped Clang modules.
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 2c7ceda7998eda1..d018dd1e69166f0 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -739,6 +739,11 @@ bool parseAnalysisUtilityPasses(
 
   return false;
 }
+
+//! List of pass builder callbacks to be applied, in addition to those imported
+//! from plugins or LLVM extensions.
+extern SmallVector<std::function<void(PassBuilder &)>>
+    ListRegisterPassBuilderCallbacks;
 }
 
 #endif



More information about the cfe-commits mailing list