[llvm] [IR][NFC] Remove vtables from AnalysisResultConcept (PR #211810)

Alexis Engelke via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 24 07:36:14 PDT 2026


https://github.com/aengelke created https://github.com/llvm/llvm-project/pull/211810

Similar to #209414 but for AnalysisResultConcept. This avoids vtables
for every analysis result type.

As a side effect, this improves the build times of PassBuilder.cpp by
~8% due to substantially fewer unique_ptr instantiations (instantiating
unique_ptr is expensive, at least with libstdc++).


>From cd5fa0bd0ddfacdc4bb08ab26560b77747dfdb13 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Fri, 24 Jul 2026 14:35:30 +0000
Subject: [PATCH] [spr] initial version

Created using spr 1.3.8-wip
---
 llvm/include/llvm/IR/PassManager.h         |  2 +-
 llvm/include/llvm/IR/PassManagerInternal.h | 98 ++++++++++------------
 2 files changed, 45 insertions(+), 55 deletions(-)

diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h
index adb375f4f837a..ad6dd5e39daf5 100644
--- a/llvm/include/llvm/IR/PassManager.h
+++ b/llvm/include/llvm/IR/PassManager.h
@@ -288,7 +288,7 @@ template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager {
   /// entry in maps below, and provides the storage for the actual result
   /// concept.
   using AnalysisResultListT =
-      std::list<std::pair<AnalysisKey *, std::unique_ptr<ResultConceptT>>>;
+      std::list<std::pair<AnalysisKey *, typename ResultConceptT::unique_ptr>>;
 
   /// Map type from IRUnitT pointer to our custom list type.
   using AnalysisResultListMapT = DenseMap<IRUnitT *, AnalysisResultListT>;
diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h
index ba1f717fd76b1..24e5d67eb51a9 100644
--- a/llvm/include/llvm/IR/PassManagerInternal.h
+++ b/llvm/include/llvm/IR/PassManagerInternal.h
@@ -151,8 +151,25 @@ class PassModel final
 /// to.
 template <typename IRUnitT, typename InvalidatorT>
 struct AnalysisResultConcept {
-  virtual ~AnalysisResultConcept() = default;
+private:
+  using DestroyTy = void (*)(AnalysisResultConcept &);
+  using InvalidateTy = bool (*)(AnalysisResultConcept &, IRUnitT &,
+                                const PreservedAnalyses &, InvalidatorT &);
+
+public:
+  struct Deleter {
+    void operator()(AnalysisResultConcept *C) { C->Destroy(*C); }
+  };
+
+  using unique_ptr = std::unique_ptr<AnalysisResultConcept, Deleter>;
+
+protected:
+  DestroyTy Destroy;
+  InvalidateTy Invalidate = nullptr;
 
+  AnalysisResultConcept(DestroyTy Destroy) : Destroy(Destroy) {}
+
+public:
   /// Method to try and mark a result as invalid.
   ///
   /// When the outer analysis manager detects a change in some underlying
@@ -168,8 +185,9 @@ struct AnalysisResultConcept {
   /// them. See the documentation in the \c AnalysisManager for more details.
   ///
   /// \returns true if the result is indeed invalid (the default).
-  virtual bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
-                          InvalidatorT &Inv) = 0;
+  bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA, InvalidatorT &Inv) {
+    return Invalidate(*this, IR, PA, Inv);
+  }
 };
 
 /// SFINAE metafunction for computing whether \c ResultT provides an
@@ -209,63 +227,35 @@ template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod {
 };
 
 /// Wrapper to model the analysis result concept.
-///
-/// By default, this will implement the invalidate method with a trivial
-/// implementation so that the actual analysis result doesn't need to provide
-/// an invalidation handler. It is only selected when the invalidation handler
-/// is not part of the ResultT's interface.
-template <typename IRUnitT, typename PassT, typename ResultT,
-          typename InvalidatorT,
-          bool HasInvalidateHandler =
-              ResultHasInvalidateMethod<IRUnitT, ResultT>::Value>
-struct AnalysisResultModel;
-
-/// Specialization of \c AnalysisResultModel which provides the default
-/// invalidate functionality.
 template <typename IRUnitT, typename PassT, typename ResultT,
           typename InvalidatorT>
-struct AnalysisResultModel<IRUnitT, PassT, ResultT, InvalidatorT, false>
-    : AnalysisResultConcept<IRUnitT, InvalidatorT> {
-  template <typename... ExtraArgTs>
-  AnalysisResultModel(PassT &Pass, IRUnitT &IR,
-                      AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
-                      ExtraArgTs &&...ExtraArgs)
-      : Result(Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...)) {}
-
-  /// The model bases invalidation solely on being in the preserved set.
-  //
-  // FIXME: We should actually use two different concepts for analysis results
-  // rather than two different models, and avoid the indirect function call for
-  // ones that use the trivial behavior.
-  bool invalidate(IRUnitT &, const PreservedAnalyses &PA,
-                  InvalidatorT &) override {
-    auto PAC = PA.template getChecker<PassT>();
-    return !PAC.preserved() &&
-           !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();
-  }
+struct AnalysisResultModel
+    : public AnalysisResultConcept<IRUnitT, InvalidatorT> {
+  using AnalysisResultConceptT = AnalysisResultConcept<IRUnitT, InvalidatorT>;
 
   ResultT Result;
-};
 
-/// Specialization of \c AnalysisResultModel which delegates invalidate
-/// handling to \c ResultT.
-template <typename IRUnitT, typename PassT, typename ResultT,
-          typename InvalidatorT>
-struct AnalysisResultModel<IRUnitT, PassT, ResultT, InvalidatorT, true>
-    : AnalysisResultConcept<IRUnitT, InvalidatorT> {
+  static void destroyImpl(AnalysisResultConceptT &Self) {
+    delete static_cast<AnalysisResultModel *>(&Self);
+  }
+
   template <typename... ExtraArgTs>
   AnalysisResultModel(PassT &Pass, IRUnitT &IR,
                       AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
                       ExtraArgTs &&...ExtraArgs)
-      : Result(Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...)) {}
-
-  /// The model delegates to the \c ResultT method.
-  bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
-                  InvalidatorT &Inv) override {
-    return Result.invalidate(IR, PA, Inv);
+      : AnalysisResultConceptT(destroyImpl),
+        Result(Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...)) {
+    this->Invalidate = [](AnalysisResultConceptT &Self, IRUnitT &IR,
+                          const PreservedAnalyses &PA, InvalidatorT &Inv) {
+      if constexpr (ResultHasInvalidateMethod<IRUnitT, ResultT>::Value) {
+        ResultT &Result = static_cast<AnalysisResultModel &>(Self).Result;
+        return Result.invalidate(IR, PA, Inv);
+      }
+      auto PAC = PA.template getChecker<PassT>();
+      return !PAC.preserved() &&
+             !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();
+    };
   }
