Commit 31c64277 authored by titzer's avatar titzer Committed by Commit bot

[turbofan] NodeMarker in ControlReducer.

R=mstarzinger@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#25583}
parent 50c4d882
...@@ -15,9 +15,32 @@ namespace internal { ...@@ -15,9 +15,32 @@ namespace internal {
namespace compiler { namespace compiler {
enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 }; enum VisitState { kUnvisited = 0, kOnStack = 1, kRevisit = 2, kVisited = 3 };
enum Reachability { kFromStart = 8 };
enum Decision { kFalse, kUnknown, kTrue }; enum Decision { kFalse, kUnknown, kTrue };
class ReachabilityMarker : public NodeMarker<uint8_t> {
public:
explicit ReachabilityMarker(Graph* graph) : NodeMarker<uint8_t>(graph, 8) {}
bool SetReachableFromEnd(Node* node) {
uint8_t before = Get(node);
Set(node, before | kFromEnd);
return before & kFromEnd;
}
bool IsReachableFromEnd(Node* node) { return Get(node) & kFromEnd; }
bool SetReachableFromStart(Node* node) {
uint8_t before = Get(node);
Set(node, before | kFromStart);
return before & kFromStart;
}
bool IsReachableFromStart(Node* node) { return Get(node) & kFromStart; }
void Push(Node* node) { Set(node, Get(node) | kFwStack); }
void Pop(Node* node) { Set(node, Get(node) & ~kFwStack); }
bool IsOnStack(Node* node) { return Get(node) & kFwStack; }
private:
enum Bit { kFromEnd = 1, kFromStart = 2, kFwStack = 4 };
};
#define TRACE(x) \ #define TRACE(x) \
if (FLAG_trace_turbo_reduction) PrintF x if (FLAG_trace_turbo_reduction) PrintF x
...@@ -72,15 +95,15 @@ class ControlReducerImpl { ...@@ -72,15 +95,15 @@ class ControlReducerImpl {
// we have to be careful about proper loop detection during reduction. // we have to be careful about proper loop detection during reduction.
// Gather all nodes backwards-reachable from end (through inputs). // Gather all nodes backwards-reachable from end (through inputs).
state_.assign(graph()->NodeCount(), kUnvisited); ReachabilityMarker marked(graph());
NodeVector nodes(zone_); NodeVector nodes(zone_);
AddNodesReachableFromEnd(nodes); AddNodesReachableFromEnd(marked, nodes);
// Walk forward through control nodes, looking for back edges to nodes // Walk forward through control nodes, looking for back edges to nodes
// that are not connected to end. Those are non-terminating loops (NTLs). // that are not connected to end. Those are non-terminating loops (NTLs).
Node* start = graph()->start(); Node* start = graph()->start();
ZoneVector<byte> fw_reachability(graph()->NodeCount(), 0, zone_); marked.Push(start);
fw_reachability[start->id()] = kFromStart | kOnStack; marked.SetReachableFromStart(start);
// We use a stack of (Node, UseIter) pairs to avoid O(n^2) traversal. // We use a stack of (Node, UseIter) pairs to avoid O(n^2) traversal.
typedef std::pair<Node*, UseIter> FwIter; typedef std::pair<Node*, UseIter> FwIter;
...@@ -93,20 +116,23 @@ class ControlReducerImpl { ...@@ -93,20 +116,23 @@ class ControlReducerImpl {
bool pop = true; bool pop = true;
while (fw_stack.back().second != node->uses().end()) { while (fw_stack.back().second != node->uses().end()) {
Node* succ = *(fw_stack.back().second); Node* succ = *(fw_stack.back().second);
byte reach = fw_reachability[succ->id()]; if (marked.IsOnStack(succ) && !marked.IsReachableFromEnd(succ)) {
if ((reach & kOnStack) != 0 && state_[succ->id()] != kVisited) {
// {succ} is on stack and not reachable from end. // {succ} is on stack and not reachable from end.
ConnectNTL(nodes, succ); Node* added = ConnectNTL(succ);
fw_reachability.resize(graph()->NodeCount(), 0); nodes.push_back(added);
marked.SetReachableFromEnd(added);
AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1);
// The use list of {succ} might have changed. // The use list of {succ} might have changed.
fw_stack[fw_stack.size() - 1] = FwIter(succ, succ->uses().begin()); fw_stack[fw_stack.size() - 1] = FwIter(succ, succ->uses().begin());
pop = false; // restart traversing successors of this node. pop = false; // restart traversing successors of this node.
break; break;
} }
if ((reach & kFromStart) == 0 && if (IrOpcode::IsControlOpcode(succ->opcode()) &&
IrOpcode::IsControlOpcode(succ->opcode())) { !marked.IsReachableFromStart(succ)) {
// {succ} is a control node and not yet reached from start. // {succ} is a control node and not yet reached from start.
fw_reachability[succ->id()] |= kFromStart | kOnStack; marked.Push(succ);
marked.SetReachableFromStart(succ);
fw_stack.push_back(FwIter(succ, succ->uses().begin())); fw_stack.push_back(FwIter(succ, succ->uses().begin()));
pop = false; // "recurse" into successor control node. pop = false; // "recurse" into successor control node.
break; break;
...@@ -114,21 +140,20 @@ class ControlReducerImpl { ...@@ -114,21 +140,20 @@ class ControlReducerImpl {
++fw_stack.back().second; ++fw_stack.back().second;
} }
if (pop) { if (pop) {
fw_reachability[node->id()] &= ~kOnStack; marked.Pop(node);
fw_stack.pop_back(); fw_stack.pop_back();
} }
} }
// Trim references from dead nodes to live nodes first. // Trim references from dead nodes to live nodes first.
jsgraph_->GetCachedNodes(&nodes); jsgraph_->GetCachedNodes(&nodes);
TrimNodes(nodes); TrimNodes(marked, nodes);
// Any control nodes not reachable from start are dead, even loops. // Any control nodes not reachable from start are dead, even loops.
for (size_t i = 0; i < nodes.size(); i++) { for (size_t i = 0; i < nodes.size(); i++) {
Node* node = nodes[i]; Node* node = nodes[i];
byte reach = fw_reachability[node->id()]; if (IrOpcode::IsControlOpcode(node->opcode()) &&
if ((reach & kFromStart) == 0 && !marked.IsReachableFromStart(node)) {
IrOpcode::IsControlOpcode(node->opcode())) {
ReplaceNode(node, dead()); // uses will be added to revisit queue. ReplaceNode(node, dead()); // uses will be added to revisit queue.
} }
} }
...@@ -136,7 +161,7 @@ class ControlReducerImpl { ...@@ -136,7 +161,7 @@ class ControlReducerImpl {
} }
// Connect {loop}, the header of a non-terminating loop, to the end node. // Connect {loop}, the header of a non-terminating loop, to the end node.
void ConnectNTL(NodeVector& nodes, Node* loop) { Node* ConnectNTL(Node* loop) {
TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic())); TRACE(("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic()));
if (loop->opcode() != IrOpcode::kTerminate) { if (loop->opcode() != IrOpcode::kTerminate) {
...@@ -173,27 +198,24 @@ class ControlReducerImpl { ...@@ -173,27 +198,24 @@ class ControlReducerImpl {
merge->AppendInput(graph()->zone(), loop); merge->AppendInput(graph()->zone(), loop);
merge->set_op(common_->Merge(merge->InputCount())); merge->set_op(common_->Merge(merge->InputCount()));
} }
nodes.push_back(to_add); return to_add;
state_.resize(graph()->NodeCount(), kUnvisited);
state_[to_add->id()] = kVisited;
AddBackwardsReachableNodes(nodes, nodes.size() - 1);
} }
void AddNodesReachableFromEnd(NodeVector& nodes) { void AddNodesReachableFromEnd(ReachabilityMarker& marked, NodeVector& nodes) {
Node* end = graph()->end(); Node* end = graph()->end();
state_[end->id()] = kVisited; marked.SetReachableFromEnd(end);
if (!end->IsDead()) { if (!end->IsDead()) {
nodes.push_back(end); nodes.push_back(end);
AddBackwardsReachableNodes(nodes, nodes.size() - 1); AddBackwardsReachableNodes(marked, nodes, nodes.size() - 1);
} }
} }
void AddBackwardsReachableNodes(NodeVector& nodes, size_t cursor) { void AddBackwardsReachableNodes(ReachabilityMarker& marked, NodeVector& nodes,
size_t cursor) {
while (cursor < nodes.size()) { while (cursor < nodes.size()) {
Node* node = nodes[cursor++]; Node* node = nodes[cursor++];
for (Node* const input : node->inputs()) { for (Node* const input : node->inputs()) {
if (state_[input->id()] != kVisited) { if (!marked.SetReachableFromEnd(input)) {
state_[input->id()] = kVisited;
nodes.push_back(input); nodes.push_back(input);
} }
} }
...@@ -202,22 +224,21 @@ class ControlReducerImpl { ...@@ -202,22 +224,21 @@ class ControlReducerImpl {
void Trim() { void Trim() {
// Gather all nodes backwards-reachable from end through inputs. // Gather all nodes backwards-reachable from end through inputs.
state_.assign(graph()->NodeCount(), kUnvisited); ReachabilityMarker marked(graph());
NodeVector nodes(zone_); NodeVector nodes(zone_);
AddNodesReachableFromEnd(nodes); AddNodesReachableFromEnd(marked, nodes);
// Process cached nodes in the JSGraph too. // Process cached nodes in the JSGraph too.
jsgraph_->GetCachedNodes(&nodes); jsgraph_->GetCachedNodes(&nodes);
TrimNodes(nodes); TrimNodes(marked, nodes);
} }
void TrimNodes(NodeVector& nodes) { void TrimNodes(ReachabilityMarker& marked, NodeVector& nodes) {
// Remove dead->live edges. // Remove dead->live edges.
for (size_t j = 0; j < nodes.size(); j++) { for (size_t j = 0; j < nodes.size(); j++) {
Node* node = nodes[j]; Node* node = nodes[j];
for (UseIter i = node->uses().begin(); i != node->uses().end();) { for (UseIter i = node->uses().begin(); i != node->uses().end();) {
size_t id = static_cast<size_t>((*i)->id()); if (!marked.IsReachableFromEnd(*i)) {
if (state_[id] != kVisited) {
TRACE(("DeadLink: #%d:%s(%d) -> #%d:%s\n", (*i)->id(), TRACE(("DeadLink: #%d:%s(%d) -> #%d:%s\n", (*i)->id(),
(*i)->op()->mnemonic(), i.index(), node->id(), (*i)->op()->mnemonic(), i.index(), node->id(),
node->op()->mnemonic())); node->op()->mnemonic()));
...@@ -235,8 +256,7 @@ class ControlReducerImpl { ...@@ -235,8 +256,7 @@ class ControlReducerImpl {
CHECK_NE(NULL, input); CHECK_NE(NULL, input);
} }
for (Node* const use : node->uses()) { for (Node* const use : node->uses()) {
size_t id = static_cast<size_t>(use->id()); CHECK(marked.IsReachableFromEnd(use));
CHECK_EQ(kVisited, state_[id]);
} }
} }
#endif #endif
...@@ -519,7 +539,6 @@ void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph, ...@@ -519,7 +539,6 @@ void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph,
CommonOperatorBuilder* common) { CommonOperatorBuilder* common) {
ControlReducerImpl impl(zone, jsgraph, common); ControlReducerImpl impl(zone, jsgraph, common);
impl.Reduce(); impl.Reduce();
impl.Trim();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment