[llvm] r292569 - [LoopInfo] Add helper methods to compute two useful orderings of the

Chandler Carruth via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 19 18:41:21 PST 2017


Author: chandlerc
Date: Thu Jan 19 20:41:20 2017
New Revision: 292569

URL: http://llvm.org/viewvc/llvm-project?rev=292569&view=rev
Log:
[LoopInfo] Add helper methods to compute two useful orderings of the
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

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

Modified: llvm/trunk/include/llvm/Analysis/LoopInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LoopInfo.h?rev=292569&r1=292568&r2=292569&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/LoopInfo.h (original)
+++ llvm/trunk/include/llvm/Analysis/LoopInfo.h Thu Jan 19 20:41:20 2017
@@ -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); }

Modified: llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h?rev=292569&r1=292568&r2=292569&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h (original)
+++ llvm/trunk/include/llvm/Analysis/LoopInfoImpl.h Thu Jan 19 20:41:20 2017
@@ -507,6 +507,55 @@ analyze(const DominatorTreeBase<BlockT>
   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 {

Modified: llvm/trunk/lib/Analysis/LoopAnalysisManager.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopAnalysisManager.cpp?rev=292569&r1=292568&r2=292569&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/LoopAnalysisManager.cpp (original)
+++ llvm/trunk/lib/Analysis/LoopAnalysisManager.cpp Thu Jan 19 20:41:20 2017
@@ -31,24 +31,10 @@ bool LoopAnalysisManagerFunctionProxy::R
     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

Modified: llvm/trunk/unittests/Analysis/LoopInfoTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Analysis/LoopInfoTest.cpp?rev=292569&r1=292568&r2=292569&view=diff
==============================================================================
--- llvm/trunk/unittests/Analysis/LoopInfoTest.cpp (original)
+++ llvm/trunk/unittests/Analysis/LoopInfoTest.cpp Thu Jan 19 20:41:20 2017
@@ -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]);
+}




More information about the llvm-commits mailing list