[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