Commit 01766cd8 authored by bgeron's avatar bgeron Committed by Commit bot

[turbolizer] Visualize also the dead nodes.

R=danno,jarin
BUG=

Review-Url: https://codereview.chromium.org/2226293002
Cr-Commit-Position: refs/heads/master@{#38502}
parent 9243d5e3
......@@ -10,25 +10,33 @@ namespace v8 {
namespace internal {
namespace compiler {
AllNodes::AllNodes(Zone* local_zone, const Graph* graph)
: live(local_zone), is_live(graph->NodeCount(), false, local_zone) {
AllNodes::AllNodes(Zone* local_zone, const Graph* graph, bool only_inputs)
: reachable(local_zone),
is_reachable_(graph->NodeCount(), false, local_zone),
only_inputs_(only_inputs) {
Node* end = graph->end();
is_live[end->id()] = true;
live.push_back(end);
// Find all live nodes reachable from end.
for (size_t i = 0; i < live.size(); i++) {
for (Node* const input : live[i]->inputs()) {
if (input == nullptr) {
// TODO(titzer): print a warning.
is_reachable_[end->id()] = true;
reachable.push_back(end);
// Find all nodes reachable from end.
for (size_t i = 0; i < reachable.size(); i++) {
for (Node* input : reachable[i]->inputs()) {
if (input == nullptr || input->id() >= graph->NodeCount()) {
continue;
}
if (input->id() >= graph->NodeCount()) {
// TODO(titzer): print a warning.
if (!is_reachable_[input->id()]) {
is_reachable_[input->id()] = true;
reachable.push_back(input);
}
}
if (!only_inputs) {
for (Node* use : reachable[i]->uses()) {
if (use == nullptr || use->id() >= graph->NodeCount()) {
continue;
}
if (!is_live[input->id()]) {
is_live[input->id()] = true;
live.push_back(input);
if (!is_reachable_[use->id()]) {
is_reachable_[use->id()] = true;
reachable.push_back(use);
}
}
}
}
......
......@@ -16,19 +16,27 @@ namespace compiler {
// from end.
class AllNodes {
public:
// Constructor. Traverses the graph and builds the {live} sets.
AllNodes(Zone* local_zone, const Graph* graph);
// Constructor. Traverses the graph and builds the {reachable} sets. When
// {only_inputs} is true, find the nodes reachable through input edges;
// these are all live nodes.
AllNodes(Zone* local_zone, const Graph* graph, bool only_inputs = true);
bool IsLive(Node* node) {
CHECK(only_inputs_);
return IsReachable(node);
}
bool IsReachable(Node* node) {
if (!node) return false;
size_t id = node->id();
return id < is_live.size() && is_live[id];
return id < is_reachable_.size() && is_reachable_[id];
}
NodeVector live; // Nodes reachable from end.
NodeVector reachable; // Nodes reachable from end.
private:
BoolVector is_live;
BoolVector is_reachable_;
const bool only_inputs_;
};
} // namespace compiler
......
......@@ -331,7 +331,7 @@ Node* EscapeAnalysisReducer::ReduceStateValueInput(Node* node, int node_index,
void EscapeAnalysisReducer::VerifyReplacement() const {
#ifdef DEBUG
AllNodes all(zone(), jsgraph()->graph());
for (Node* node : all.live) {
for (Node* node : all.reachable) {
if (node->opcode() == IrOpcode::kAllocate) {
CHECK(!escape_analysis_->IsVirtual(node));
}
......
......@@ -24,7 +24,7 @@ void GraphReplayPrinter::PrintReplay(Graph* graph) {
AllNodes nodes(&zone, graph);
// Allocate the nodes first.
for (Node* node : nodes.live) {
for (Node* node : nodes.reachable) {
PrintReplayOpCreator(node->op());
PrintF(" Node* n%d = graph()->NewNode(op", node->id());
for (int i = 0; i < node->InputCount(); ++i) {
......@@ -34,7 +34,7 @@ void GraphReplayPrinter::PrintReplay(Graph* graph) {
}
// Connect the nodes to their inputs.
for (Node* node : nodes.live) {
for (Node* node : nodes.reachable) {
for (int i = 0; i < node->InputCount(); i++) {
PrintF(" n%d->ReplaceInput(%d, n%d);\n", node->id(), i,
node->InputAt(i)->id());
......
......@@ -113,10 +113,14 @@ class JSONGraphNodeWriter {
public:
JSONGraphNodeWriter(std::ostream& os, Zone* zone, const Graph* graph,
const SourcePositionTable* positions)
: os_(os), all_(zone, graph), positions_(positions), first_node_(true) {}
: os_(os),
all_(zone, graph, false),
live_(zone, graph, true),
positions_(positions),
first_node_(true) {}
void Print() {
for (Node* const node : all_.live) PrintNode(node);
for (Node* const node : all_.reachable) PrintNode(node);
os_ << "\n";
}
......@@ -133,6 +137,7 @@ class JSONGraphNodeWriter {
os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << Escaped(label, "\"")
<< "\""
<< ",\"title\":\"" << Escaped(title, "\"") << "\""
<< ",\"live\": " << (live_.IsLive(node) ? "true" : "false")
<< ",\"properties\":\"" << Escaped(properties, "\"") << "\"";
IrOpcode::Value opcode = node->opcode();
if (IrOpcode::IsPhiOpcode(opcode)) {
......@@ -173,6 +178,7 @@ class JSONGraphNodeWriter {
private:
std::ostream& os_;
AllNodes all_;
AllNodes live_;
const SourcePositionTable* positions_;
bool first_node_;
......@@ -183,10 +189,10 @@ class JSONGraphNodeWriter {
class JSONGraphEdgeWriter {
public:
JSONGraphEdgeWriter(std::ostream& os, Zone* zone, const Graph* graph)
: os_(os), all_(zone, graph), first_edge_(true) {}
: os_(os), all_(zone, graph, false), first_edge_(true) {}
void Print() {
for (Node* const node : all_.live) PrintEdges(node);
for (Node* const node : all_.reachable) PrintEdges(node);
os_ << "\n";
}
......
......@@ -84,8 +84,8 @@ static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common,
}
// Copy all nodes.
for (size_t i = 0; i < all.live.size(); i++) {
Node* orig = all.live[i];
for (size_t i = 0; i < all.reachable.size(); i++) {
Node* orig = all.reachable[i];
Node* copy = mapping->at(orig->id());
if (copy != sentinel) {
// Mapping already exists.
......@@ -113,7 +113,7 @@ static void PeelOuterLoopsForOsr(Graph* graph, CommonOperatorBuilder* common,
}
// Fix missing inputs.
for (Node* orig : all.live) {
for (Node* orig : all.reachable) {
Node* copy = mapping->at(orig->id());
for (int j = 0; j < copy->InputCount(); j++) {
if (copy->InputAt(j) == sentinel) {
......
......@@ -130,7 +130,7 @@ void StoreStoreElimination::Run() {
NodeVector eligible(temp_zone()); // loops over all nodes
AllNodes all(temp_zone(), jsgraph()->graph());
for (Node* node : all.live) {
for (Node* node : all.reachable) {
if (IsEligibleNode(node)) {
eligible.push_back(node);
}
......
......@@ -1266,10 +1266,10 @@ void Verifier::Run(Graph* graph, Typing typing, CheckInputs check_inputs) {
Zone zone(graph->zone()->allocator());
Visitor visitor(&zone, typing, check_inputs);
AllNodes all(&zone, graph);
for (Node* node : all.live) visitor.Check(node);
for (Node* node : all.reachable) visitor.Check(node);
// Check the uniqueness of projections.
for (Node* proj : all.live) {
for (Node* proj : all.reachable) {
if (proj->opcode() != IrOpcode::kProjection) continue;
Node* node = proj->InputAt(0);
for (Node* other : node->uses()) {
......
......@@ -120,10 +120,10 @@ class OsrDeconstructorTester : public HandleAndZoneScope {
CHECK(!nodes.IsLive(osr_normal_entry));
CHECK(!nodes.IsLive(osr_loop_entry));
// No dangling nodes should be left over.
for (Node* const node : nodes.live) {
for (Node* const node : nodes.reachable) {
for (Node* const use : node->uses()) {
CHECK(std::find(nodes.live.begin(), nodes.live.end(), use) !=
nodes.live.end());
CHECK(std::find(nodes.reachable.begin(), nodes.reachable.end(), use) !=
nodes.reachable.end());
}
}
}
......
......@@ -125,6 +125,7 @@ class GraphView extends View {
d3.select("#upload").on("click", partial(this.uploadAction, graph));
d3.select("#layout").on("click", partial(this.layoutAction, graph));
d3.select("#show-all").on("click", partial(this.showAllAction, graph));
d3.select("#hide-dead").on("click", partial(this.hideDeadAction, graph));
d3.select("#hide-unselected").on("click", partial(this.hideUnselectedAction, graph));
d3.select("#hide-selected").on("click", partial(this.hideSelectedAction, graph));
d3.select("#zoom-selection").on("click", partial(this.zoomSelectionAction, graph));
......@@ -463,6 +464,11 @@ class GraphView extends View {
graph.viewWholeGraph();
}
hideDeadAction(graph) {
graph.nodes.filter(function(n) { if (!n.live) n.visible = false; })
graph.updateGraphVisibility();
}
hideUnselectedAction(graph) {
var unselected = graph.visibleNodes.filter(function(n) {
return !this.classList.contains("selected");
......@@ -725,6 +731,8 @@ class GraphView extends View {
.append("g");
newGs.classed("control", function(n) { return n.isControl(); })
.classed("live", function(n) { return n.isLive(); })
.classed("dead", function(n) { return !n.isLive(); })
.classed("javascript", function(n) { return n.isJavaScript(); })
.classed("input", function(n) { return n.isInput(); })
.classed("simplified", function(n) { return n.isSimplified(); })
......
......@@ -16,6 +16,8 @@
alt="layout graph" class="button-input">
<input id="show-all" type="image" title="show all nodes" src="expand-all.jpg"
alt="show all nodes" class="button-input">
<input id="hide-dead" type="image" title="only live nodes" src="live.png"
alt="only live nodes" class="button-input">
<input id="hide-unselected" type="image" title="hide unselected nodes"
src="hide-unselected.png" alt="hide unselected nodes" class="button-input">
<input id="hide-selected" type="image" title="hide selected nodes"
......
This diff was suppressed by a .gitattributes entry.
......@@ -21,6 +21,9 @@ var Node = {
isInput: function() {
return this.opcode == 'Parameter' || this.opcode.endsWith('Constant');
},
isLive: function() {
return this.live;
},
isJavaScript: function() {
return this.opcode.startsWith('JS');
},
......
......@@ -85,6 +85,10 @@ g rect {
stroke-width: 2px;
}
g.dead {
opacity: .5;
}
g.unsorted rect {
opacity: 0.5;
}
......
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