[turbofan] Add NodeMarker and use it in the GraphReducer.
authorBen L. Titzer <titzer@chromium.org>
Fri, 28 Nov 2014 13:04:49 +0000 (14:04 +0100)
committerBen L. Titzer <titzer@chromium.org>
Fri, 28 Nov 2014 13:04:59 +0000 (13:04 +0000)
R=mstarzinger@chromium.org
BUG=

Review URL: https://codereview.chromium.org/768763002

Cr-Commit-Position: refs/heads/master@{#25567}

src/compiler/graph-reducer.cc
src/compiler/graph-reducer.h
src/compiler/graph.cc
src/compiler/graph.h
src/compiler/node.h

index 26163bf..1f56b30 100644 (file)
@@ -22,10 +22,10 @@ enum class GraphReducer::State : uint8_t {
 
 GraphReducer::GraphReducer(Graph* graph, Zone* zone)
     : graph_(graph),
+      state_(graph, 4),
       reducers_(zone),
       revisit_(zone),
-      stack_(zone),
-      state_(zone) {}
+      stack_(zone) {}
 
 
 void GraphReducer::AddReducer(Reducer* reducer) {
@@ -36,12 +36,8 @@ void GraphReducer::AddReducer(Reducer* reducer) {
 void GraphReducer::ReduceNode(Node* node) {
   DCHECK(stack_.empty());
   DCHECK(revisit_.empty());
-  std::fill(state_.begin(), state_.end(), State::kUnvisited);
   Push(node);
   for (;;) {
-    DCHECK(!stack_.empty() ||
-           std::find(state_.begin(), state_.end(), State::kOnStack) ==
-               state_.end());
     if (!stack_.empty()) {
       // Process the node on the top of the stack, potentially pushing more or
       // popping the node off the stack.
@@ -50,7 +46,7 @@ void GraphReducer::ReduceNode(Node* node) {
       // If the stack becomes empty, revisit any nodes in the revisit queue.
       Node* const node = revisit_.top();
       revisit_.pop();
-      if (state_[node->id()] == State::kRevisit) {
+      if (state_.Get(node) == State::kRevisit) {
         // state can change while in queue.
         Push(node);
       }
@@ -58,8 +54,6 @@ void GraphReducer::ReduceNode(Node* node) {
       break;
     }
   }
-  DCHECK(std::find(state_.begin(), state_.end(), State::kOnStack) ==
-         state_.end());
   DCHECK(revisit_.empty());
   DCHECK(stack_.empty());
 }
@@ -101,7 +95,7 @@ Reduction GraphReducer::Reduce(Node* const node) {
 void GraphReducer::ReduceTop() {
   NodeState& entry = stack_.top();
   Node* node = entry.node;
-  DCHECK(state_[node->id()] == State::kOnStack);
+  DCHECK(state_.Get(node) == State::kOnStack);
 
   if (node->IsDead()) return Pop();  // Node was killed while on stack.
 
@@ -164,34 +158,29 @@ void GraphReducer::ReduceTop() {
 
 
 void GraphReducer::Pop() {
-  Node* const node = stack_.top().node;
-  state_[node->id()] = State::kVisited;
+  Node* node = stack_.top().node;
+  state_.Set(node, State::kVisited);
   stack_.pop();
 }
 
 
 void GraphReducer::Push(Node* const node) {
-  size_t const id = static_cast<size_t>(node->id());
-  if (id >= state_.size()) state_.resize(id + 1);
-  DCHECK(id < state_.size());
-  DCHECK(state_[id] != State::kOnStack);
-  state_[id] = State::kOnStack;
+  DCHECK(state_.Get(node) != State::kOnStack);
+  state_.Set(node, State::kOnStack);
   stack_.push({node, 0});
 }
 
 
-bool GraphReducer::Recurse(Node* const node) {
-  size_t const id = static_cast<size_t>(node->id());
-  if (id < state_.size() && state_[id] > State::kRevisit) return false;
+bool GraphReducer::Recurse(Node* node) {
+  if (state_.Get(node) > State::kRevisit) return false;
   Push(node);
   return true;
 }
 
 
-void GraphReducer::Revisit(Node* const node) {
-  size_t const id = static_cast<size_t>(node->id());
-  if (id < state_.size() && state_[id] == State::kVisited) {
-    state_[id] = State::kRevisit;
+void GraphReducer::Revisit(Node* node) {
+  if (state_.Get(node) == State::kVisited) {
+    state_.Set(node, State::kRevisit);
     revisit_.push(node);
   }
 }
index f07fb2b..09a650c 100644 (file)
@@ -5,17 +5,13 @@
 #ifndef V8_COMPILER_GRAPH_REDUCER_H_
 #define V8_COMPILER_GRAPH_REDUCER_H_
 
+#include "src/compiler/graph.h"
 #include "src/zone-containers.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-// Forward declarations.
-class Graph;
-class Node;
-
-
 // Represents the result of trying to reduce a node in the graph.
 class Reduction FINAL {
  public:
@@ -80,17 +76,17 @@ class GraphReducer FINAL {
 
   // Node stack operations.
   void Pop();
-  void Push(Node* const);
+  void Push(Node* node);
 
   // Revisit queue operations.
-  bool Recurse(Node* const);
-  void Revisit(Node* const);
+  bool Recurse(Node* node);
+  void Revisit(Node* node);
 
   Graph* graph_;
+  NodeMarker<State> state_;
   ZoneVector<Reducer*> reducers_;
   ZoneStack<Node*> revisit_;
   ZoneStack<NodeState> stack_;
-  ZoneDeque<State> state_;
 
   DISALLOW_COPY_AND_ASSIGN(GraphReducer);
 };
index 7e320fe..3c6d5a4 100644 (file)
@@ -19,7 +19,8 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
-Graph::Graph(Zone* zone) : GenericGraph<Node>(zone), decorators_(zone) {}
+Graph::Graph(Zone* zone)
+    : GenericGraph<Node>(zone), mark_max_(0), decorators_(zone) {}
 
 
 void Graph::Decorate(Node* node) {
index 5cb7702..71fa3e7 100644 (file)
@@ -19,7 +19,6 @@ namespace compiler {
 
 class GraphDecorator;
 
-
 class Graph : public GenericGraph<Node> {
  public:
   explicit Graph(Zone* zone);
@@ -78,10 +77,50 @@ class Graph : public GenericGraph<Node> {
   }
 
  private:
+  template <typename State>
+  friend class NodeMarker;
+
+  Mark mark_max_;
   ZoneVector<GraphDecorator*> decorators_;
 };
 
 
+// A NodeMarker uses monotonically increasing marks to assign local "states"
+// to nodes. Only one NodeMarker per graph is valid at a given time.
+template <typename State>
+class NodeMarker BASE_EMBEDDED {
+ public:
+  NodeMarker(Graph* graph, uint32_t num_states)
+      : mark_min_(graph->mark_max_), mark_max_(graph->mark_max_ += num_states) {
+    DCHECK(num_states > 0);         // user error!
+    DCHECK(mark_max_ > mark_min_);  // check for wraparound.
+  }
+
+  State Get(Node* node) {
+    Mark mark = node->mark();
+    if (mark < mark_min_) {
+      mark = mark_min_;
+      node->set_mark(mark_min_);
+    }
+    DCHECK_LT(mark, mark_max_);
+    return static_cast<State>(mark - mark_min_);
+  }
+
+  void Set(Node* node, State state) {
+    Mark local = static_cast<Mark>(state);
+    DCHECK(local < (mark_max_ - mark_min_));
+    DCHECK_LT(node->mark(), mark_max_);
+    node->set_mark(local + mark_min_);
+  }
+
+ private:
+  Mark mark_min_;
+  Mark mark_max_;
+};
+
+
+// A graph decorator can be used to add behavior to the creation of nodes
+// in a graph.
 class GraphDecorator : public ZoneObject {
  public:
   virtual ~GraphDecorator() {}
index 8a442ce..93dc78a 100644 (file)
@@ -21,6 +21,11 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+// Marks are used during traversal of the graph to distinguish states of nodes.
+// Each node has a mark which is a monotonically increasing integer, and a
+// {NodeMarker} has a range of values that indicate states of a node.
+typedef uint32_t Mark;
+
 class NodeData {
  public:
   const Operator* op() const { return op_; }
@@ -34,11 +39,19 @@ class NodeData {
  protected:
   const Operator* op_;
   Bounds bounds_;
+  Mark mark_;
   explicit NodeData(Zone* zone) {}
 
   friend class NodeProperties;
+  template <typename State>
+  friend class NodeMarker;
+
   Bounds bounds() { return bounds_; }
   void set_bounds(Bounds b) { bounds_ = b; }
+
+  // Only NodeMarkers should manipulate the marks on nodes.
+  Mark mark() { return mark_; }
+  void set_mark(Mark mark) { mark_ = mark; }
 };
 
 // A Node is the basic primitive of an IR graph. In addition to the members
@@ -51,7 +64,10 @@ class Node FINAL : public GenericNode<NodeData, Node> {
   Node(GenericGraphBase* graph, int input_count, int reserve_input_count)
       : GenericNode<NodeData, Node>(graph, input_count, reserve_input_count) {}
 
-  void Initialize(const Operator* op) { set_op(op); }
+  void Initialize(const Operator* op) {
+    set_op(op);
+    set_mark(0);
+  }
 
   bool IsDead() const { return InputCount() > 0 && InputAt(0) == NULL; }
   void Kill();