summaryrefslogtreecommitdiff
path: root/chromium/v8/src/compiler/branch-elimination.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/compiler/branch-elimination.cc')
-rw-r--r--chromium/v8/src/compiler/branch-elimination.cc143
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(); }