Skip to content

Commit

Permalink
[LoopInfo] Add helper methods to compute two useful orderings of the
Browse files Browse the repository at this point in the history
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

llvm-svn: 292569
  • Loading branch information
chandlerc committed Jan 20, 2017
1 parent efa3185 commit f002264
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 18 deletions.
17 changes: 17 additions & 0 deletions llvm/include/llvm/Analysis/LoopInfo.h
Expand Up @@ -570,6 +570,23 @@ class LoopInfoBase {
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); }
Expand Down
49 changes: 49 additions & 0 deletions llvm/include/llvm/Analysis/LoopInfoImpl.h
Expand Up @@ -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 {
Expand Down
22 changes: 4 additions & 18 deletions llvm/lib/Analysis/LoopAnalysisManager.cpp
Expand Up @@ -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
Expand Down
75 changes: 75 additions & 0 deletions llvm/unittests/Analysis/LoopInfoTest.cpp
Expand Up @@ -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]);
}

0 comments on commit f002264

Please sign in to comment.