[llvm] Reapply "[IR][NFC] Drop vtable from PassConcept/PassModel" (#208168) (PR #209414)

Alexis Engelke via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 04:24:35 PDT 2026


https://github.com/aengelke updated https://github.com/llvm/llvm-project/pull/209414

>From 272e691aab08c945f5cbdd459d4b60ca8e4e9825 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Tue, 14 Jul 2026 09:31:54 +0000
Subject: [PATCH 1/2] [spr] initial version

Created using spr 1.3.8-wip
---
 llvm/include/llvm/Analysis/CGSCCPassManager.h |  18 +--
 .../include/llvm/CodeGen/MachinePassManager.h |   7 +-
 llvm/include/llvm/IR/PassManager.h            |  10 +-
 llvm/include/llvm/IR/PassManagerInternal.h    | 115 ++++++++++++------
 .../llvm/Transforms/Scalar/LoopPassManager.h  |  18 +--
 5 files changed, 105 insertions(+), 63 deletions(-)

diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h
index e85c1ef9a90d2..1cfe68ee6fa59 100644
--- a/llvm/include/llvm/Analysis/CGSCCPassManager.h
+++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h
@@ -319,7 +319,7 @@ class ModuleToPostOrderCGSCCPassAdaptor
       detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager,
                           LazyCallGraph &, CGSCCUpdateResult &>;
 
-  explicit ModuleToPostOrderCGSCCPassAdaptor(std::unique_ptr<PassConceptT> Pass)
+  explicit ModuleToPostOrderCGSCCPassAdaptor(PassConceptT::unique_ptr Pass)
       : Pass(std::move(Pass)) {}
 
   ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg)
@@ -347,7 +347,7 @@ class ModuleToPostOrderCGSCCPassAdaptor
   }
 
 private:
-  std::unique_ptr<PassConceptT> Pass;
+  PassConceptT::unique_ptr Pass;
 };
 
 /// A function to deduce a function pass type and wrap it in the
@@ -361,7 +361,7 @@ createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT &&Pass) {
   // Do not use make_unique, it causes too many template instantiations,
   // causing terrible compile times.
   return ModuleToPostOrderCGSCCPassAdaptor(
-      std::unique_ptr<ModuleToPostOrderCGSCCPassAdaptor::PassConceptT>(
+      ModuleToPostOrderCGSCCPassAdaptor::PassConceptT::unique_ptr(
           new PassModelT(std::forward<CGSCCPassT>(Pass))));
 }
 
@@ -447,7 +447,7 @@ class CGSCCToFunctionPassAdaptor
 public:
   using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>;
 
-  explicit CGSCCToFunctionPassAdaptor(std::unique_ptr<PassConceptT> Pass,
+  explicit CGSCCToFunctionPassAdaptor(typename PassConceptT::unique_ptr Pass,
                                       bool EagerlyInvalidate, bool NoRerun)
       : Pass(std::move(Pass)), EagerlyInvalidate(EagerlyInvalidate),
         NoRerun(NoRerun) {}
@@ -490,7 +490,7 @@ class CGSCCToFunctionPassAdaptor
   }
 
 private:
-  std::unique_ptr<PassConceptT> Pass;
+  PassConceptT::unique_ptr Pass;
   bool EagerlyInvalidate;
   bool NoRerun;
 };
@@ -507,7 +507,7 @@ createCGSCCToFunctionPassAdaptor(FunctionPassT &&Pass,
   // Do not use make_unique, it causes too many template instantiations,
   // causing terrible compile times.
   return CGSCCToFunctionPassAdaptor(
-      std::unique_ptr<CGSCCToFunctionPassAdaptor::PassConceptT>(
+      CGSCCToFunctionPassAdaptor::PassConceptT::unique_ptr(
           new PassModelT(std::forward<FunctionPassT>(Pass))),
       EagerlyInvalidate, NoRerun);
 }
@@ -547,7 +547,7 @@ class DevirtSCCRepeatedPass
       detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager,
                           LazyCallGraph &, CGSCCUpdateResult &>;
 
-  explicit DevirtSCCRepeatedPass(std::unique_ptr<PassConceptT> Pass,
+  explicit DevirtSCCRepeatedPass(PassConceptT::unique_ptr Pass,
                                  int MaxIterations)
       : Pass(std::move(Pass)), MaxIterations(MaxIterations) {}
 
@@ -565,7 +565,7 @@ class DevirtSCCRepeatedPass
   }
 
 private:
-  std::unique_ptr<PassConceptT> Pass;
+  PassConceptT::unique_ptr Pass;
   int MaxIterations;
 };
 
