[llvm] r299660 - [ADT] Add a generic breadth-first-search graph iterator.
Davide Italiano via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 6 10:03:05 PDT 2017
Author: davide
Date: Thu Apr 6 12:03:04 2017
New Revision: 299660
URL: http://llvm.org/viewvc/llvm-project?rev=299660&view=rev
Log:
[ADT] Add a generic breadth-first-search graph iterator.
This will be used in LCSSA to speed up the canonicalization.
Differential Revision: https://reviews.llvm.org/D31694
Added:
llvm/trunk/include/llvm/ADT/BreadthFirstIterator.h
llvm/trunk/unittests/ADT/BreadthFirstIteratorTest.cpp
Modified:
llvm/trunk/unittests/ADT/CMakeLists.txt
Added: llvm/trunk/include/llvm/ADT/BreadthFirstIterator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/BreadthFirstIterator.h?rev=299660&view=auto
==============================================================================
--- llvm/trunk/include/llvm/ADT/BreadthFirstIterator.h (added)
+++ llvm/trunk/include/llvm/ADT/BreadthFirstIterator.h Thu Apr 6 12:03:04 2017
@@ -0,0 +1,165 @@
+//===- llvm/ADT/BreadthFirstIterator.h - Breadth First iterator -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file builds on the ADT/GraphTraits.h file to build a generic breadth
+// first graph iterator. This file exposes the following functions/types:
+//
+// bf_begin/bf_end/bf_iterator
+// * Normal breadth-first iteration - visit a graph level-by-level.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_BREADTHFIRSTITERATOR_H
+#define LLVM_ADT_BREADTHFIRSTITERATOR_H
+
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/iterator_range.h"
+#include <iterator>
+#include <queue>
+#include <set>
+#include <utility>
+
+namespace llvm {
+
+// bf_iterator_storage - A private class which is used to figure out where to
+// store the visited set. We only provide a non-external variant for now.
+template <class SetType> class bf_iterator_storage {
+public:
+ SetType Visited;
+};
+
+// The visited state for the iteration is a simple set.
+template <typename NodeRef, unsigned SmallSize = 8>
+using bf_iterator_default_set = SmallPtrSet<NodeRef, SmallSize>;
+
+// Generic Breadth first search iterator.
+template <class GraphT,
+ class SetType =
+ bf_iterator_default_set<typename GraphTraits<GraphT>::NodeRef>,
+ class GT = GraphTraits<GraphT>>
+class bf_iterator
+ : public std::iterator<std::forward_iterator_tag, typename GT::NodeRef>,
+ public bf_iterator_storage<SetType> {
+ typedef std::iterator<std::forward_iterator_tag, typename GT::NodeRef> super;
+
+ typedef typename GT::NodeRef NodeRef;
+ typedef typename GT::ChildIteratorType ChildItTy;
+
+ // First element is the node reference, second is the next child to visit.
+ typedef std::pair<NodeRef, Optional<ChildItTy>> QueueElement;
+
+ // Visit queue - used to maintain BFS ordering.
+ // Optional<> because we need markers for levels.
+ std::queue<Optional<QueueElement>> VisitQueue;
+
+ // Current level.
+ unsigned Level;
+
+private:
+ inline bf_iterator(NodeRef Node) {
+ this->Visited.insert(Node);
+ Level = 0;
+
+ // Also, insert a dummy node as marker.
+ VisitQueue.push(QueueElement(Node, None));
+ VisitQueue.push(None);
+ }
+
+ inline bf_iterator() = default;
+
+ inline void toNext() {
+ Optional<QueueElement> Head = VisitQueue.front();
+ QueueElement H = Head.getValue();
+ NodeRef Node = H.first;
+ Optional<ChildItTy> &ChildIt = H.second;
+
+ if (!ChildIt)
+ ChildIt.emplace(GT::child_begin(Node));
+ while (*ChildIt != GT::child_end(Node)) {
+ NodeRef Next = *(*ChildIt)++;
+
+ // Already visited?
+ if (this->Visited.insert(Next).second)
+ VisitQueue.push(QueueElement(Next, None));
+ }
+ VisitQueue.pop();
+
+ // Go to the next element skipping markers if needed.
+ if (!VisitQueue.empty()) {
+ Head = VisitQueue.front();
+ if (Head != None)
+ return;
+ Level += 1;
+ VisitQueue.pop();
+
+ // Don't push another marker if this is the last
+ // element.
+ if (!VisitQueue.empty())
+ VisitQueue.push(None);
+ }
+ }
+
+public:
+ typedef typename super::pointer pointer;
+
+ // Provide static begin and end methods as our public "constructors"
+ static bf_iterator begin(const GraphT &G) {
+ return bf_iterator(GT::getEntryNode(G));
+ }
+
+ static bf_iterator end(const GraphT &G) { return bf_iterator(); }
+
+ bool operator==(const bf_iterator &RHS) const {
+ assert(VisitQueue.size() == 0);
+ return VisitQueue == RHS.VisitQueue;
+ }
+
+ bool operator!=(const bf_iterator &RHS) const { return !(*this == RHS); }
+
+ const NodeRef &operator*() const { return VisitQueue.front()->first; }
+
+ // This is a nonstandard operator-> that dereferenfces the pointer an extra
+ // time so that you can actually call methods on the node, because the
+ // contained type is a pointer.
+ NodeRef operator->() const { return **this; }
+
+ bf_iterator &operator++() { // Pre-increment
+ toNext();
+ return *this;
+ }
+
+ bf_iterator operator++(int) { // Post-increment
+ bf_iterator ItCopy = *this;
+ ++*this;
+ return ItCopy;
+ }
+
+ unsigned getLevel() const { return Level; }
+};
+
+// Provide global constructors that automatically figure out correct types.
+template <class T> bf_iterator<T> bf_begin(const T &G) {
+ return bf_iterator<T>::begin(G);
+}
+
+template <class T> bf_iterator<T> bf_end(const T &G) {
+ return bf_iterator<T>::end(G);
+}
+
+// Provide an accessor method to use them in range-based patterns.
+template <class T> iterator_range<bf_iterator<T>> breadth_first(const T &G) {
+ return make_range(bf_begin(G), bf_end(G));
+}
+
+} // end namespace llvm
+
+#endif // LLVM_ADT_BREADTHFIRSTITERATOR_H
Added: llvm/trunk/unittests/ADT/BreadthFirstIteratorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/BreadthFirstIteratorTest.cpp?rev=299660&view=auto
==============================================================================
--- llvm/trunk/unittests/ADT/BreadthFirstIteratorTest.cpp (added)
+++ llvm/trunk/unittests/ADT/BreadthFirstIteratorTest.cpp Thu Apr 6 12:03:04 2017
@@ -0,0 +1,74 @@
+//=== llvm/unittest/ADT/BreadthFirstIteratorTest.cpp - BFS iterator tests -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/BreadthFirstIterator.h"
+#include "TestGraph.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace llvm {
+
+TEST(BreadthFristIteratorTest, Basic) {
+ typedef bf_iterator<Graph<4>> BFIter;
+
+ Graph<4> G;
+ G.AddEdge(0, 1);
+ G.AddEdge(0, 2);
+ G.AddEdge(1, 3);
+
+ auto It = BFIter::begin(G);
+ auto End = BFIter::end(G);
+ EXPECT_EQ(It.getLevel(), 0U);
+ EXPECT_EQ(*It, G.AccessNode(0));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 1U);
+ EXPECT_EQ(*It, G.AccessNode(1));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 1U);
+ EXPECT_EQ(*It, G.AccessNode(2));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 2U);
+ EXPECT_EQ(*It, G.AccessNode(3));
+ ++It;
+ EXPECT_EQ(It, End);
+}
+
+TEST(BreadthFristIteratorTest, Cycle) {
+ typedef bf_iterator<Graph<4>> BFIter;
+
+ Graph<4> G;
+ G.AddEdge(0, 1);
+ G.AddEdge(1, 0);
+ G.AddEdge(1, 2);
+ G.AddEdge(2, 1);
+ G.AddEdge(2, 1);
+ G.AddEdge(2, 3);
+ G.AddEdge(3, 2);
+ G.AddEdge(3, 1);
+ G.AddEdge(3, 0);
+
+ auto It = BFIter::begin(G);
+ auto End = BFIter::end(G);
+ EXPECT_EQ(It.getLevel(), 0U);
+ EXPECT_EQ(*It, G.AccessNode(0));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 1U);
+ EXPECT_EQ(*It, G.AccessNode(1));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 2U);
+ EXPECT_EQ(*It, G.AccessNode(2));
+ ++It;
+ EXPECT_EQ(It.getLevel(), 3U);
+ EXPECT_EQ(*It, G.AccessNode(3));
+ ++It;
+ EXPECT_EQ(It, End);
+}
+
+} // end namespace llvm
Modified: llvm/trunk/unittests/ADT/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/CMakeLists.txt?rev=299660&r1=299659&r2=299660&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/CMakeLists.txt (original)
+++ llvm/trunk/unittests/ADT/CMakeLists.txt Thu Apr 6 12:03:04 2017
@@ -9,6 +9,7 @@ set(ADTSources
ArrayRefTest.cpp
BitmaskEnumTest.cpp
BitVectorTest.cpp
+ BreadthFirstIteratorTest.cpp
BumpPtrListTest.cpp
DAGDeltaAlgorithmTest.cpp
DeltaAlgorithmTest.cpp
More information about the llvm-commits
mailing list