]> granicus.if.org Git - llvm/commitdiff
[LoopInfo] Add helper methods to compute two useful orderings of the
authorChandler Carruth <chandlerc@gmail.com>
Fri, 20 Jan 2017 02:41:20 +0000 (02:41 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Fri, 20 Jan 2017 02:41:20 +0000 (02:41 +0000)
loops in a function.

These are relatively confusing to talk about and compute correctly so it
seems really good to write down their implementation in one place. I've
replaced one place we needed this in the loop PM infrastructure and
I have another place in a pending patch that wants it.

We can't quite use this for the core loop PM walk because there we're
sometimes working on a sub-forest.

I'll add the expected unittests before committing this but wanted to
make sure folks were happy with these names / comments.

Credit goes to Richard Smith for the idea for naming the order where siblings
are in reverse program order but the tree traversal remains preorder.

Differential Revision: https://reviews.llvm.org/D28932

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292569 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/LoopInfo.h
include/llvm/Analysis/LoopInfoImpl.h
lib/Analysis/LoopAnalysisManager.cpp
unittests/Analysis/LoopInfoTest.cpp

index 678ad1c4cf51aa315b059e58ba1c5e2a4f63535c..c49ed78403143f60bc56652ae4344045d6d24f18 100644 (file)
@@ -570,6 +570,23 @@ public:
   reverse_iterator rend() const { return TopLevelLoops.rend(); }
   bool empty() const { return TopLevelLoops.empty(); }
 
+  /// Return all of the loops in the function in preorder across the loop
+  /// nests, with siblings in forward program order.
+  ///
+  /// Note that because loops form a forest of trees, preorder is equivalent to
+  /// reverse postorder.
+  SmallVector<LoopT *, 4> getLoopsInPreorder();
+
+  /// Return all of the loops in the function in preorder across the loop
+  /// nests, with siblings in *reverse* program order.
+  ///
+  /// Note that because loops form a forest of trees, preorder is equivalent to
+  /// reverse postorder.
+  ///
+  /// Also note that this is *not* a reverse preorder. Only the siblings are in
+  /// reverse program order.
+  SmallVector<LoopT *, 4> getLoopsInReverseSiblingPreorder();
+
   /// Return the inner most loop that BB lives in. If a basic block is in no
   /// loop (for example the entry node), null is returned.
   LoopT *getLoopFor(const BlockT *BB) const { return BBMap.lookup(BB); }
index 833a2202a568872c55107d550f1e8f552ccec881..f6a7ab021ede5b1b72defd8962c5c64924fad74b 100644 (file)
@@ -507,6 +507,55 @@ analyze(const DominatorTreeBase<BlockT> &DomTree) {
   DFS.traverse(DomRoot->getBlock());
 }
 
+template <class BlockT, class LoopT>
+SmallVector<LoopT *, 4> LoopInfoBase<BlockT, LoopT>::getLoopsInPreorder() {
+  SmallVector<LoopT *, 4> PreOrderLoops, PreOrderWorklist;
+  // The outer-most loop actually goes into the result in the same relative
+  // order as we walk it. But LoopInfo stores the top level loops in reverse
+  // program order so for here we reverse it to get forward program order.
+  // FIXME: If we change the order of LoopInfo we will want to remove the
+  // reverse here.
+  for (LoopT *RootL : reverse(*this)) {
+    assert(PreOrderWorklist.empty() &&
+           "Must start with an empty preorder walk worklist.");
+    PreOrderWorklist.push_back(RootL);
+    do {
+      LoopT *L = PreOrderWorklist.pop_back_val();
+      // Sub-loops are stored in forward program order, but will process the
+      // worklist backwards so append them in reverse order.
+      PreOrderWorklist.append(L->rbegin(), L->rend());
+      PreOrderLoops.push_back(L);
+    } while (!PreOrderWorklist.empty());
+  }
+
+  return PreOrderLoops;
+}
+
+template <class BlockT, class LoopT>
+SmallVector<LoopT *, 4>
+LoopInfoBase<BlockT, LoopT>::getLoopsInReverseSiblingPreorder() {
+  SmallVector<LoopT *, 4> PreOrderLoops, PreOrderWorklist;
+  // The outer-most loop actually goes into the result in the same relative
+  // order as we walk it. LoopInfo stores the top level loops in reverse
+  // program order so we walk in order here.
+  // FIXME: If we change the order of LoopInfo we will want to add a reverse
+  // here.
+  for (LoopT *RootL : *this) {
+    assert(PreOrderWorklist.empty() &&
+           "Must start with an empty preorder walk worklist.");
+    PreOrderWorklist.push_back(RootL);
+    do {
+      LoopT *L = PreOrderWorklist.pop_back_val();
+      // Sub-loops are stored in forward program order, but will process the
+      // worklist backwards so we can just append them in order.
+      PreOrderWorklist.append(L->begin(), L->end());
+      PreOrderLoops.push_back(L);
+    } while (!PreOrderWorklist.empty());
+  }
+
+  return PreOrderLoops;
+}
+
 // Debugging
 template<class BlockT, class LoopT>
 void LoopInfoBase<BlockT, LoopT>::print(raw_ostream &OS) const {
index 2946baef8aeb03450222fd1edd76fb12d858cf86..e4a0f90b2f7102543abc587554edce0c50d56fc6 100644 (file)
@@ -31,24 +31,10 @@ bool LoopAnalysisManagerFunctionProxy::Result::invalidate(
     FunctionAnalysisManager::Invalidator &Inv) {
   // First compute the sequence of IR units covered by this proxy. We will want
   // to visit this in postorder, but because this is a tree structure we can do
-  // this by building a preorder sequence and walking it in reverse.
-  SmallVector<Loop *, 4> PreOrderLoops, PreOrderWorklist;
-  // Note that we want to walk the roots in reverse order because we will end
-  // up reversing the preorder sequence. However, it happens that the loop nest
-  // roots are in reverse order within the LoopInfo object. So we just walk
-  // forward here.
-  // FIXME: If we change the order of LoopInfo we will want to add a reverse
-  // here.
-  for (Loop *RootL : *LI) {
-    assert(PreOrderWorklist.empty() &&
-           "Must start with an empty preorder walk worklist.");
-    PreOrderWorklist.push_back(RootL);
-    do {
-      Loop *L = PreOrderWorklist.pop_back_val();
-      PreOrderWorklist.append(L->begin(), L->end());
-      PreOrderLoops.push_back(L);
-    } while (!PreOrderWorklist.empty());
-  }
+  // this by building a preorder sequence and walking it backwards. We also
+  // want siblings in forward program order to match the LoopPassManager so we
+  // get the preorder with siblings reversed.
+  SmallVector<Loop *, 4> PreOrderLoops = LI->getLoopsInReverseSiblingPreorder();
 
   // If this proxy or the loop info is going to be invalidated, we also need
   // to clear all the keys coming from that analysis. We also completely blow
index 5a7f130275fb15c733d822a661ad09d3ceffc8fe..647ce8a3c1ba0e9c3f9bf5208c964c2af8dad990 100644 (file)
@@ -81,3 +81,78 @@ TEST(LoopInfoTest, LoopWithSingleLatch) {
     EXPECT_TRUE(loopIDFoundAndSet);
   });
 }
+
+TEST(LoopInfoTest, PreorderTraversals) {
+  const char *ModuleStr = "define void @f() {\n"
+                          "entry:\n"
+                          "  br label %loop.0\n"
+                          "loop.0:\n"
+                          "  br i1 undef, label %loop.0.0, label %loop.1\n"
+                          "loop.0.0:\n"
+                          "  br i1 undef, label %loop.0.0, label %loop.0.1\n"
+                          "loop.0.1:\n"
+                          "  br i1 undef, label %loop.0.1, label %loop.0.2\n"
+                          "loop.0.2:\n"
+                          "  br i1 undef, label %loop.0.2, label %loop.0\n"
+                          "loop.1:\n"
+                          "  br i1 undef, label %loop.1.0, label %end\n"
+                          "loop.1.0:\n"
+                          "  br i1 undef, label %loop.1.0, label %loop.1.1\n"
+                          "loop.1.1:\n"
+                          "  br i1 undef, label %loop.1.1, label %loop.1.2\n"
+                          "loop.1.2:\n"
+                          "  br i1 undef, label %loop.1.2, label %loop.1\n"
+                          "end:\n"
+                          "  ret void\n"
+                          "}\n";
+  // Parse the module.
+  LLVMContext Context;
+  std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleStr);
+  Function &F = *M->begin();
+
+  DominatorTree DT(F);
+  LoopInfo LI;
+  LI.analyze(DT);
+
+  Function::iterator I = F.begin();
+  ASSERT_EQ("entry", I->getName());
+  ++I;
+  Loop &L_0 = *LI.getLoopFor(&*I++);
+  ASSERT_EQ("loop.0", L_0.getHeader()->getName());
+  Loop &L_0_0 = *LI.getLoopFor(&*I++);
+  ASSERT_EQ("loop.0.0", L_0_0.getHeader()->getName());
+  Loop &L_0_1 = *LI.getLoopFor(&*I++);
+  ASSERT_EQ("loop.0.1", L_0_1.getHeader()->getName());
+  Loop &L_0_2 = *LI.getLoopFor(&*I++);
+  ASSERT_EQ("loop.0.2", L_0_2.getHeader()->getName());
+  Loop &L_1 = *LI.getLoopFor(&*I++);
+  ASSERT_EQ("loop.1", L_1.getHeader()->getName());
+  Loop &L_1_0 = *LI.getLoopFor(&*I++);
+  ASSERT_EQ("loop.1.0", L_1_0.getHeader()->getName());
+  Loop &L_1_1 = *LI.getLoopFor(&*I++);
+  ASSERT_EQ("loop.1.1", L_1_1.getHeader()->getName());
+  Loop &L_1_2 = *LI.getLoopFor(&*I++);
+  ASSERT_EQ("loop.1.2", L_1_2.getHeader()->getName());
+
+  auto Preorder = LI.getLoopsInPreorder();
+  ASSERT_EQ(8u, Preorder.size());
+  EXPECT_EQ(&L_0, Preorder[0]);
+  EXPECT_EQ(&L_0_0, Preorder[1]);
+  EXPECT_EQ(&L_0_1, Preorder[2]);
+  EXPECT_EQ(&L_0_2, Preorder[3]);
+  EXPECT_EQ(&L_1, Preorder[4]);
+  EXPECT_EQ(&L_1_0, Preorder[5]);
+  EXPECT_EQ(&L_1_1, Preorder[6]);
+  EXPECT_EQ(&L_1_2, Preorder[7]);
+
+  auto ReverseSiblingPreorder = LI.getLoopsInReverseSiblingPreorder();
+  ASSERT_EQ(8u, ReverseSiblingPreorder.size());
+  EXPECT_EQ(&L_1, ReverseSiblingPreorder[0]);
+  EXPECT_EQ(&L_1_2, ReverseSiblingPreorder[1]);
+  EXPECT_EQ(&L_1_1, ReverseSiblingPreorder[2]);
+  EXPECT_EQ(&L_1_0, ReverseSiblingPreorder[3]);
+  EXPECT_EQ(&L_0, ReverseSiblingPreorder[4]);
+  EXPECT_EQ(&L_0_2, ReverseSiblingPreorder[5]);
+  EXPECT_EQ(&L_0_1, ReverseSiblingPreorder[6]);
+  EXPECT_EQ(&L_0_0, ReverseSiblingPreorder[7]);
+}