@@ -580,7 +580,7 @@ DevirtSCCRepeatedPass createDevirtSCCRepeatedPass(CGSCCPassT &&Pass,
   // Do not use make_unique, it causes too many template instantiations,
   // causing terrible compile times.
   return DevirtSCCRepeatedPass(
-      std::unique_ptr<DevirtSCCRepeatedPass::PassConceptT>(
+      DevirtSCCRepeatedPass::PassConceptT::unique_ptr(
           new PassModelT(std::forward<CGSCCPassT>(Pass))),
       MaxIterations);
 }
diff --git a/llvm/include/llvm/CodeGen/MachinePassManager.h b/llvm/include/llvm/CodeGen/MachinePassManager.h
index 936e80e88192c..5de520fa550f8 100644
--- a/llvm/include/llvm/CodeGen/MachinePassManager.h
+++ b/llvm/include/llvm/CodeGen/MachinePassManager.h
@@ -194,8 +194,7 @@ class FunctionToMachineFunctionPassAdaptor
   using PassConceptT =
       detail::PassConcept<MachineFunction, MachineFunctionAnalysisManager>;
 
-  explicit FunctionToMachineFunctionPassAdaptor(
-      std::unique_ptr<PassConceptT> Pass)
+  explicit FunctionToMachineFunctionPassAdaptor(PassConceptT::unique_ptr Pass)
       : Pass(std::move(Pass)) {}
 
   /// Runs the function pass across every function in the function.
@@ -205,7 +204,7 @@ class FunctionToMachineFunctionPassAdaptor
                 function_ref<StringRef(StringRef)> MapClassName2PassName);
 
 private:
-  std::unique_ptr<PassConceptT> Pass;
+  PassConceptT::unique_ptr Pass;
 };
 
 template <typename MachineFunctionPassT>
@@ -216,7 +215,7 @@ createFunctionToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) {
   // Do not use make_unique, it causes too many template instantiations,
   // causing terrible compile times.
   return FunctionToMachineFunctionPassAdaptor(
-      std::unique_ptr<FunctionToMachineFunctionPassAdaptor::PassConceptT>(
+      FunctionToMachineFunctionPassAdaptor::PassConceptT::unique_ptr(
           new PassModelT(std::forward<MachineFunctionPassT>(Pass))));
 }
 
diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h
index 22e02853bc567..0c6dac6be8d31 100644
--- a/llvm/include/llvm/IR/PassManager.h
+++ b/llvm/include/llvm/IR/PassManager.h
@@ -222,7 +222,7 @@ class PassManager : public RequiredPassInfoMixin<
         detail::PassModel<IRUnitT, PassT, AnalysisManagerT, ExtraArgTs...>;
     // Do not use make_unique or emplace_back, they cause too many template
     // instantiations, causing terrible compile times.
-    Passes.push_back(std::unique_ptr<PassConceptT>(
+    Passes.push_back(typename PassConceptT::unique_ptr(
         new PassModelT(std::forward<PassT>(Pass))));
   }
 
@@ -245,7 +245,7 @@ class PassManager : public RequiredPassInfoMixin<
   using PassConceptT =
       detail::PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...>;
 
-  std::vector<std::unique_ptr<PassConceptT>> Passes;
+  std::vector<typename PassConceptT::unique_ptr> Passes;
 };
 
 template <typename IRUnitT>
@@ -875,7 +875,7 @@ class ModuleToFunctionPassAdaptor
 public:
   using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>;
 
-  explicit ModuleToFunctionPassAdaptor(std::unique_ptr<PassConceptT> Pass,
+  explicit ModuleToFunctionPassAdaptor(PassConceptT::unique_ptr Pass,
                                        bool EagerlyInvalidate)
       : Pass(std::move(Pass)), EagerlyInvalidate(EagerlyInvalidate) {}
 
@@ -886,7 +886,7 @@ class ModuleToFunctionPassAdaptor
                 function_ref<StringRef(StringRef)> MapClassName2PassName);
 
 private:
-  std::unique_ptr<PassConceptT> Pass;
+  PassConceptT::unique_ptr Pass;
   bool EagerlyInvalidate;
 };
 
