diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h --- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h @@ -62,6 +62,16 @@ // Forward declarations of an update tracking API used in the pass manager. class LPMUpdater; +namespace { + +template +using HasRunOnLoopT = decltype(std::declval().run( + std::declval(), std::declval(), + std::declval(), + std::declval())); + +} // namespace + // Explicit specialization and instantiation declarations for the pass manager. // See the comments on the definition of the specialization for details on how // it differs from the primary template. @@ -71,13 +81,6 @@ : public PassInfoMixin< PassManager> { -private: - template - using HasRunOnLoopT = decltype(std::declval().run( - std::declval(), std::declval(), - std::declval(), - std::declval())); - public: /// Construct a pass manager. /// @@ -155,6 +158,9 @@ static bool isRequired() { return true; } + size_t getNumLoopPasses() const { return LoopPasses.size(); } + size_t getNumLoopNestPasses() const { return LoopNestPasses.size(); } + protected: using LoopPassConceptT = detail::PassConceptcontains(&L)) && "Cannot delete a loop outside of the " @@ -264,6 +272,8 @@ /// loops within them will be visited in postorder as usual for the loop pass /// manager. void addChildLoops(ArrayRef NewChildLoops) { + assert(!LoopNestMode && + "Child loops should not be pushed in loop-nest mode."); // Insert ourselves back into the worklist first, as this loop should be // revisited after all the children have been processed. Worklist.insert(CurrentL); @@ -295,7 +305,10 @@ "All of the new loops must be siblings of the current loop!"); #endif - appendLoopsToWorklist(NewSibLoops, Worklist); + if (LoopNestMode) + Worklist.insert(NewSibLoops); + else + appendLoopsToWorklist(NewSibLoops, Worklist); // No need to skip the current loop or revisit it, as sibling loops // shouldn't impact anything. @@ -325,6 +338,7 @@ Loop *CurrentL; bool SkipCurrentLoop; + const bool LoopNestMode; #ifndef NDEBUG // In debug builds we also track the parent loop to implement asserts even in @@ -333,8 +347,8 @@ #endif LPMUpdater(SmallPriorityWorklist &Worklist, - LoopAnalysisManager &LAM) - : Worklist(Worklist), LAM(LAM) {} + LoopAnalysisManager &LAM, bool LoopNestMode = false) + : Worklist(Worklist), LAM(LAM), LoopNestMode(LoopNestMode) {} }; template @@ -372,9 +386,10 @@ : public PassInfoMixin> { public: explicit FunctionToLoopPassAdaptor(LoopPassT Pass, bool UseMemorySSA = false, - bool DebugLogging = false) + bool DebugLogging = false, + bool LoopNestMode = false) : Pass(std::move(Pass)), LoopCanonicalizationFPM(DebugLogging), - UseMemorySSA(UseMemorySSA) { + UseMemorySSA(UseMemorySSA), LoopNestMode(LoopNestMode) { LoopCanonicalizationFPM.addPass(LoopSimplifyPass()); LoopCanonicalizationFPM.addPass(LCSSAPass()); } @@ -430,11 +445,16 @@ // Register the worklist and loop analysis manager so that loop passes can // update them when they mutate the loop nest structure. - LPMUpdater Updater(Worklist, LAM); + LPMUpdater Updater(Worklist, LAM, LoopNestMode); // Add the loop nests in the reverse order of LoopInfo. See method // declaration. - appendLoopsToWorklist(LI, Worklist); + if (!LoopNestMode) { + appendLoopsToWorklist(LI, Worklist); + } else { + for (Loop *L : LI) + Worklist.insert(L); + } #ifndef NDEBUG PI.pushBeforeNonSkippedPassCallback([&LAR, &LI](StringRef PassID, Any IR) { @@ -455,6 +475,8 @@ do { Loop *L = Worklist.pop_back_val(); + assert(!(LoopNestMode && L->getParentLoop()) && + "L should be a top-level loop in loop-nest mode."); // Reset the update structure for this loop. Updater.CurrentL = L; @@ -530,16 +552,28 @@ FunctionPassManager LoopCanonicalizationFPM; bool UseMemorySSA = false; + const bool LoopNestMode; }; /// A function to deduce a loop pass type and wrap it in the templated /// adaptor. template -FunctionToLoopPassAdaptor +inline FunctionToLoopPassAdaptor createFunctionToLoopPassAdaptor(LoopPassT Pass, bool UseMemorySSA = false, bool DebugLogging = false) { - return FunctionToLoopPassAdaptor(std::move(Pass), UseMemorySSA, - DebugLogging); + return FunctionToLoopPassAdaptor( + std::move(Pass), UseMemorySSA, DebugLogging, + is_detected::value); +} + +template <> +inline FunctionToLoopPassAdaptor +createFunctionToLoopPassAdaptor(LoopPassManager LPM, + bool UseMemorySSA, + bool DebugLogging) { + bool LoopNestMode = (LPM.getNumLoopPasses() == 0); + return FunctionToLoopPassAdaptor( + std::move(LPM), UseMemorySSA, DebugLogging, LoopNestMode); } /// Pass for printing a loop's contents as textual IR.