-
-  ResultT Result;
 };
 
 /// Abstract concept of an analysis pass.
@@ -279,7 +269,7 @@ struct AnalysisPassConcept {
   /// Method to run this analysis over a unit of IR.
   /// \returns A unique_ptr to the analysis result object to be queried by
   /// users.
-  virtual std::unique_ptr<AnalysisResultConcept<IRUnitT, InvalidatorT>>
+  virtual typename AnalysisResultConcept<IRUnitT, InvalidatorT>::unique_ptr
   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
       ExtraArgTs... ExtraArgs) = 0;
 
@@ -319,12 +309,12 @@ struct AnalysisPassModel
   /// The model delegates to the \c PassT::run method.
   ///
   /// The return is wrapped in an \c AnalysisResultModel.
-  std::unique_ptr<AnalysisResultConcept<IRUnitT, InvalidatorT>>
+  typename ResultModelT::unique_ptr
   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
       ExtraArgTs... ExtraArgs) override {
     // Call Pass.run in constructor to avoid move of analysis result.
-    return std::make_unique<ResultModelT>(
-        Pass, IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...);
+    return typename ResultModelT::unique_ptr(
+        new ResultModelT(Pass, IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...));
   }
 
   /// The model delegates to a static \c PassT::name method.



More information about the llvm-commits mailing list