From: Ben L. Titzer Date: Fri, 28 Nov 2014 13:04:49 +0000 (+0100) Subject: [turbofan] Add NodeMarker and use it in the GraphReducer. X-Git-Tag: upstream/4.7.83~5473 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6f60c0d3b83efe05cff992c460f4f8df325e0204;p=platform%2Fupstream%2Fv8.git [turbofan] Add NodeMarker and use it in the GraphReducer. R=mstarzinger@chromium.org BUG= Review URL: https://codereview.chromium.org/768763002 Cr-Commit-Position: refs/heads/master@{#25567} --- diff --git a/src/compiler/graph-reducer.cc b/src/compiler/graph-reducer.cc index 26163bf..1f56b30 100644 --- a/src/compiler/graph-reducer.cc +++ b/src/compiler/graph-reducer.cc @@ -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(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(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(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); } } diff --git a/src/compiler/graph-reducer.h b/src/compiler/graph-reducer.h index f07fb2b..09a650c 100644 --- a/src/compiler/graph-reducer.h +++ b/src/compiler/graph-reducer.h @@ -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_; ZoneVector reducers_; ZoneStack revisit_; ZoneStack stack_; - ZoneDeque state_; DISALLOW_COPY_AND_ASSIGN(GraphReducer); }; diff --git a/src/compiler/graph.cc b/src/compiler/graph.cc index 7e320fe..3c6d5a4 100644 --- a/src/compiler/graph.cc +++ b/src/compiler/graph.cc @@ -19,7 +19,8 @@ namespace v8 { namespace internal { namespace compiler { -Graph::Graph(Zone* zone) : GenericGraph(zone), decorators_(zone) {} +Graph::Graph(Zone* zone) + : GenericGraph(zone), mark_max_(0), decorators_(zone) {} void Graph::Decorate(Node* node) { diff --git a/src/compiler/graph.h b/src/compiler/graph.h index 5cb7702..71fa3e7 100644 --- a/src/compiler/graph.h +++ b/src/compiler/graph.h @@ -19,7 +19,6 @@ namespace compiler { class GraphDecorator; - class Graph : public GenericGraph { public: explicit Graph(Zone* zone); @@ -78,10 +77,50 @@ class Graph : public GenericGraph { } private: + template + friend class NodeMarker; + + Mark mark_max_; ZoneVector 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 +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(mark - mark_min_); + } + + void Set(Node* node, State state) { + Mark local = static_cast(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() {} diff --git a/src/compiler/node.h b/src/compiler/node.h index 8a442ce..93dc78a 100644 --- a/src/compiler/node.h +++ b/src/compiler/node.h @@ -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 + 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 { Node(GenericGraphBase* graph, int input_count, int reserve_input_count) : GenericNode(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();