@@ -901,7 +901,7 @@ createModuleToFunctionPassAdaptor(FunctionPassT &&Pass,
   // Do not use make_unique, it causes too many template instantiations,
   // causing terrible compile times.
   return ModuleToFunctionPassAdaptor(
-      std::unique_ptr<ModuleToFunctionPassAdaptor::PassConceptT>(
+      ModuleToFunctionPassAdaptor::PassConceptT::unique_ptr(
           new PassModelT(std::forward<FunctionPassT>(Pass))),
       EagerlyInvalidate);
 }
diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h
index f894f91cf1783..d731bc56a2820 100644
--- a/llvm/include/llvm/IR/PassManagerInternal.h
+++ b/llvm/include/llvm/IR/PassManagerInternal.h
@@ -34,68 +34,111 @@ class PreservedAnalyses;
 // Implementation details of the pass manager interfaces.
 namespace detail {
 
-/// Template for the abstract base class used to dispatch
-/// polymorphically over pass objects.
+/// Template for the abstract base class used to dispatch over pass objects.
+/// This doesn't use virtual functions to avoid vtables, which cost a fair
+/// amount of storage that needs to be relocated in PIC builds and add an extra
+/// indirection on dispatch.
 template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
-struct PassConcept {
-  PassConcept() = default;
+class PassConcept {
+private:
+  using DestroyTy = void (*)(PassConcept &);
+  using RunTy = PreservedAnalyses (*)(PassConcept &, IRUnitT &,
+                                      AnalysisManagerT &, ExtraArgTs...);
+  using PrintPipelineTy =
+      void (*)(PassConcept &, raw_ostream &,
+               function_ref<StringRef(StringRef)> MapClassName2PassName);
 
-  // Boiler plate necessary for the container of derived classes.
-  virtual ~PassConcept() = default;
+public:
+  struct Deleter {
+    void operator()(PassConcept *P) { P->Destroy(*P); }
+  };
+
+  using unique_ptr = std::unique_ptr<PassConcept, Deleter>;
+
+private:
+  StringRef Name;
+  bool IsRequired;
+
+  DestroyTy Destroy;
+  RunTy Run;
+  PrintPipelineTy PrintPipeline;
+
+protected:
+  PassConcept(StringRef Name, bool IsRequired, DestroyTy Destroy, RunTy Run,
+              PrintPipelineTy PrintPipeline)
+      : Name(Name), IsRequired(IsRequired), Destroy(Destroy), Run(Run),
+        PrintPipeline(PrintPipeline) {}
 
+  // Note: this is intentionally not public to catch uses of delete and
+  // unique_ptr<PassConcept>.
+  void operator delete(void *P) { ::operator delete(P); }
+
+public:
   // Passes are immovable.
   PassConcept(const PassConcept &) = delete;
   PassConcept &operator=(const PassConcept &) = delete;
 
-  /// The polymorphic API which runs the pass over a given IR entity.
-  ///
-  /// Note that actual pass object can omit the analysis manager argument if
-  /// desired. Also that the analysis manager may be null if there is no
-  /// analysis manager in the pass pipeline.
-  virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
-                                ExtraArgTs... ExtraArgs) = 0;
-
-  virtual void
-  printPipeline(raw_ostream &OS,
-                function_ref<StringRef(StringRef)> MapClassName2PassName) = 0;
-  /// Polymorphic method to access the name of a pass.
-  virtual StringRef name() const = 0;
+  /// Run the pass.
+  PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
+                        ExtraArgTs... ExtraArgs) {
+    return Run(*this, IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...);
+  }
+
+  void printPipeline(raw_ostream &OS,
+                     function_ref<StringRef(StringRef)> MapClassName2PassName) {
+    PrintPipeline(*this, OS, MapClassName2PassName);
+  }
 
-  /// Polymorphic method to let a pass optionally exempted from skipping by
+  /// Get name of a pass.
+  StringRef name() const { return Name; }
+
+  /// Indicate whether a pass can optionally be exempted from skipping by
   /// PassInstrumentation.
   /// To opt-in, pass should implement `static bool isRequired()`, or inherit
   /// from `RequiredPassInfoMixin` or `OptionalPassInfoMixin`.
   /// It's no-op to have `isRequired` always return false since that is the
   /// default.
-  virtual bool isRequired() const = 0;
+  bool isRequired() const { return IsRequired; }
 };
 
-/// A template wrapper used to implement the polymorphic API.
+/// A template wrapper used to implement PassConcept.
 ///
 /// Can be instantiated for any object which provides a \c run method accepting
-/// an \c IRUnitT& and an \c AnalysisManager<IRUnit>&. It requires the pass to
-/// be a copyable object.
+/// an \c IRUnitT& and an \c AnalysisManager<IRUnit>&.
 template <typename IRUnitT, typename PassT, typename AnalysisManagerT,
           typename... ExtraArgTs>
-struct PassModel final : PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> {
-  explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
+class PassModel final
+    : public PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> {
+private:
+  using PassConceptT = PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...>;
 
-  PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
-                        ExtraArgTs... ExtraArgs) override {
-    return Pass.run(IR, AM, ExtraArgs...);
+  PassT Pass;
+
+  static PassT &getPass(PassConceptT &Self) {
+    return static_cast<PassModel &>(Self).Pass;
   }
 
-  void printPipeline(
-      raw_ostream &OS,
-      function_ref<StringRef(StringRef)> MapClassName2PassName) override {
-    Pass.printPipeline(OS, MapClassName2PassName);
+  static void destroyImpl(PassConceptT &Self) {
+    delete static_cast<PassModel *>(&Self);
   }
 
-  StringRef name() const override { return PassT::name(); }
+  static PreservedAnalyses runImpl(PassConceptT &Self, IRUnitT &IR,
+                                   AnalysisManagerT &AM,
+                                   ExtraArgTs... ExtraArgs) {
+    return getPass(Self).run(IR, AM, ExtraArgs...);
+  }
 
-  bool isRequired() const override { return PassT::isRequired(); }
+  static void
+  printPipelineImpl(PassConceptT &Self, raw_ostream &OS,
+                    function_ref<StringRef(StringRef)> MapClassName2PassName) {
+    getPass(Self).printPipeline(OS, MapClassName2PassName);
+  }
 
-  PassT Pass;
+public:
+  explicit PassModel(PassT Pass)
+      : PassConceptT(PassT::name(), PassT::isRequired(), destroyImpl, runImpl,
+                     printPipelineImpl),
+        Pass(std::move(Pass)) {}
 };
 
 /// Abstract concept of an analysis result.
diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
index 973d8a3cb1008..e11af53a47142 100644
--- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
+++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
@@ -113,7 +113,7 @@ class PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
       IsLoopNestPass.push_back(false);
       // Do not use make_unique or emplace_back, they cause too many template
       // instantiations, causing terrible compile times.
-      LoopPasses.push_back(std::unique_ptr<LoopPassConceptT>(
+      LoopPasses.push_back(LoopPassConceptT::unique_ptr(
           new LoopPassModelT(std::forward<PassT>(Pass))));
     } else {
       using LoopNestPassModelT =
@@ -122,7 +122,7 @@ class PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
       IsLoopNestPass.push_back(true);
       // Do not use make_unique or emplace_back, they cause too many template
       // instantiations, causing terrible compile times.
-      LoopNestPasses.push_back(std::unique_ptr<LoopNestPassConceptT>(
+      LoopNestPasses.push_back(LoopNestPassConceptT::unique_ptr(
           new LoopNestPassModelT(std::forward<PassT>(Pass))));
     }
   }
@@ -143,8 +143,8 @@ class PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
   // BitVector that identifies whether the passes are loop passes or loop-nest
   // passes (true for loop-nest passes).
   BitVector IsLoopNestPass;
-  std::vector<std::unique_ptr<LoopPassConceptT>> LoopPasses;
-  std::vector<std::unique_ptr<LoopNestPassConceptT>> LoopNestPasses;
+  std::vector<LoopPassConceptT::unique_ptr> LoopPasses;
+  std::vector<LoopNestPassConceptT::unique_ptr> LoopNestPasses;
 
   /// Run either a loop pass or a loop-nest pass. Returns `std::nullopt` if
   /// PassInstrumentation's BeforePass returns false. Otherwise, returns the
@@ -400,7 +400,7 @@ class FunctionToLoopPassAdaptor
       detail::PassConcept<Loop, LoopAnalysisManager,
                           LoopStandardAnalysisResults &, LPMUpdater &>;
 
-  explicit FunctionToLoopPassAdaptor(std::unique_ptr<PassConceptT> Pass,
+  explicit FunctionToLoopPassAdaptor(PassConceptT::unique_ptr Pass,
                                      bool UseMemorySSA = false,
                                      bool LoopNestMode = false)
       : Pass(std::move(Pass)), UseMemorySSA(UseMemorySSA),
@@ -418,7 +418,7 @@ class FunctionToLoopPassAdaptor
   bool isLoopNestMode() const { return LoopNestMode; }
 
 private:
-  std::unique_ptr<PassConceptT> Pass;
+  PassConceptT::unique_ptr Pass;
 
   FunctionPassManager LoopCanonicalizationFPM;
 
@@ -443,7 +443,7 @@ createFunctionToLoopPassAdaptor(LoopPassT &&Pass, bool UseMemorySSA = false) {
     // Do not use make_unique, it causes too many template instantiations,
     // causing terrible compile times.
     return FunctionToLoopPassAdaptor(
-        std::unique_ptr<FunctionToLoopPassAdaptor::PassConceptT>(
+        FunctionToLoopPassAdaptor::PassConceptT::unique_ptr(
             new PassModelT(std::forward<LoopPassT>(Pass))),
         UseMemorySSA, false);
   } else {
@@ -455,7 +455,7 @@ createFunctionToLoopPassAdaptor(LoopPassT &&Pass, bool UseMemorySSA = false) {
     // Do not use make_unique, it causes too many template instantiations,
     // causing terrible compile times.
     return FunctionToLoopPassAdaptor(
-        std::unique_ptr<FunctionToLoopPassAdaptor::PassConceptT>(
+        FunctionToLoopPassAdaptor::PassConceptT::unique_ptr(
             new PassModelT(std::move(LPM))),
         UseMemorySSA, true);
   }
@@ -476,7 +476,7 @@ createFunctionToLoopPassAdaptor<LoopPassManager>(LoopPassManager &&LPM,
   // Do not use make_unique, it causes too many template instantiations,
   // causing terrible compile times.
   return FunctionToLoopPassAdaptor(
-      std::unique_ptr<FunctionToLoopPassAdaptor::PassConceptT>(
+      FunctionToLoopPassAdaptor::PassConceptT::unique_ptr(
           new PassModelT(std::move(LPM))),
       UseMemorySSA, LoopNestMode);
 }

>From a01c83d7eca786f8030635480cbade114dd0db71 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Tue, 14 Jul 2026 11:23:55 +0000
Subject: [PATCH 2/2] more cleanup, wrap PassModel construction in function

Created using spr 1.3.8-wip
---
 llvm/include/llvm/Analysis/CGSCCPassManager.h | 22 +++---------
 .../include/llvm/CodeGen/MachinePassManager.h |  5 +--
 llvm/include/llvm/IR/PassManager.h            | 13 ++-----
 llvm/include/llvm/IR/PassManagerInternal.h    |  8 +++--
 .../llvm/Transforms/Scalar/LoopPassManager.h  | 36 +++++--------------
 5 files changed, 24 insertions(+), 60 deletions(-)

diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h
index 1cfe68ee6fa59..f2ce8158675ae 100644
--- a/llvm/include/llvm/Analysis/CGSCCPassManager.h
+++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h
@@ -358,11 +358,7 @@ createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT &&Pass) {
   using PassModelT =
       detail::PassModel<LazyCallGraph::SCC, CGSCCPassT, CGSCCAnalysisManager,
                         LazyCallGraph &, CGSCCUpdateResult &>;
-  // Do not use make_unique, it causes too many template instantiations,
-  // causing terrible compile times.
-  return ModuleToPostOrderCGSCCPassAdaptor(
-      ModuleToPostOrderCGSCCPassAdaptor::PassConceptT::unique_ptr(
-          new PassModelT(std::forward<CGSCCPassT>(Pass))));
+  return ModuleToPostOrderCGSCCPassAdaptor(PassModelT::create(std::move(Pass)));
 }
 
 /// A proxy from a \c FunctionAnalysisManager to an \c SCC.
@@ -504,12 +500,8 @@ createCGSCCToFunctionPassAdaptor(FunctionPassT &&Pass,
                                  bool NoRerun = false) {
   using PassModelT =
       detail::PassModel<Function, FunctionPassT, FunctionAnalysisManager>;
-  // Do not use make_unique, it causes too many template instantiations,
-  // causing terrible compile times.
-  return CGSCCToFunctionPassAdaptor(
-      CGSCCToFunctionPassAdaptor::PassConceptT::unique_ptr(
-          new PassModelT(std::forward<FunctionPassT>(Pass))),
-      EagerlyInvalidate, NoRerun);
+  return CGSCCToFunctionPassAdaptor(PassModelT::create(std::move(Pass)),
+                                    EagerlyInvalidate, NoRerun);
 }
 
 // A marker to determine if function passes should be run on a function within a
@@ -577,12 +569,8 @@ DevirtSCCRepeatedPass createDevirtSCCRepeatedPass(CGSCCPassT &&Pass,
   using PassModelT =
       detail::PassModel<LazyCallGraph::SCC, CGSCCPassT, CGSCCAnalysisManager,
                         LazyCallGraph &, CGSCCUpdateResult &>;
-  // Do not use make_unique, it causes too many template instantiations,
-  // causing terrible compile times.
-  return DevirtSCCRepeatedPass(
-      DevirtSCCRepeatedPass::PassConceptT::unique_ptr(
-          new PassModelT(std::forward<CGSCCPassT>(Pass))),
-      MaxIterations);
+  return DevirtSCCRepeatedPass(PassModelT::create(std::move(Pass)),
+                               MaxIterations);
 }
 
 // Clear out the debug logging macro.
diff --git a/llvm/include/llvm/CodeGen/MachinePassManager.h b/llvm/include/llvm/CodeGen/MachinePassManager.h
index 5de520fa550f8..f4d5ab4d55b2d 100644
--- a/llvm/include/llvm/CodeGen/MachinePassManager.h
+++ b/llvm/include/llvm/CodeGen/MachinePassManager.h
@@ -212,11 +212,8 @@ FunctionToMachineFunctionPassAdaptor
 createFunctionToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) {
   using PassModelT = detail::PassModel<MachineFunction, MachineFunctionPassT,
                                        MachineFunctionAnalysisManager>;
-  // Do not use make_unique, it causes too many template instantiations,
-  // causing terrible compile times.
   return FunctionToMachineFunctionPassAdaptor(
-      FunctionToMachineFunctionPassAdaptor::PassConceptT::unique_ptr(
-          new PassModelT(std::forward<MachineFunctionPassT>(Pass))));
+      PassModelT::create(std::move(Pass)));
 }
 
 template <>
diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h
index 0c6dac6be8d31..adb375f4f837a 100644
--- a/llvm/include/llvm/IR/PassManager.h
+++ b/llvm/include/llvm/IR/PassManager.h
@@ -220,10 +220,7 @@ class PassManager : public RequiredPassInfoMixin<
   addPass(PassT &&Pass) {
     using PassModelT =
         detail::PassModel<IRUnitT, PassT, AnalysisManagerT, ExtraArgTs...>;
-    // Do not use make_unique or emplace_back, they cause too many template
-    // instantiations, causing terrible compile times.
-    Passes.push_back(typename PassConceptT::unique_ptr(
-        new PassModelT(std::forward<PassT>(Pass))));
+    Passes.push_back(PassModelT::create(std::move(Pass)));
   }
 
   /// When adding a pass manager pass that has the same type as this pass
@@ -898,12 +895,8 @@ createModuleToFunctionPassAdaptor(FunctionPassT &&Pass,
                                   bool EagerlyInvalidate = false) {
   using PassModelT =
       detail::PassModel<Function, FunctionPassT, FunctionAnalysisManager>;
-  // Do not use make_unique, it causes too many template instantiations,
-  // causing terrible compile times.
-  return ModuleToFunctionPassAdaptor(
-      ModuleToFunctionPassAdaptor::PassConceptT::unique_ptr(
-          new PassModelT(std::forward<FunctionPassT>(Pass))),
-      EagerlyInvalidate);
+  return ModuleToFunctionPassAdaptor(PassModelT::create(std::move(Pass)),
+                                     EagerlyInvalidate);
 }
 
 /// A utility pass template to force an analysis result to be available.
diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h
index d731bc56a2820..376dcd7d3af62 100644
--- a/llvm/include/llvm/IR/PassManagerInternal.h
+++ b/llvm/include/llvm/IR/PassManagerInternal.h
@@ -134,11 +134,15 @@ class PassModel final
     getPass(Self).printPipeline(OS, MapClassName2PassName);
   }
 
-public:
-  explicit PassModel(PassT Pass)
+  explicit PassModel(PassT &&Pass)
       : PassConceptT(PassT::name(), PassT::isRequired(), destroyImpl, runImpl,
                      printPipelineImpl),
         Pass(std::move(Pass)) {}
+
+public:
+  static typename PassConceptT::unique_ptr create(PassT &&Pass) {
+    return typename PassConceptT::unique_ptr(new PassModel(std::move(Pass)));
+  }
 };
 
 /// Abstract concept of an analysis result.
diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
index e11af53a47142..bb882096142f7 100644
--- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
+++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
@@ -111,19 +111,13 @@ class PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
           detail::PassModel<Loop, PassT, LoopAnalysisManager,
                             LoopStandardAnalysisResults &, LPMUpdater &>;
       IsLoopNestPass.push_back(false);
-      // Do not use make_unique or emplace_back, they cause too many template
-      // instantiations, causing terrible compile times.
-      LoopPasses.push_back(LoopPassConceptT::unique_ptr(
-          new LoopPassModelT(std::forward<PassT>(Pass))));
+      LoopPasses.push_back(LoopPassModelT::create(std::move(Pass)));
     } else {
       using LoopNestPassModelT =
           detail::PassModel<LoopNest, PassT, LoopAnalysisManager,
                             LoopStandardAnalysisResults &, LPMUpdater &>;
       IsLoopNestPass.push_back(true);
-      // Do not use make_unique or emplace_back, they cause too many template
-      // instantiations, causing terrible compile times.
-      LoopNestPasses.push_back(LoopNestPassConceptT::unique_ptr(
-          new LoopNestPassModelT(std::forward<PassT>(Pass))));
+      LoopNestPasses.push_back(LoopNestPassModelT::create(std::move(Pass)));
     }
   }
 
@@ -440,24 +434,16 @@ createFunctionToLoopPassAdaptor(LoopPassT &&Pass, bool UseMemorySSA = false) {
     using PassModelT =
         detail::PassModel<Loop, LoopPassT, LoopAnalysisManager,
                           LoopStandardAnalysisResults &, LPMUpdater &>;
-    // Do not use make_unique, it causes too many template instantiations,
-    // causing terrible compile times.
-    return FunctionToLoopPassAdaptor(
-        FunctionToLoopPassAdaptor::PassConceptT::unique_ptr(
-            new PassModelT(std::forward<LoopPassT>(Pass))),
-        UseMemorySSA, false);
+    return FunctionToLoopPassAdaptor(PassModelT::create(std::move(Pass)),
+                                     UseMemorySSA, false);
   } else {
     LoopPassManager LPM;
-    LPM.addPass(std::forward<LoopPassT>(Pass));
+    LPM.addPass(std::move(Pass));
     using PassModelT =
         detail::PassModel<Loop, LoopPassManager, LoopAnalysisManager,
                           LoopStandardAnalysisResults &, LPMUpdater &>;
-    // Do not use make_unique, it causes too many template instantiations,
-    // causing terrible compile times.
-    return FunctionToLoopPassAdaptor(
-        FunctionToLoopPassAdaptor::PassConceptT::unique_ptr(
-            new PassModelT(std::move(LPM))),
-        UseMemorySSA, true);
+    return FunctionToLoopPassAdaptor(PassModelT::create(std::move(LPM)),
+                                     UseMemorySSA, true);
   }
 }
 
@@ -473,12 +459,8 @@ createFunctionToLoopPassAdaptor<LoopPassManager>(LoopPassManager &&LPM,
       detail::PassModel<Loop, LoopPassManager, LoopAnalysisManager,
                         LoopStandardAnalysisResults &, LPMUpdater &>;
   bool LoopNestMode = (LPM.getNumLoopPasses() == 0);
-  // Do not use make_unique, it causes too many template instantiations,
-  // causing terrible compile times.
-  return FunctionToLoopPassAdaptor(
-      FunctionToLoopPassAdaptor::PassConceptT::unique_ptr(
-          new PassModelT(std::move(LPM))),
-      UseMemorySSA, LoopNestMode);
+  return FunctionToLoopPassAdaptor(PassModelT::create(std::move(LPM)),
+                                   UseMemorySSA, LoopNestMode);
 }
 
 /// Pass for printing a loop's contents as textual IR.



More information about the llvm-commits mailing list