Commit 29afe1e5 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[turbofan] Optimize traps after Merge/IfTrue/IfFalse

We implement two optimizations for trap conditionals for patterns that
come up in wasm-gc.
In case of a Merge followed by a trap, where the path conditions of all
branches of the Merge contain the trap condition, we lift the trap into
the branches of the Merge.
In case of a Branch whose IfTrue branch is followed by a TrapIf with the
same condition, we replace it with the trap followed by the IfFalse
branch. Symmetrically for IfFalse and TrapUnless.

Bug: v8:7748
Change-Id: I43040aebe60eab7b2230fc3130e3b8250e8b2f45
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3190109Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77181}
parent 9227a8da
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "src/compiler/branch-elimination.h" #include "src/compiler/branch-elimination.h"
#include "src/base/small-vector.h" #include "src/base/small-vector.h"
#include "src/compiler/compiler-source-position-table.h"
#include "src/compiler/js-graph.h" #include "src/compiler/js-graph.h"
#include "src/compiler/node-properties.h" #include "src/compiler/node-properties.h"
#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator.h"
...@@ -14,12 +15,15 @@ namespace internal { ...@@ -14,12 +15,15 @@ namespace internal {
namespace compiler { namespace compiler {
BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph, BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph,
Zone* zone, Phase phase) Zone* zone,
SourcePositionTable* source_positions,
Phase phase)
: AdvancedReducer(editor), : AdvancedReducer(editor),
jsgraph_(js_graph), jsgraph_(js_graph),
node_conditions_(js_graph->graph()->NodeCount(), zone), node_conditions_(js_graph->graph()->NodeCount(), zone),
reduced_(js_graph->graph()->NodeCount(), zone), reduced_(js_graph->graph()->NodeCount(), zone),
zone_(zone), zone_(zone),
source_positions_(source_positions),
dead_(js_graph->Dead()), dead_(js_graph->Dead()),
phase_(phase) {} phase_(phase) {}
...@@ -158,6 +162,71 @@ Reduction BranchElimination::ReduceBranch(Node* node) { ...@@ -158,6 +162,71 @@ Reduction BranchElimination::ReduceBranch(Node* node) {
return TakeConditionsFromFirstControl(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);
Revisit(merge);
return true;
}
Reduction BranchElimination::ReduceTrapConditional(Node* node) { Reduction BranchElimination::ReduceTrapConditional(Node* node) {
DCHECK(node->opcode() == IrOpcode::kTrapIf || DCHECK(node->opcode() == IrOpcode::kTrapIf ||
node->opcode() == IrOpcode::kTrapUnless); node->opcode() == IrOpcode::kTrapUnless);
...@@ -167,17 +236,55 @@ Reduction BranchElimination::ReduceTrapConditional(Node* node) { ...@@ -167,17 +236,55 @@ Reduction BranchElimination::ReduceTrapConditional(Node* node) {
// If we do not know anything about the predecessor, do not propagate just // 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 // yet because we will have to recompute anyway once we compute the
// predecessor. // predecessor.
if (!reduced_.Get(control_input)) { if (!reduced_.Get(control_input)) return NoChange();
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); ControlPathConditions from_input = node_conditions_.Get(control_input);
Node* branch; Node* previous_branch;
bool condition_value; 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) { if (condition_value == trapping_condition) {
// This will always trap. Mark its outputs as dead and connect it to // Special case: Trap directly inside a branch. Replace the branch with
// graph()->end(). // 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)) {
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);
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()); ReplaceWithValue(node, dead(), dead(), dead());
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = graph()->NewNode(common()->Throw(), effect, node); Node* control = graph()->NewNode(common()->Throw(), effect, node);
......
...@@ -19,6 +19,7 @@ namespace compiler { ...@@ -19,6 +19,7 @@ namespace compiler {
// Forward declarations. // Forward declarations.
class CommonOperatorBuilder; class CommonOperatorBuilder;
class JSGraph; class JSGraph;
class SourcePositionTable;
class V8_EXPORT_PRIVATE BranchElimination final class V8_EXPORT_PRIVATE BranchElimination final
: public NON_EXPORTED_BASE(AdvancedReducer) { : public NON_EXPORTED_BASE(AdvancedReducer) {
...@@ -28,7 +29,7 @@ class V8_EXPORT_PRIVATE BranchElimination final ...@@ -28,7 +29,7 @@ class V8_EXPORT_PRIVATE BranchElimination final
kLATE, kLATE,
}; };
BranchElimination(Editor* editor, JSGraph* js_graph, Zone* zone, BranchElimination(Editor* editor, JSGraph* js_graph, Zone* zone,
Phase phase = kLATE); SourcePositionTable* sourse_positions, Phase phase = kLATE);
~BranchElimination() final; ~BranchElimination() final;
const char* reducer_name() const override { return "BranchElimination"; } const char* reducer_name() const override { return "BranchElimination"; }
...@@ -108,6 +109,7 @@ class V8_EXPORT_PRIVATE BranchElimination final ...@@ -108,6 +109,7 @@ class V8_EXPORT_PRIVATE BranchElimination final
Reduction ReduceStart(Node* node); Reduction ReduceStart(Node* node);
Reduction ReduceOtherControl(Node* node); Reduction ReduceOtherControl(Node* node);
void SimplifyBranchCondition(Node* branch); void SimplifyBranchCondition(Node* branch);
bool TryPullTrapIntoMerge(Node* node);
Reduction TakeConditionsFromFirstControl(Node* node); Reduction TakeConditionsFromFirstControl(Node* node);
Reduction UpdateConditions(Node* node, ControlPathConditions conditions); Reduction UpdateConditions(Node* node, ControlPathConditions conditions);
...@@ -131,6 +133,7 @@ class V8_EXPORT_PRIVATE BranchElimination final ...@@ -131,6 +133,7 @@ class V8_EXPORT_PRIVATE BranchElimination final
node_conditions_; node_conditions_;
NodeAuxData<bool> reduced_; NodeAuxData<bool> reduced_;
Zone* zone_; Zone* zone_;
SourcePositionTable* source_positions_;
Node* dead_; Node* dead_;
Phase phase_; Phase phase_;
}; };
......
...@@ -1853,8 +1853,8 @@ struct LoadEliminationPhase { ...@@ -1853,8 +1853,8 @@ struct LoadEliminationPhase {
GraphReducer graph_reducer( GraphReducer graph_reducer(
temp_zone, data->graph(), &data->info()->tick_counter(), data->broker(), temp_zone, data->graph(), &data->info()->tick_counter(), data->broker(),
data->jsgraph()->Dead(), data->observe_node_manager()); data->jsgraph()->Dead(), data->observe_node_manager());
BranchElimination branch_condition_elimination(&graph_reducer, BranchElimination branch_condition_elimination(
data->jsgraph(), temp_zone, &graph_reducer, data->jsgraph(), temp_zone, data->source_positions(),
BranchElimination::kEARLY); BranchElimination::kEARLY);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common(), temp_zone); data->common(), temp_zone);
...@@ -1922,8 +1922,8 @@ struct LateOptimizationPhase { ...@@ -1922,8 +1922,8 @@ struct LateOptimizationPhase {
GraphReducer graph_reducer( GraphReducer graph_reducer(
temp_zone, data->graph(), &data->info()->tick_counter(), data->broker(), temp_zone, data->graph(), &data->info()->tick_counter(), data->broker(),
data->jsgraph()->Dead(), data->observe_node_manager()); data->jsgraph()->Dead(), data->observe_node_manager());
BranchElimination branch_condition_elimination(&graph_reducer, BranchElimination branch_condition_elimination(
data->jsgraph(), temp_zone); &graph_reducer, data->jsgraph(), temp_zone, data->source_positions());
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common(), temp_zone); data->common(), temp_zone);
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone()); ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
...@@ -2051,7 +2051,7 @@ struct WasmOptimizationPhase { ...@@ -2051,7 +2051,7 @@ struct WasmOptimizationPhase {
data->machine(), temp_zone); data->machine(), temp_zone);
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone()); ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
BranchElimination branch_condition_elimination( BranchElimination branch_condition_elimination(
&graph_reducer, data->jsgraph(), temp_zone); &graph_reducer, data->jsgraph(), temp_zone, data->source_positions());
AddReducer(data, &graph_reducer, &machine_reducer); AddReducer(data, &graph_reducer, &machine_reducer);
AddReducer(data, &graph_reducer, &dead_code_elimination); AddReducer(data, &graph_reducer, &dead_code_elimination);
AddReducer(data, &graph_reducer, &common_reducer); AddReducer(data, &graph_reducer, &common_reducer);
...@@ -2106,7 +2106,7 @@ struct CsaEarlyOptimizationPhase { ...@@ -2106,7 +2106,7 @@ struct CsaEarlyOptimizationPhase {
data->machine(), temp_zone); data->machine(), temp_zone);
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone()); ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
BranchElimination branch_condition_elimination( BranchElimination branch_condition_elimination(
&graph_reducer, data->jsgraph(), temp_zone); &graph_reducer, data->jsgraph(), temp_zone, data->source_positions());
AddReducer(data, &graph_reducer, &machine_reducer); AddReducer(data, &graph_reducer, &machine_reducer);
AddReducer(data, &graph_reducer, &dead_code_elimination); AddReducer(data, &graph_reducer, &dead_code_elimination);
AddReducer(data, &graph_reducer, &common_reducer); AddReducer(data, &graph_reducer, &common_reducer);
...@@ -2124,8 +2124,8 @@ struct CsaOptimizationPhase { ...@@ -2124,8 +2124,8 @@ struct CsaOptimizationPhase {
GraphReducer graph_reducer( GraphReducer graph_reducer(
temp_zone, data->graph(), &data->info()->tick_counter(), data->broker(), temp_zone, data->graph(), &data->info()->tick_counter(), data->broker(),
data->jsgraph()->Dead(), data->observe_node_manager()); data->jsgraph()->Dead(), data->observe_node_manager());
BranchElimination branch_condition_elimination(&graph_reducer, BranchElimination branch_condition_elimination(
data->jsgraph(), temp_zone); &graph_reducer, data->jsgraph(), temp_zone, data->source_positions());
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common(), temp_zone); data->common(), temp_zone);
MachineOperatorReducer machine_reducer(&graph_reducer, data->jsgraph(), MachineOperatorReducer machine_reducer(&graph_reducer, data->jsgraph(),
......
...@@ -31,7 +31,7 @@ class BranchEliminationTest : public GraphTest { ...@@ -31,7 +31,7 @@ class BranchEliminationTest : public GraphTest {
GraphReducer graph_reducer(zone(), graph(), tick_counter(), broker(), GraphReducer graph_reducer(zone(), graph(), tick_counter(), broker(),
jsgraph.Dead()); jsgraph.Dead());
BranchElimination branch_condition_elimination(&graph_reducer, &jsgraph, BranchElimination branch_condition_elimination(&graph_reducer, &jsgraph,
zone()); zone(), nullptr);
graph_reducer.AddReducer(&branch_condition_elimination); graph_reducer.AddReducer(&branch_condition_elimination);
graph_reducer.ReduceGraph(); graph_reducer.ReduceGraph();
} }
......
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