Skip to content

[Pass] Support eraseIf in pass manager #116734

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

paperchalice
Copy link
Contributor

Split from #108690.
These methods are required to support start stop options in llc.

@llvmbot
Copy link
Member

llvmbot commented Nov 19, 2024

@llvm/pr-subscribers-llvm-ir
@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: None (paperchalice)

Changes

Split from #108690.
These methods are required to support start stop options in llc.


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

8 Files Affected:

  • (modified) llvm/include/llvm/Analysis/CGSCCPassManager.h (+6)
  • (modified) llvm/include/llvm/CodeGen/MachinePassManager.h (+4)
  • (modified) llvm/include/llvm/IR/PassManager.h (+19)
  • (modified) llvm/include/llvm/IR/PassManagerInternal.h (+35)
  • (modified) llvm/include/llvm/Transforms/Scalar/LoopPassManager.h (+8)
  • (modified) llvm/lib/Analysis/CGSCCPassManager.cpp (+23)
  • (modified) llvm/lib/IR/PassManager.cpp (+11)
  • (modified) llvm/lib/Transforms/Scalar/LoopPassManager.cpp (+44)
diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h
index 15b7f226fd8283..4a49bfb283b6a2 100644
--- a/llvm/include/llvm/Analysis/CGSCCPassManager.h
+++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h
@@ -346,6 +346,10 @@ class ModuleToPostOrderCGSCCPassAdaptor
 
   static bool isRequired() { return true; }
 
+  bool isEmpty() const { return Pass == nullptr; }
+
+  void eraseIf(function_ref<bool(StringRef)> Pred);
+
 private:
   std::unique_ptr<PassConceptT> Pass;
 };
@@ -488,6 +492,8 @@ class CGSCCToFunctionPassAdaptor
 
   static bool isRequired() { return true; }
 
+  void eraseIf(function_ref<bool(StringRef)> Pred);
+
 private:
   std::unique_ptr<PassConceptT> Pass;
   bool EagerlyInvalidate;
diff --git a/llvm/include/llvm/CodeGen/MachinePassManager.h b/llvm/include/llvm/CodeGen/MachinePassManager.h
index 69b5f6e92940c4..3d7c7d87af480a 100644
--- a/llvm/include/llvm/CodeGen/MachinePassManager.h
+++ b/llvm/include/llvm/CodeGen/MachinePassManager.h
@@ -207,6 +207,10 @@ class FunctionToMachineFunctionPassAdaptor
 
   static bool isRequired() { return true; }
 
+  bool isEmpty() const { return Pass == nullptr; }
+
+  void eraseIf(function_ref<bool(StringRef)> Pred);
+
 private:
   std::unique_ptr<PassConceptT> Pass;
 };
diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h
index d269221fac0701..4f28b4aceb3e66 100644
--- a/llvm/include/llvm/IR/PassManager.h
+++ b/llvm/include/llvm/IR/PassManager.h
@@ -218,6 +218,21 @@ class PassManager : public PassInfoMixin<
 
   static bool isRequired() { return true; }
 
+  /// Erase all passes that satisfy the predicate \p Pred.
+  /// For internal use only!
+  void eraseIf(function_ref<bool(StringRef)> Pred) {
+    for (auto I = Passes.begin(); I != Passes.end();) {
+      (*I)->eraseIf(Pred);
+      bool IsSpecial = (*I)->name().ends_with("PassAdaptor") ||
+                       (*I)->name().contains("PassManager");
+      bool PredResult = Pred((*I)->name());
+      if ((!IsSpecial && PredResult) || (IsSpecial && (*I)->isEmpty()))
+        I = Passes.erase(I);
+      else
+        ++I;
+    }
+  }
+
 protected:
   using PassConceptT =
       detail::PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...>;
@@ -836,6 +851,10 @@ class ModuleToFunctionPassAdaptor
 
   static bool isRequired() { return true; }
 
+  bool isEmpty() const { return Pass == nullptr; }
+
+  void eraseIf(function_ref<bool(StringRef)> Pred);
+
 private:
   std::unique_ptr<PassConceptT> Pass;
   bool EagerlyInvalidate;
diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h
index 4ada6ee5dd6831..3a75c9c4e97faf 100644
--- a/llvm/include/llvm/IR/PassManagerInternal.h
+++ b/llvm/include/llvm/IR/PassManagerInternal.h
@@ -59,6 +59,13 @@ struct PassConcept {
   /// To opt-in, pass should implement `static bool isRequired()`. It's no-op
   /// to have `isRequired` always return false since that is the default.
   virtual bool isRequired() const = 0;
+
+  /// Polymorphic method to refurbish pass pipeline.
+  virtual void eraseIf(function_ref<bool(StringRef)> Pred) = 0;
+
+  /// There may be some empty PassManager after erasing,
+  /// use it to remove them.
+  virtual bool isEmpty() const = 0;
 };
 
 /// A template wrapper used to implement the polymorphic API.
@@ -114,6 +121,34 @@ struct PassModel : PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> {
 
   bool isRequired() const override { return passIsRequiredImpl<PassT>(); }
 
+  template <typename T>
+  using has_erase_if_t = decltype(std::declval<T &>().eraseIf(
+      std::declval<function_ref<bool(StringRef)>>()));
+
+  template <typename T>
+  std::enable_if_t<is_detected<has_erase_if_t, T>::value>
+  eraseIfImpl(function_ref<bool(StringRef)> Pred) {
+    Pass.eraseIf(Pred);
+  }
+
+  template <typename T>
+  std::enable_if_t<!is_detected<has_erase_if_t, T>::value>
+  eraseIfImpl(function_ref<bool(StringRef)>) {}
+
+  void eraseIf(function_ref<bool(StringRef)> Pred) override {
+    eraseIfImpl<PassT>(Pred);
+  }
+
+  template <typename T>
+  using has_is_empty_t = decltype(std::declval<T &>().isEmpty());
+
+  bool isEmpty() const override {
+    if constexpr (is_detected<has_is_empty_t, PassT>::value)
+      return Pass.isEmpty();
+    else
+      return false;
+  }
+
   PassT Pass;
 };
 
diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
index f55022fbff07c1..33ebbd711bec04 100644
--- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
+++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
@@ -134,6 +134,10 @@ class PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
 
   static bool isRequired() { return true; }
 
+  /// Erase all passes that satisfy the predicate \p Pred.
+  /// For internal use only!
+  void eraseIf(function_ref<bool(StringRef)> Pred);
+
   size_t getNumLoopPasses() const { return LoopPasses.size(); }
   size_t getNumLoopNestPasses() const { return LoopNestPasses.size(); }
 
@@ -425,6 +429,10 @@ class FunctionToLoopPassAdaptor
 
   static bool isRequired() { return true; }
 
+  bool isEmpty() const { return Pass == nullptr; }
+
+  void eraseIf(function_ref<bool(StringRef)> Pred);
+
   bool isLoopNestMode() const { return LoopNestMode; }
 
 private:
diff --git a/llvm/lib/Analysis/CGSCCPassManager.cpp b/llvm/lib/Analysis/CGSCCPassManager.cpp
index 948bc2435ab275..d87ed86655ab30 100644
--- a/llvm/lib/Analysis/CGSCCPassManager.cpp
+++ b/llvm/lib/Analysis/CGSCCPassManager.cpp
@@ -576,6 +576,17 @@ PreservedAnalyses CGSCCToFunctionPassAdaptor::run(LazyCallGraph::SCC &C,
   return PA;
 }
 
+void CGSCCToFunctionPassAdaptor::eraseIf(function_ref<bool(StringRef)> Pred) {
+  StringRef PassName = Pass->name();
+  if (PassName.contains("PassManager") || PassName.ends_with("PassAdaptor")) {
+    Pass->eraseIf(Pred);
+    if (Pass->isEmpty())
+      Pass.reset();
+  } else if (Pred(PassName)) {
+    Pass.reset();
+  }
+}
+
 bool CGSCCAnalysisManagerModuleProxy::Result::invalidate(
     Module &M, const PreservedAnalyses &PA,
     ModuleAnalysisManager::Invalidator &Inv) {
@@ -751,6 +762,18 @@ bool FunctionAnalysisManagerCGSCCProxy::Result::invalidate(
   return false;
 }
 
+void ModuleToPostOrderCGSCCPassAdaptor::eraseIf(
+    function_ref<bool(StringRef)> Pred) {
+  StringRef PassName = Pass->name();
+  if (PassName.contains("PassManager") || PassName.ends_with("PassAdaptor")) {
+    Pass->eraseIf(Pred);
+    if (Pass->isEmpty())
+      Pass.reset();
+  } else if (Pred(PassName)) {
+    Pass.reset();
+  }
+}
+
 } // end namespace llvm
 
 /// When a new SCC is created for the graph we first update the
