From 1c28b57b8b1d50245e7b0e90b08352e971c41c30 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Tue, 17 Jan 2017 19:18:12 +0000 Subject: [PATCH] [PM] Teach the LoopPassManager to automatically canonicalize loops by runnig LCSSA over them prior to running the loop pipeline. This also teaches the loop PM to verify that LCSSA form is preserved throughout the pipeline's run across the loop nest. Most of the test updates just leverage this new functionality. One has to be relaxed with the new PM as IVUsers is less powerful when it sees LCSSA input. Differential Revision: https://reviews.llvm.org/D28743 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292241 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../llvm/Transforms/Scalar/LoopPassManager.h | 24 +++++++++++++++---- test/Analysis/IVUsers/quadradic-exit-value.ll | 6 ++--- test/Other/new-pass-manager.ll | 2 +- test/Transforms/LICM/atomics.ll | 2 +- test/Transforms/LICM/constexpr.ll | 2 +- test/Transforms/LICM/hoist-nounwind.ll | 2 +- test/Transforms/LICM/hoisting.ll | 2 +- 7 files changed, 28 insertions(+), 12 deletions(-) diff --git a/include/llvm/Transforms/Scalar/LoopPassManager.h b/include/llvm/Transforms/Scalar/LoopPassManager.h index e9973fec6bd..ea79d6ef703 100644 --- a/include/llvm/Transforms/Scalar/LoopPassManager.h +++ b/include/llvm/Transforms/Scalar/LoopPassManager.h @@ -51,6 +51,7 @@ #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Utils/LCSSA.h" namespace llvm { @@ -248,10 +249,18 @@ template class FunctionToLoopPassAdaptor : public PassInfoMixin> { public: - explicit FunctionToLoopPassAdaptor(LoopPassT Pass) : Pass(std::move(Pass)) {} + explicit FunctionToLoopPassAdaptor(LoopPassT Pass) : Pass(std::move(Pass)) { + LoopCanonicalizationFPM.addPass(LCSSAPass()); + } /// \brief Runs the loop passes across every loop in the function. PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { + // Before we even compute any loop analyses, first run a miniature function + // pass pipeline to put loops into their canonical form. Note that we can + // directly build up function analyses after this as the function pass + // manager handles all the invalidation at that layer. + PreservedAnalyses PA = LoopCanonicalizationFPM.run(F, AM); + // Setup the loop analysis manager from its proxy. LoopAnalysisManager &LAM = AM.getResult(F).getManager(); @@ -260,7 +269,7 @@ public: // If there are no loops, there is nothing to do here. if (LI.empty()) - return PreservedAnalyses::all(); + return PA; // Get the analysis results needed by loop passes. LoopStandardAnalysisResults LAR = {AM.getResult(F), @@ -271,8 +280,6 @@ public: AM.getResult(F), AM.getResult(F)}; - PreservedAnalyses PA = PreservedAnalyses::all(); - // A postorder worklist of loops to process. SmallPriorityWorklist Worklist; @@ -294,8 +301,15 @@ public: // Reset the update structure for this loop. Updater.CurrentL = L; Updater.SkipCurrentLoop = false; + #ifndef NDEBUG + // Save a parent loop pointer for asserts. Updater.ParentL = L->getParentLoop(); + + // Verify the loop structure and LCSSA form before visiting the loop. + L->verifyLoop(); + assert(L->isRecursivelyLCSSAForm(LAR.DT, LI) && + "Loops must remain in LCSSA form!"); #endif PreservedAnalyses PassPA = Pass.run(*L, LAM, LAR, Updater); @@ -335,6 +349,8 @@ public: private: LoopPassT Pass; + + FunctionPassManager LoopCanonicalizationFPM; }; /// \brief A function to deduce a loop pass type and wrap it in the templated diff --git a/test/Analysis/IVUsers/quadradic-exit-value.ll b/test/Analysis/IVUsers/quadradic-exit-value.ll index 593c0e388da..214afcb2ffa 100644 --- a/test/Analysis/IVUsers/quadradic-exit-value.ll +++ b/test/Analysis/IVUsers/quadradic-exit-value.ll @@ -5,7 +5,7 @@ ; passes *always* work on LCSSA. This should stop using a different set of ; checks at that point. -; RUN: opt < %s -analyze -iv-users | FileCheck %s +; RUN: opt < %s -analyze -iv-users | FileCheck %s --check-prefixes=CHECK,CHECK-NO-LCSSA ; RUN: opt < %s -disable-output -passes='print' 2>&1 | FileCheck %s ; Provide legal integer types. @@ -14,7 +14,7 @@ target datalayout = "n8:16:32:64" ; The value of %r is dependent on a polynomial iteration expression. ; ; CHECK-LABEL: IV Users for loop %foo.loop -; CHECK: {1,+,3,+,2}<%foo.loop> +; CHECK-NO-LCSSA: {1,+,3,+,2}<%foo.loop> define i64 @foo(i64 %n) { entry: br label %foo.loop @@ -36,7 +36,7 @@ exit: ; sure they aren't marked as post-inc users. ; ; CHECK-LABEL: IV Users for loop %test2.loop -; CHECK: %sext.us = {0,+,(16777216 + (-16777216 * %sub.us)),+,33554432}<%test2.loop> in %f = ashr i32 %sext.us, 24 +; CHECK-NO-LCSSA: %sext.us = {0,+,(16777216 + (-16777216 * %sub.us)),+,33554432}<%test2.loop> in %f = ashr i32 %sext.us, 24 define i32 @test2() { entry: br label %test2.loop diff --git a/test/Other/new-pass-manager.ll b/test/Other/new-pass-manager.ll index eae2d855e92..069d8e214c2 100644 --- a/test/Other/new-pass-manager.ll +++ b/test/Other/new-pass-manager.ll @@ -539,9 +539,9 @@ ; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> ; CHECK-REPEAT-LOOP-PASS-NEXT: Starting llvm::Function pass manager run ; CHECK-REPEAT-LOOP-PASS-NEXT: Running pass: FunctionToLoopPassAdaptor -; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> ; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: LoopAnalysis ; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: DominatorTreeAnalysis +; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}> ; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: AAManager ; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: TargetLibraryAnalysis ; CHECK-REPEAT-LOOP-PASS-NEXT: Running analysis: AssumptionAnalysis diff --git a/test/Transforms/LICM/atomics.ll b/test/Transforms/LICM/atomics.ll index d23cb49c548..919d1bdd114 100644 --- a/test/Transforms/LICM/atomics.ll +++ b/test/Transforms/LICM/atomics.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -S -basicaa -licm | FileCheck %s -; RUN: opt -aa-pipeline=basic-aa -passes='lcssa,require,require,require,require,loop(licm)' < %s -S | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require,loop(licm)' < %s -S | FileCheck %s ; Check that we can hoist unordered loads define i32 @test1(i32* nocapture %y) nounwind uwtable ssp { diff --git a/test/Transforms/LICM/constexpr.ll b/test/Transforms/LICM/constexpr.ll index 8ffc7351360..488821ac8fd 100644 --- a/test/Transforms/LICM/constexpr.ll +++ b/test/Transforms/LICM/constexpr.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -S -basicaa -licm | FileCheck %s -; RUN: opt -aa-pipeline=basic-aa -passes='lcssa,require,require,require,require,loop(licm)' < %s -S | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require,loop(licm)' < %s -S | FileCheck %s ; This fixes PR22460 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/Transforms/LICM/hoist-nounwind.ll b/test/Transforms/LICM/hoist-nounwind.ll index e9720235893..9fc4903b830 100644 --- a/test/Transforms/LICM/hoist-nounwind.ll +++ b/test/Transforms/LICM/hoist-nounwind.ll @@ -1,5 +1,5 @@ ; RUN: opt -S -basicaa -licm < %s | FileCheck %s -; RUN: opt -aa-pipeline=basic-aa -passes='lcssa,require,require,require,require,loop(licm)' -S %s | FileCheck %s +; RUN: opt -aa-pipeline=basic-aa -passes='require,loop(licm)' -S %s | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/Transforms/LICM/hoisting.ll b/test/Transforms/LICM/hoisting.ll index 29595b3e1cc..9b29f5d600f 100644 --- a/test/Transforms/LICM/hoisting.ll +++ b/test/Transforms/LICM/hoisting.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -licm -S | FileCheck %s -; RUN: opt -lcssa %s | opt -aa-pipeline=basic-aa -passes='require,require,require,require,loop(licm)' -S | FileCheck %s +; RUN: opt < %s -aa-pipeline=basic-aa -passes='require,loop(licm)' -S | FileCheck %s @X = global i32 0 ; [#uses=1] -- 2.40.0