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) {
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.
// 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);
}
break;
}
}
- DCHECK(std::find(state_.begin(), state_.end(), State::kOnStack) ==
- state_.end());
DCHECK(revisit_.empty());
DCHECK(stack_.empty());
}
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.
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);
}
}
#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:
// 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);
};
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) {
class GraphDecorator;
-
class Graph : public GenericGraph<Node> {
public:
explicit Graph(Zone* zone);
}
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() {}
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_; }
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
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();