diff --git a/llvm/lib/IR/PassManager.cpp b/llvm/lib/IR/PassManager.cpp
index bf8f7906d3368d..0c9ee99f24dd19 100644
--- a/llvm/lib/IR/PassManager.cpp
+++ b/llvm/lib/IR/PassManager.cpp
@@ -145,6 +145,17 @@ PreservedAnalyses ModuleToFunctionPassAdaptor::run(Module &M,
   return PA;
 }
 
+void ModuleToFunctionPassAdaptor::eraseIf(function_ref<bool(StringRef)> Pred) {
+  StringRef PassName = Pass->name();
+  if (PassName.contains("PassManager") || PassName.ends_with("PassAdaptor")) {
+    Pass->eraseIf(Pred);
+    if (Pass->isEmpty())
+      Pass.reset();
+  } else if (Pred(PassName)) {
+    Pass.reset();
+  }
+}
+
 template <>
 void llvm::printIRUnitNameForStackTrace<Module>(raw_ostream &OS,
                                                 const Module &IR) {
diff --git a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
index 9f4270f5d62f5c..081303c2dda4c9 100644
--- a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
@@ -62,6 +62,39 @@ void PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
   }
 }
 
+void PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
+                 LPMUpdater &>::eraseIf(function_ref<bool(StringRef)> Pred) {
+  std::vector<char> IsLoopNestPassVec(
+      static_cast<size_t>(IsLoopNestPass.size()));
+  for (unsigned Idx = 0, Sz = IsLoopNestPass.size(); Idx != Sz; ++Idx)
+    IsLoopNestPassVec[Idx] = IsLoopNestPass[Idx];
+
+  auto ILP = LoopPasses.begin();
+  auto ILNP = LoopNestPasses.begin();
+  for (auto I = IsLoopNestPassVec.begin(); I != IsLoopNestPassVec.end();) {
+    if (*I) {
+      if (Pred((*ILNP)->name())) {
+        I = IsLoopNestPassVec.erase(I);
+        ILNP = LoopNestPasses.erase(ILNP);
+        continue;
+      }
+      ++ILNP;
+    } else {
+      if (Pred((*ILP)->name())) {
+        I = IsLoopNestPassVec.erase(I);
+        ILP = LoopPasses.erase(ILP);
+        continue;
+      }
+      ++ILP;
+    }
+    ++I;
+  }
+
+  IsLoopNestPass.clear();
+  for (const auto I : IsLoopNestPassVec)
+    IsLoopNestPass.push_back(I);
+}
+
 // Run both loop passes and loop-nest passes on top-level loop \p L.
 PreservedAnalyses
 LoopPassManager::runWithLoopNestPasses(Loop &L, LoopAnalysisManager &AM,
@@ -359,6 +392,17 @@ PreservedAnalyses FunctionToLoopPassAdaptor::run(Function &F,
   return PA;
 }
 
+void FunctionToLoopPassAdaptor::eraseIf(function_ref<bool(StringRef)> Pred) {
+  StringRef PassName = Pass->name();
+  if (PassName.contains("PassManager") || PassName.ends_with("PassAdaptor")) {
+    Pass->eraseIf(Pred);
+    if (Pass->isEmpty())
+      Pass.reset();
+  } else if (Pred(PassName)) {
+    Pass.reset();
+  }
+}
+
 PrintLoopPass::PrintLoopPass() : OS(dbgs()) {}
 PrintLoopPass::PrintLoopPass(raw_ostream &OS, const std::string &Banner)
     : OS(OS), Banner(Banner) {}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants