Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(316)

Unified Diff: src/compiler/control-reducer.cc

Issue 1122423003: [turbofan] Add support for advanced reducers. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Move comment Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/control-reducer.h ('k') | src/compiler/graph-reducer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/control-reducer.cc
diff --git a/src/compiler/control-reducer.cc b/src/compiler/control-reducer.cc
index fb4405cc9aba917cedb2475a252b56a11484b28b..281458b9b2823d40c88d664854e1f199f47c062f 100644
--- a/src/compiler/control-reducer.cc
+++ b/src/compiler/control-reducer.cc
@@ -5,6 +5,7 @@
#include "src/compiler/common-operator.h"
#include "src/compiler/control-reducer.h"
#include "src/compiler/graph.h"
+#include "src/compiler/graph-reducer.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node-marker.h"
#include "src/compiler/node-matchers.h"
@@ -47,56 +48,25 @@ class ReachabilityMarker : public NodeMarker<uint8_t> {
};
-class ControlReducerImpl {
+class ControlReducerImpl final : public AdvancedReducer {
public:
- ControlReducerImpl(Zone* zone, JSGraph* jsgraph,
- CommonOperatorBuilder* common)
- : zone_(zone),
- jsgraph_(jsgraph),
- common_(common),
- state_(jsgraph->graph()->NodeCount(), kUnvisited, zone_),
- stack_(zone_),
- revisit_(zone_),
- max_phis_for_select_(0) {}
-
Zone* zone_;
JSGraph* jsgraph_;
- CommonOperatorBuilder* common_;
- ZoneVector<VisitState> state_;
- ZoneDeque<Node*> stack_;
- ZoneDeque<Node*> revisit_;
int max_phis_for_select_;
- void Reduce() {
- Push(graph()->end());
- do {
- // Process the node on the top of the stack, potentially pushing more
- // or popping the node off the stack.
- ReduceTop();
- // If the stack becomes empty, revisit any nodes in the revisit queue.
- // If no nodes in the revisit queue, try removing dead loops.
- // If no dead loops, then finish.
- } while (!stack_.empty() || TryRevisit() || RepairAndRemoveLoops());
- }
-
- bool TryRevisit() {
- while (!revisit_.empty()) {
- Node* n = revisit_.back();
- revisit_.pop_back();
- if (state_[n->id()] == kRevisit) { // state can change while in queue.
- Push(n);
- return true;
- }
- }
- return false;
- }
+ ControlReducerImpl(Editor* editor, Zone* zone, JSGraph* jsgraph)
+ : AdvancedReducer(editor),
+ zone_(zone),
+ jsgraph_(jsgraph),
+ max_phis_for_select_(0) {}
- // Repair the graph after the possible creation of non-terminating or dead
- // loops. Removing dead loops can produce more opportunities for reduction.
- bool RepairAndRemoveLoops() {
- // TODO(turbofan): we can skip this if the graph has no loops, but
- // we have to be careful about proper loop detection during reduction.
+ Graph* graph() { return jsgraph_->graph(); }
+ CommonOperatorBuilder* common() { return jsgraph_->common(); }
+ Node* dead() { return jsgraph_->DeadControl(); }
+ // Finish reducing the graph by trimming nodes and/or connecting NTLs.
+ bool Finish() final {
+ bool done = true;
// Gather all nodes backwards-reachable from end (through inputs).
ReachabilityMarker marked(graph());
NodeVector nodes(zone_);
@@ -164,11 +134,15 @@ class ControlReducerImpl {
for (size_t i = 0; i < nodes.size(); i++) {
Node* node = nodes[i];
if (node->op()->ControlOutputCount() > 0 &&
- !marked.IsReachableFromStart(node)) {
- ReplaceNode(node, dead()); // uses will be added to revisit queue.
+ !marked.IsReachableFromStart(node) &&
+ node->opcode() != IrOpcode::kDead) {
+ TRACE("Dead: #%d:%s\n", node->id(), node->op()->mnemonic());
+ node->ReplaceUses(dead());
+ done = false;
}
}
- return TryRevisit(); // try to push a node onto the stack.
+
+ return done;
}
// Connect {loop}, the header of a non-terminating loop, to the end node.
@@ -176,23 +150,12 @@ class ControlReducerImpl {
TRACE("ConnectNTL: #%d:%s\n", loop->id(), loop->op()->mnemonic());
DCHECK_EQ(IrOpcode::kLoop, loop->opcode());
- Node* always = graph()->NewNode(common_->Always());
- // Mark the node as visited so that we can revisit later.
- MarkAsVisited(always);
-
- Node* branch = graph()->NewNode(common_->Branch(), always, loop);
- // Mark the node as visited so that we can revisit later.
- MarkAsVisited(branch);
+ Node* always = graph()->NewNode(common()->Always());
+ Node* branch = graph()->NewNode(common()->Branch(), always, loop);
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* if_true = graph()->NewNode(common_->IfTrue(), branch);
- // Mark the node as visited so that we can revisit later.
- MarkAsVisited(if_true);
-
- Node* if_false = graph()->NewNode(common_->IfFalse(), branch);
- // Mark the node as visited so that we can revisit later.
- MarkAsVisited(if_false);
-
- // Hook up the branch into the loop and collect all loop effects.
+ // Insert the branch into the loop and collect all loop effects.
NodeVector effects(zone_);
for (auto edge : loop->use_edges()) {
DCHECK_EQ(loop, edge.to());
@@ -217,35 +180,35 @@ class ControlReducerImpl {
if (effects_count == 1) {
effect = effects[0];
} else if (effects_count > 1) {
- effect = graph()->NewNode(common_->EffectSet(effects_count),
+ effect = graph()->NewNode(common()->EffectSet(effects_count),
effects_count, &effects.front());
- // Mark the node as visited so that we can revisit later.
- MarkAsVisited(effect);
}
// Add a return to connect the NTL to the end.
Node* ret = graph()->NewNode(
- common_->Return(), jsgraph_->UndefinedConstant(), effect, if_false);
- // Mark the node as visited so that we can revisit later.
- MarkAsVisited(ret);
+ common()->Return(), jsgraph_->UndefinedConstant(), effect, if_false);
Node* end = graph()->end();
- CHECK_EQ(IrOpcode::kEnd, end->opcode());
+ if (end->opcode() == IrOpcode::kDead) {
+ // End is actually the dead node. Make a new end.
+ end = graph()->NewNode(common()->End(), ret);
+ graph()->SetEnd(end);
+ return end;
+ }
+ // End is not dead.
Node* merge = end->InputAt(0);
if (merge == NULL || merge->opcode() == IrOpcode::kDead) {
// The end node died; just connect end to {ret}.
end->ReplaceInput(0, ret);
} else if (merge->opcode() != IrOpcode::kMerge) {
// Introduce a final merge node for {end->InputAt(0)} and {ret}.
- merge = graph()->NewNode(common_->Merge(2), merge, ret);
+ merge = graph()->NewNode(common()->Merge(2), merge, ret);
end->ReplaceInput(0, merge);
ret = merge;
- // Mark the node as visited so that we can revisit later.
- MarkAsVisited(merge);
} else {
// Append a new input to the final merge at the end.
merge->AppendInput(graph()->zone(), ret);
- merge->set_op(common_->Merge(merge->InputCount()));
+ merge->set_op(common()->Merge(merge->InputCount()));
}
return ret;
}
@@ -320,116 +283,48 @@ class ControlReducerImpl {
#endif
}
- // Reduce the node on the top of the stack.
- // If an input {i} is not yet visited or needs to be revisited, push {i} onto
- // the stack and return. Otherwise, all inputs are visited, so apply
- // reductions for {node} and pop it off the stack.
- void ReduceTop() {
- size_t height = stack_.size();
- Node* node = stack_.back();
-
- if (node->IsDead()) return Pop(); // Node was killed while on stack.
-
- TRACE("ControlReduce: #%d:%s\n", node->id(), node->op()->mnemonic());
-
- // Recurse on an input if necessary.
- for (Node* const input : node->inputs()) {
- DCHECK(input);
- if (Recurse(input)) return;
- }
-
- // All inputs should be visited or on stack. Apply reductions to node.
- Node* replacement = ReduceNode(node);
- if (replacement != node) ReplaceNode(node, replacement);
-
- // After reducing the node, pop it off the stack.
- CHECK_EQ(static_cast<int>(height), static_cast<int>(stack_.size()));
- Pop();
-
- // If there was a replacement, reduce it after popping {node}.
- if (replacement != node) Recurse(replacement);
- }
-
- void EnsureStateSize(size_t id) {
- if (id >= state_.size()) {
- state_.resize((3 * id) / 2, kUnvisited);
- }
- }
-
- // Push a node onto the stack if its state is {kUnvisited} or {kRevisit}.
- bool Recurse(Node* node) {
- size_t id = static_cast<size_t>(node->id());
- EnsureStateSize(id);
- if (state_[id] != kRevisit && state_[id] != kUnvisited) return false;
- Push(node);
- return true;
- }
-
- void Push(Node* node) {
- state_[node->id()] = kOnStack;
- stack_.push_back(node);
- }
-
- void Pop() {
- int pos = static_cast<int>(stack_.size()) - 1;
- DCHECK_GE(pos, 0);
- DCHECK_EQ(kOnStack, state_[stack_[pos]->id()]);
- state_[stack_[pos]->id()] = kVisited;
- stack_.pop_back();
- }
-
- // Queue a node to be revisited if it has been visited once already.
- void Revisit(Node* node) {
- size_t id = static_cast<size_t>(node->id());
- if (id < state_.size() && state_[id] == kVisited) {
- TRACE(" Revisit #%d:%s\n", node->id(), node->op()->mnemonic());
- state_[id] = kRevisit;
- revisit_.push_back(node);
- }
- }
-
- // Mark {node} as visited.
- void MarkAsVisited(Node* node) {
- size_t id = static_cast<size_t>(node->id());
- EnsureStateSize(id);
- state_[id] = kVisited;
- }
-
- Node* dead() { return jsgraph_->DeadControl(); }
-
//===========================================================================
// Reducer implementation: perform reductions on a node.
//===========================================================================
- Node* ReduceNode(Node* node) {
+ Reduction Reduce(Node* node) override {
if (node->op()->ControlInputCount() == 1 ||
node->opcode() == IrOpcode::kLoop) {
// If a node has only one control input and it is dead, replace with dead.
Node* control = NodeProperties::GetControlInput(node);
if (control->opcode() == IrOpcode::kDead) {
TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic());
- return control;
+ return Replace(control);
}
}
+ Node* result = node;
// Reduce branches, phis, and merges.
switch (node->opcode()) {
case IrOpcode::kBranch:
- return ReduceBranch(node);
+ result = ReduceBranch(node);
+ break;
case IrOpcode::kIfTrue:
- return ReduceIfProjection(node, kTrue);
+ result = ReduceIfProjection(node, kTrue);
+ break;
case IrOpcode::kIfFalse:
- return ReduceIfProjection(node, kFalse);
- case IrOpcode::kLoop:
+ result = ReduceIfProjection(node, kFalse);
+ break;
+ case IrOpcode::kLoop: // fallthrough
case IrOpcode::kMerge:
- return ReduceMerge(node);
+ result = ReduceMerge(node);
+ break;
case IrOpcode::kSelect:
- return ReduceSelect(node);
+ result = ReduceSelect(node);
+ break;
case IrOpcode::kPhi:
case IrOpcode::kEffectPhi:
- return ReducePhi(node);
+ result = ReducePhi(node);
+ break;
default:
- return node;
+ break;
}
+
+ return result == node ? NoChange() : Replace(result);
}
// Try to statically fold a condition.
@@ -543,7 +438,9 @@ class ControlReducerImpl {
if (live == 1) {
// All phis are redundant. Replace them with their live input.
- for (Node* const phi : phis) ReplaceNode(phi, phi->InputAt(live_index));
+ for (Node* const phi : phis) {
+ Replace(phi, phi->InputAt(live_index));
+ }
// The merge itself is redundant.
return node->InputAt(live_index);
}
@@ -583,13 +480,13 @@ class ControlReducerImpl {
Node* cond = matcher.Branch()->InputAt(0);
for (Node* phi : phis) {
Node* select = graph()->NewNode(
- common_->Select(OpParameter<MachineType>(phi),
- BranchHintOf(matcher.Branch()->op())),
+ common()->Select(OpParameter<MachineType>(phi),
+ BranchHintOf(matcher.Branch()->op())),
cond, matcher.TrueInputOf(phi), matcher.FalseInputOf(phi));
TRACE(" MatchSelect: #%d:Branch #%d:IfTrue #%d:IfFalse -> #%d\n",
matcher.Branch()->id(), matcher.IfTrue()->id(),
matcher.IfFalse()->id(), select->id());
- ReplaceNode(phi, select);
+ Replace(phi, select);
}
return control;
}
@@ -641,65 +538,63 @@ class ControlReducerImpl {
DCHECK_EQ(total, live + node->InputCount() - merge->InputCount());
DCHECK_NE(total, node->InputCount());
node->TrimInputCount(total);
- node->set_op(common_->ResizeMergeOrPhi(node->op(), live));
+ node->set_op(common()->ResizeMergeOrPhi(node->op(), live));
}
-
- // Replace uses of {node} with {replacement} and revisit the uses.
- void ReplaceNode(Node* node, Node* replacement) {
- if (node == replacement) return;
- TRACE(" Replace: #%d:%s with #%d:%s\n", node->id(), node->op()->mnemonic(),
- replacement->id(), replacement->op()->mnemonic());
- for (Node* const use : node->uses()) {
- // Don't revisit this node if it refers to itself.
- if (use != node) Revisit(use);
- }
- node->ReplaceUses(replacement);
- node->Kill();
- }
-
- Graph* graph() { return jsgraph_->graph(); }
};
void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph,
- CommonOperatorBuilder* common,
int max_phis_for_select) {
- ControlReducerImpl impl(zone, jsgraph, common);
+ GraphReducer graph_reducer(jsgraph->graph(), zone);
+ ControlReducerImpl impl(&graph_reducer, zone, jsgraph);
impl.max_phis_for_select_ = max_phis_for_select;
- impl.Reduce();
+ graph_reducer.AddReducer(&impl);
+ graph_reducer.ReduceGraph();
}
+namespace {
+
+class DummyEditor final : public AdvancedReducer::Editor {
+ public:
+ void Replace(Node* node, Node* replacement) final {
+ node->ReplaceUses(replacement);
+ }
+ void Revisit(Node* node) final {}
+};
+
+} // namespace
+
+
void ControlReducer::TrimGraph(Zone* zone, JSGraph* jsgraph) {
- ControlReducerImpl impl(zone, jsgraph, NULL);
+ DummyEditor editor;
+ ControlReducerImpl impl(&editor, zone, jsgraph);
impl.Trim();
}
-Node* ControlReducer::ReduceMerge(JSGraph* jsgraph,
- CommonOperatorBuilder* common, Node* node,
+Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, Node* node,
int max_phis_for_select) {
Zone zone;
- ControlReducerImpl impl(&zone, jsgraph, common);
+ DummyEditor editor;
+ ControlReducerImpl impl(&editor, &zone, jsgraph);
impl.max_phis_for_select_ = max_phis_for_select;
return impl.ReduceMerge(node);
}
-Node* ControlReducer::ReducePhiForTesting(JSGraph* jsgraph,
- CommonOperatorBuilder* common,
- Node* node) {
+Node* ControlReducer::ReducePhiForTesting(JSGraph* jsgraph, Node* node) {
Zone zone;
- ControlReducerImpl impl(&zone, jsgraph, common);
+ DummyEditor editor;
+ ControlReducerImpl impl(&editor, &zone, jsgraph);
return impl.ReducePhi(node);
}
-Node* ControlReducer::ReduceIfNodeForTesting(JSGraph* jsgraph,
- CommonOperatorBuilder* common,
- Node* node) {
+Node* ControlReducer::ReduceIfNodeForTesting(JSGraph* jsgraph, Node* node) {
Zone zone;
- ControlReducerImpl impl(&zone, jsgraph, common);
+ DummyEditor editor;
+ ControlReducerImpl impl(&editor, &zone, jsgraph);
switch (node->opcode()) {
case IrOpcode::kIfTrue:
return impl.ReduceIfProjection(node, kTrue);
@@ -709,6 +604,7 @@ Node* ControlReducer::ReduceIfNodeForTesting(JSGraph* jsgraph,
return node;
}
}
-}
-}
-} // namespace v8::internal::compiler
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
« no previous file with comments | « src/compiler/control-reducer.h ('k') | src/compiler/graph-reducer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698