diff options
Diffstat (limited to 'chromium/v8/src/compiler/branch-elimination.cc')
-rw-r--r-- | chromium/v8/src/compiler/branch-elimination.cc | 143 |
1 files changed, 119 insertions, 24 deletions
diff --git a/chromium/v8/src/compiler/branch-elimination.cc b/chromium/v8/src/compiler/branch-elimination.cc index a864012a7a6..d2fce8a2768 100644 --- a/chromium/v8/src/compiler/branch-elimination.cc +++ b/chromium/v8/src/compiler/branch-elimination.cc @@ -5,6 +5,7 @@ #include "src/compiler/branch-elimination.h" #include "src/base/small-vector.h" +#include "src/compiler/compiler-source-position-table.h" #include "src/compiler/js-graph.h" #include "src/compiler/node-properties.h" #include "src/compiler/simplified-operator.h" @@ -14,12 +15,15 @@ namespace internal { namespace compiler { BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph, - Zone* zone, Phase phase) + Zone* zone, + SourcePositionTable* source_positions, + Phase phase) : AdvancedReducer(editor), jsgraph_(js_graph), node_conditions_(js_graph->graph()->NodeCount(), zone), reduced_(js_graph->graph()->NodeCount(), zone), zone_(zone), + source_positions_(source_positions), dead_(js_graph->Dead()), phase_(phase) {} @@ -135,7 +139,6 @@ Reduction BranchElimination::ReduceBranch(Node* node) { bool condition_value; // If we know the condition we can discard the branch. if (from_input.LookupCondition(condition, &branch, &condition_value)) { - MarkAsSafetyCheckIfNeeded(branch, node); for (Node* const use : node->uses()) { switch (use->opcode()) { case IrOpcode::kIfTrue: @@ -159,6 +162,72 @@ Reduction BranchElimination::ReduceBranch(Node* node) { return TakeConditionsFromFirstControl(node); } +// Simplify a trap following a merge. +// Assuming condition is in control1's path conditions, and !condition is in +// control2's path condtions, the following transformation takes place: +// +// control1 control2 condition effect1 +// \ / \ / | +// Merge X | control1 +// | / \ | / +// effect1 effect2 | | TrapIf control2 +// \ | /| ==> | \ / +// EffectPhi | | effect2 Merge +// | / | | / +// condition | / \ | / +// \ | / EffectPhi +// TrapIf +// TODO(manoskouk): We require that the trap's effect input is the Merge's +// EffectPhi, so we can ensure that the new traps' effect inputs are not +// dominated by the Merge. Can we relax this? +bool BranchElimination::TryPullTrapIntoMerge(Node* node) { + DCHECK(node->opcode() == IrOpcode::kTrapIf || + node->opcode() == IrOpcode::kTrapUnless); + Node* merge = NodeProperties::GetControlInput(node); + DCHECK_EQ(merge->opcode(), IrOpcode::kMerge); + Node* condition = NodeProperties::GetValueInput(node, 0); + Node* effect_input = NodeProperties::GetEffectInput(node); + if (!(effect_input->opcode() == IrOpcode::kEffectPhi && + NodeProperties::GetControlInput(effect_input) == merge)) { + return false; + } + + bool trapping_condition = node->opcode() == IrOpcode::kTrapIf; + base::SmallVector<Node*, 8> new_merge_inputs; + for (Edge edge : merge->input_edges()) { + Node* input = edge.to(); + ControlPathConditions from_input = node_conditions_.Get(input); + Node* previous_branch; + bool condition_value; + if (!from_input.LookupCondition(condition, &previous_branch, + &condition_value)) { + return false; + } + if (condition_value == trapping_condition) { + Node* inputs[] = { + condition, NodeProperties::GetEffectInput(effect_input, edge.index()), + input}; + Node* trap_clone = graph()->NewNode(node->op(), 3, inputs); + if (source_positions_) { + source_positions_->SetSourcePosition( + trap_clone, source_positions_->GetSourcePosition(node)); + } + new_merge_inputs.emplace_back(trap_clone); + } else { + new_merge_inputs.emplace_back(input); + } + } + + for (int i = 0; i < merge->InputCount(); i++) { + merge->ReplaceInput(i, new_merge_inputs[i]); + } + ReplaceWithValue(node, dead(), dead(), merge); + node->Kill(); + Revisit(merge); + + return true; +} + Reduction BranchElimination::ReduceTrapConditional(Node* node) { DCHECK(node->opcode() == IrOpcode::kTrapIf || node->opcode() == IrOpcode::kTrapUnless); @@ -168,17 +237,59 @@ Reduction BranchElimination::ReduceTrapConditional(Node* node) { // If we do not know anything about the predecessor, do not propagate just // yet because we will have to recompute anyway once we compute the // predecessor. - if (!reduced_.Get(control_input)) { - return NoChange(); + if (!reduced_.Get(control_input)) return NoChange(); + + // If the trap comes directly after a merge, pull it into the merge. This will + // unlock other optimizations later. + if (control_input->opcode() == IrOpcode::kMerge && + TryPullTrapIntoMerge(node)) { + return Replace(dead()); } + ControlPathConditions from_input = node_conditions_.Get(control_input); - Node* branch; + Node* previous_branch; bool condition_value; - if (from_input.LookupCondition(condition, &branch, &condition_value)) { + if (from_input.LookupCondition(condition, &previous_branch, + &condition_value)) { if (condition_value == trapping_condition) { - // This will always trap. Mark its outputs as dead and connect it to - // graph()->end(). + // Special case: Trap directly inside a branch without sibling nodes. + // Replace the branch with the trap. + // condition control condition control + // | \ / \ / + // | Branch TrapIf + // | / \ ==> | + // | IfTrue IfFalse <subgraph2> + // | / | + // TrapIf <subraph2> Dead + // | | + // <subgraph1> <subgraph1> + // (and symmetrically for TrapUnless.) + if ((control_input->opcode() == IrOpcode::kIfTrue || + control_input->opcode() == IrOpcode::kIfFalse) && + control_input->UseCount() == 1) { + Node* branch = NodeProperties::GetControlInput(control_input); + DCHECK_EQ(branch->opcode(), IrOpcode::kBranch); + if (condition == NodeProperties::GetValueInput(branch, 0)) { + Node* other_if_branch = nullptr; + for (Node* use : branch->uses()) { + if (use != control_input) other_if_branch = use; + } + DCHECK_NOT_NULL(other_if_branch); + + node->ReplaceInput(NodeProperties::FirstControlIndex(node), + NodeProperties::GetControlInput(branch)); + ReplaceWithValue(node, dead(), dead(), dead()); + ReplaceWithValue(other_if_branch, node, node, node); + other_if_branch->Kill(); + control_input->Kill(); + branch->Kill(); + return Changed(node); + } + } + + // General case: This will always trap. Mark its outputs as dead and + // connect it to graph()->end(). ReplaceWithValue(node, dead(), dead(), dead()); Node* effect = NodeProperties::GetEffectInput(node); Node* control = graph()->NewNode(common()->Throw(), effect, node); @@ -215,7 +326,6 @@ Reduction BranchElimination::ReduceDeoptimizeConditional(Node* node) { Node* branch; // If we know the condition we can discard the branch. if (conditions.LookupCondition(condition, &branch, &condition_value)) { - MarkAsSafetyCheckIfNeeded(branch, node); if (condition_is_true == condition_value) { // We don't update the conditions here, because we're replacing {node} // with the {control} node that already contains the right information. @@ -410,21 +520,6 @@ bool BranchElimination::ControlPathConditions::BlocksAndConditionsInvariant() { } #endif -void BranchElimination::MarkAsSafetyCheckIfNeeded(Node* branch, Node* node) { - // Check if {branch} is dead because we might have a stale side-table entry. - if (!branch->IsDead() && branch->opcode() != IrOpcode::kDead && - branch->opcode() != IrOpcode::kTrapIf && - branch->opcode() != IrOpcode::kTrapUnless) { - IsSafetyCheck branch_safety = IsSafetyCheckOf(branch->op()); - IsSafetyCheck combined_safety = - CombineSafetyChecks(branch_safety, IsSafetyCheckOf(node->op())); - if (branch_safety != combined_safety) { - NodeProperties::ChangeOp( - branch, common()->MarkAsSafetyCheck(branch->op(), combined_safety)); - } - } -} - Graph* BranchElimination::graph() const { return jsgraph()->graph(); } Isolate* BranchElimination::isolate() const { return jsgraph()->isolate(); } |