Index: src/compiler/control-reducer.cc |
diff --git a/src/compiler/control-reducer.cc b/src/compiler/control-reducer.cc |
deleted file mode 100644 |
index dedd3c949154d773ad26cab5ffcde711eab497e5..0000000000000000000000000000000000000000 |
--- a/src/compiler/control-reducer.cc |
+++ /dev/null |
@@ -1,328 +0,0 @@ |
-// Copyright 2014 the V8 project authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "src/compiler/common-operator.h" |
-#include "src/compiler/common-operator-reducer.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" |
-#include "src/compiler/node-properties.h" |
-#include "src/zone-containers.h" |
- |
-namespace v8 { |
-namespace internal { |
-namespace compiler { |
- |
-#define TRACE(...) \ |
- do { \ |
- if (FLAG_trace_turbo_reduction) PrintF(__VA_ARGS__); \ |
- } while (false) |
- |
-enum Decision { kFalse, kUnknown, kTrue }; |
- |
-class ControlReducerImpl final : public AdvancedReducer { |
- public: |
- Zone* zone_; |
- JSGraph* jsgraph_; |
- int max_phis_for_select_; |
- |
- ControlReducerImpl(Editor* editor, Zone* zone, JSGraph* jsgraph) |
- : AdvancedReducer(editor), |
- zone_(zone), |
- jsgraph_(jsgraph), |
- max_phis_for_select_(0) {} |
- |
- Graph* graph() { return jsgraph_->graph(); } |
- CommonOperatorBuilder* common() { return jsgraph_->common(); } |
- Node* dead() { return jsgraph_->DeadControl(); } |
- |
- //=========================================================================== |
- // Reducer implementation: perform reductions on a 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::kDeadControl) { |
- TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic()); |
- return Replace(control); |
- } |
- } |
- |
- Node* result = node; |
- // Reduce branches, phis, and merges. |
- switch (node->opcode()) { |
- case IrOpcode::kBranch: |
- result = ReduceBranch(node); |
- break; |
- case IrOpcode::kIfTrue: |
- result = ReduceIfProjection(node, kTrue); |
- break; |
- case IrOpcode::kIfFalse: |
- result = ReduceIfProjection(node, kFalse); |
- break; |
- case IrOpcode::kLoop: // fallthrough |
- case IrOpcode::kMerge: |
- result = ReduceMerge(node); |
- break; |
- case IrOpcode::kEnd: |
- result = ReduceEnd(node); |
- break; |
- default: |
- break; |
- } |
- |
- return result == node ? NoChange() : Replace(result); |
- } |
- |
- // Try to statically fold a condition. |
- Decision DecideCondition(Node* cond) { |
- switch (cond->opcode()) { |
- case IrOpcode::kInt32Constant: |
- return Int32Matcher(cond).Is(0) ? kFalse : kTrue; |
- case IrOpcode::kInt64Constant: |
- return Int64Matcher(cond).Is(0) ? kFalse : kTrue; |
- case IrOpcode::kHeapConstant: { |
- Handle<Object> object = |
- HeapObjectMatcher<Object>(cond).Value().handle(); |
- return object->BooleanValue() ? kTrue : kFalse; |
- } |
- default: |
- break; |
- } |
- return kUnknown; |
- } |
- |
- // Reduce branches. |
- Node* ReduceBranch(Node* branch) { |
- if (DecideCondition(branch->InputAt(0)) != kUnknown) { |
- for (Node* use : branch->uses()) Revisit(use); |
- } |
- return branch; |
- } |
- |
- // Reduce end by trimming away dead inputs. |
- Node* ReduceEnd(Node* node) { |
- // Count the number of live inputs. |
- int live = 0; |
- for (int index = 0; index < node->InputCount(); ++index) { |
- // Skip dead inputs. |
- if (node->InputAt(index)->opcode() == IrOpcode::kDeadControl) continue; |
- // Compact live inputs. |
- if (index != live) node->ReplaceInput(live, node->InputAt(index)); |
- ++live; |
- } |
- |
- TRACE("ReduceEnd: #%d:%s (%d of %d live)\n", node->id(), |
- node->op()->mnemonic(), live, node->InputCount()); |
- |
- if (live == 0) return dead(); // No remaining inputs. |
- |
- if (live < node->InputCount()) { |
- node->set_op(common()->End(live)); |
- node->TrimInputCount(live); |
- } |
- |
- return node; |
- } |
- |
- // Reduce merges by trimming away dead inputs from the merge and phis. |
- Node* ReduceMerge(Node* node) { |
- // Count the number of live inputs. |
- int live = 0; |
- int index = 0; |
- int live_index = 0; |
- for (Node* const input : node->inputs()) { |
- if (input->opcode() != IrOpcode::kDeadControl) { |
- live++; |
- live_index = index; |
- } |
- index++; |
- } |
- |
- TRACE("ReduceMerge: #%d:%s (%d of %d live)\n", node->id(), |
- node->op()->mnemonic(), live, index); |
- |
- if (live == 0) return dead(); // no remaining inputs. |
- |
- // Gather terminates, phis and effect phis to be edited. |
- NodeVector phis(zone_); |
- Node* terminate = nullptr; |
- for (Node* const use : node->uses()) { |
- if (NodeProperties::IsPhi(use)) { |
- phis.push_back(use); |
- } else if (use->opcode() == IrOpcode::kTerminate) { |
- DCHECK_NULL(terminate); |
- terminate = use; |
- } |
- } |
- |
- if (live == 1) { |
- // All phis are redundant. Replace them with their live input. |
- for (Node* const phi : phis) { |
- Replace(phi, phi->InputAt(live_index)); |
- } |
- // The terminate is not needed anymore. |
- if (terminate) Replace(terminate, dead()); |
- // The merge itself is redundant. |
- return node->InputAt(live_index); |
- } |
- |
- DCHECK_LE(2, live); |
- |
- if (live < node->InputCount()) { |
- // Edit phis in place, removing dead inputs and revisiting them. |
- for (Node* const phi : phis) { |
- TRACE(" PhiInMerge: #%d:%s (%d live)\n", phi->id(), |
- phi->op()->mnemonic(), live); |
- RemoveDeadInputs(node, phi); |
- Revisit(phi); |
- } |
- // Edit the merge in place, removing dead inputs. |
- RemoveDeadInputs(node, node); |
- } |
- |
- DCHECK_EQ(live, node->InputCount()); |
- |
- // Try to remove dead diamonds or introduce selects. |
- if (live == 2 && CheckPhisForSelect(phis)) { |
- DiamondMatcher matcher(node); |
- if (matcher.Matched() && matcher.IfProjectionsAreOwned()) { |
- // Dead diamond, i.e. neither the IfTrue nor the IfFalse nodes |
- // have uses except for the Merge. Remove the branch if there |
- // are no phis or replace phis with selects. |
- Node* control = NodeProperties::GetControlInput(matcher.Branch()); |
- if (phis.size() == 0) { |
- // No phis. Remove the branch altogether. |
- TRACE(" DeadDiamond: #%d:Branch #%d:IfTrue #%d:IfFalse\n", |
- matcher.Branch()->id(), matcher.IfTrue()->id(), |
- matcher.IfFalse()->id()); |
- return control; |
- } else { |
- // A small number of phis. Replace with selects. |
- Node* cond = matcher.Branch()->InputAt(0); |
- for (Node* phi : phis) { |
- Node* select = graph()->NewNode( |
- 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()); |
- Replace(phi, select); |
- } |
- return control; |
- } |
- } |
- } |
- |
- return node; |
- } |
- |
- bool CheckPhisForSelect(const NodeVector& phis) { |
- if (phis.size() > static_cast<size_t>(max_phis_for_select_)) return false; |
- for (Node* phi : phis) { |
- if (phi->opcode() != IrOpcode::kPhi) return false; // no EffectPhis. |
- } |
- return true; |
- } |
- |
- // Reduce if projections if the branch has a constant input. |
- Node* ReduceIfProjection(Node* node, Decision decision) { |
- Node* branch = node->InputAt(0); |
- DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
- Decision result = DecideCondition(branch->InputAt(0)); |
- if (result == decision) { |
- // Fold a branch by replacing IfTrue/IfFalse with the branch control. |
- TRACE(" BranchReduce: #%d:%s => #%d:%s\n", branch->id(), |
- branch->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
- return branch->InputAt(1); |
- } |
- return result == kUnknown ? node : dead(); |
- } |
- |
- // Remove inputs to {node} corresponding to the dead inputs to {merge} |
- // and compact the remaining inputs, updating the operator. |
- void RemoveDeadInputs(Node* merge, Node* node) { |
- int live = 0; |
- for (int i = 0; i < merge->InputCount(); i++) { |
- // skip dead inputs. |
- if (merge->InputAt(i)->opcode() == IrOpcode::kDeadControl) continue; |
- // compact live inputs. |
- if (live != i) node->ReplaceInput(live, node->InputAt(i)); |
- live++; |
- } |
- // compact remaining inputs. |
- int total = live; |
- for (int i = merge->InputCount(); i < node->InputCount(); i++) { |
- if (total != i) node->ReplaceInput(total, node->InputAt(i)); |
- total++; |
- } |
- DCHECK_EQ(total, live + node->InputCount() - merge->InputCount()); |
- DCHECK_NE(total, node->InputCount()); |
- node->TrimInputCount(total); |
- node->set_op(common()->ResizeMergeOrPhi(node->op(), live)); |
- } |
-}; |
- |
- |
-void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph, |
- int max_phis_for_select) { |
- GraphReducer graph_reducer(zone, jsgraph->graph()); |
- CommonOperatorReducer common(&graph_reducer, jsgraph->graph(), |
- jsgraph->common(), jsgraph->machine()); |
- ControlReducerImpl impl(&graph_reducer, zone, jsgraph); |
- impl.max_phis_for_select_ = max_phis_for_select; |
- graph_reducer.AddReducer(&impl); |
- graph_reducer.AddReducer(&common); |
- 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 {} |
- void ReplaceWithValue(Node* node, Node* value, Node* effect, |
- Node* control) final {} |
-}; |
- |
-} // namespace |
- |
- |
-Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, Node* node, |
- int max_phis_for_select) { |
- Zone zone; |
- DummyEditor editor; |
- ControlReducerImpl impl(&editor, &zone, jsgraph); |
- impl.max_phis_for_select_ = max_phis_for_select; |
- return impl.ReduceMerge(node); |
-} |
- |
- |
-Node* ControlReducer::ReduceIfNodeForTesting(JSGraph* jsgraph, Node* node) { |
- Zone zone; |
- DummyEditor editor; |
- ControlReducerImpl impl(&editor, &zone, jsgraph); |
- switch (node->opcode()) { |
- case IrOpcode::kIfTrue: |
- return impl.ReduceIfProjection(node, kTrue); |
- case IrOpcode::kIfFalse: |
- return impl.ReduceIfProjection(node, kFalse); |
- default: |
- return node; |
- } |
-} |
- |
-} // namespace compiler |
-} // namespace internal |
-} // namespace v8 |