Commit 3548c5c6 authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[turbofan] Make IfException projections consume effects.

This is needed in order to allow expansion of a throwing node into a
set of nodes that produce different effects for the successful and the
exceptional continuation.

R=bmeurer@chromium.org

Review URL: https://codereview.chromium.org/1179543002

Cr-Commit-Position: refs/heads/master@{#28918}
parent ec4baaed
......@@ -3845,8 +3845,10 @@ Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
// Copy the environment for the success continuation.
Environment* success_env = environment()->CopyForConditional();
const Operator* op = common()->IfException(hint);
Node* on_exception = graph()->NewNode(op, result);
Node* effect = environment()->GetEffectDependency();
Node* on_exception = graph()->NewNode(op, effect, result);
environment_->UpdateControlDependency(on_exception);
environment_->UpdateEffectDependency(on_exception);
execution_control()->ThrowValue(on_exception);
set_environment(success_env);
}
......
......@@ -230,7 +230,7 @@ struct CommonOperatorGlobalCache final {
: Operator1<IfExceptionHint>( // --
IrOpcode::kIfException, Operator::kKontrol, // opcode
"IfException", // name
0, 0, 1, 1, 0, 1, // counts
0, 1, 1, 1, 1, 1, // counts
kCaughtLocally) {} // parameter
};
IfExceptionOperator<IfExceptionHint::kLocallyCaught> kIfExceptionCOperator;
......
......@@ -231,9 +231,10 @@ void GraphReducer::ReplaceWithValue(Node* node, Node* value, Node* effect,
} else if (user->opcode() == IrOpcode::kIfException) {
for (Edge e : user->use_edges()) {
if (NodeProperties::IsValueEdge(e)) e.UpdateTo(dead_value_);
if (NodeProperties::IsEffectEdge(e)) e.UpdateTo(graph()->start());
if (NodeProperties::IsControlEdge(e)) e.UpdateTo(dead_control_);
}
user->Kill();
edge.UpdateTo(user);
} else {
UNREACHABLE();
}
......@@ -242,6 +243,7 @@ void GraphReducer::ReplaceWithValue(Node* node, Node* value, Node* effect,
edge.UpdateTo(effect);
Revisit(user);
} else {
DCHECK_NOT_NULL(value);
edge.UpdateTo(value);
Revisit(user);
}
......
......@@ -931,7 +931,7 @@ void InstructionSelector::VisitParameter(Node* node) {
void InstructionSelector::VisitIfException(Node* node) {
OperandGenerator g(this);
Node* call = node->InputAt(0);
Node* call = node->InputAt(1);
DCHECK_EQ(IrOpcode::kCall, call->opcode());
const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(call);
Emit(kArchNop, g.DefineAsLocation(node, descriptor->GetReturnLocation(0),
......
......@@ -214,7 +214,9 @@ void NodeProperties::CollectControlProjections(Node* node, Node** projections,
std::memset(projections, 0, sizeof(*projections) * projection_count);
#endif
size_t if_value_index = 0;
for (Node* const use : node->uses()) {
for (Edge const edge : node->use_edges()) {
if (!IsControlEdge(edge)) continue;
Node* use = edge.from();
size_t index;
switch (use->opcode()) {
case IrOpcode::kIfTrue:
......
......@@ -225,11 +225,11 @@ TEST_F(CommonOperatorTest, IfException) {
EXPECT_EQ(IrOpcode::kIfException, op->opcode());
EXPECT_EQ(Operator::kKontrol, op->properties());
EXPECT_EQ(0, op->ValueInputCount());
EXPECT_EQ(0, op->EffectInputCount());
EXPECT_EQ(1, op->EffectInputCount());
EXPECT_EQ(1, op->ControlInputCount());
EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(2, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(1, op->ValueOutputCount());
EXPECT_EQ(0, op->EffectOutputCount());
EXPECT_EQ(1, op->EffectOutputCount());
EXPECT_EQ(1, op->ControlOutputCount());
}
}
......
......@@ -340,10 +340,11 @@ TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse1) {
TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse2) {
CommonOperatorBuilder common(zone());
Node* start = graph()->NewNode(common.Start(1));
Node* effect = graph()->NewNode(&kMockOperator);
Node* dead = graph()->NewNode(&kMockOperator);
Node* node = graph()->NewNode(&kMockOpControl, start);
Node* success = graph()->NewNode(common.IfSuccess(), node);
Node* exception = graph()->NewNode(common.IfException(kNoHint), node);
Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node);
Node* use_control = graph()->NewNode(common.Merge(1), success);
Node* use_exception_control = graph()->NewNode(common.Merge(1), exception);
Node* replacement = graph()->NewNode(&kMockOperator);
......@@ -364,10 +365,11 @@ TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse2) {
TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse3) {
CommonOperatorBuilder common(zone());
Node* start = graph()->NewNode(common.Start(1));
Node* effect = graph()->NewNode(&kMockOperator);
Node* dead = graph()->NewNode(&kMockOperator);
Node* node = graph()->NewNode(&kMockOpControl, start);
Node* success = graph()->NewNode(common.IfSuccess(), node);
Node* exception = graph()->NewNode(common.IfException(kNoHint), node);
Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node);
Node* use_control = graph()->NewNode(common.Merge(1), success);
Node* use_exception_value = graph()->NewNode(common.Return(), exception);
Node* replacement = graph()->NewNode(&kMockOperator);
......
......@@ -17,8 +17,16 @@ namespace compiler {
class NodePropertiesTest : public TestWithZone {
public:
Node* NewMockNode(const Operator* op, int input_count, Node** inputs) {
return Node::New(zone(), 0, op, input_count, inputs, false);
Node* NewMockNode(const Operator* op) {
return Node::New(zone(), 0, op, 0, nullptr, false);
}
Node* NewMockNode(const Operator* op, Node* n1) {
Node* nodes[] = {n1};
return Node::New(zone(), 0, op, arraysize(nodes), nodes, false);
}
Node* NewMockNode(const Operator* op, Node* n1, Node* n2) {
Node* nodes[] = {n1, n2};
return Node::New(zone(), 0, op, arraysize(nodes), nodes, false);
}
};
......@@ -29,26 +37,28 @@ const Operator kMockOperator(IrOpcode::kDead, Operator::kNoProperties,
const Operator kMockCallOperator(IrOpcode::kCall, Operator::kNoProperties,
"MockCallOperator", 0, 0, 0, 0, 0, 2);
const IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught;
} // namespace
TEST_F(NodePropertiesTest, ReplaceUses) {
CommonOperatorBuilder common(zone());
IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught;
Node* node = NewMockNode(&kMockOperator, 0, nullptr);
Node* use_value = NewMockNode(common.Return(), 1, &node);
Node* use_effect = NewMockNode(common.EffectPhi(1), 1, &node);
Node* use_success = NewMockNode(common.IfSuccess(), 1, &node);
Node* use_exception = NewMockNode(common.IfException(kNoHint), 1, &node);
Node* r_value = NewMockNode(&kMockOperator, 0, nullptr);
Node* r_effect = NewMockNode(&kMockOperator, 0, nullptr);
Node* r_success = NewMockNode(&kMockOperator, 0, nullptr);
Node* r_exception = NewMockNode(&kMockOperator, 0, nullptr);
Node* node = NewMockNode(&kMockOperator);
Node* effect = NewMockNode(&kMockOperator);
Node* use_value = NewMockNode(common.Return(), node);
Node* use_effect = NewMockNode(common.EffectPhi(1), node);
Node* use_success = NewMockNode(common.IfSuccess(), node);
Node* use_exception = NewMockNode(common.IfException(kNoHint), effect, node);
Node* r_value = NewMockNode(&kMockOperator);
Node* r_effect = NewMockNode(&kMockOperator);
Node* r_success = NewMockNode(&kMockOperator);
Node* r_exception = NewMockNode(&kMockOperator);
NodeProperties::ReplaceUses(node, r_value, r_effect, r_success, r_exception);
EXPECT_EQ(r_value, use_value->InputAt(0));
EXPECT_EQ(r_effect, use_effect->InputAt(0));
EXPECT_EQ(r_success, use_success->InputAt(0));
EXPECT_EQ(r_exception, use_exception->InputAt(0));
EXPECT_EQ(r_exception, use_exception->InputAt(1));
EXPECT_EQ(0, node->UseCount());
EXPECT_EQ(1, r_value->UseCount());
EXPECT_EQ(1, r_effect->UseCount());
......@@ -63,9 +73,9 @@ TEST_F(NodePropertiesTest, ReplaceUses) {
TEST_F(NodePropertiesTest, FindProjection) {
CommonOperatorBuilder common(zone());
Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false);
Node* proj0 = Node::New(zone(), 1, common.Projection(0), 1, &start, false);
Node* proj1 = Node::New(zone(), 2, common.Projection(1), 1, &start, false);
Node* start = NewMockNode(common.Start(1));
Node* proj0 = NewMockNode(common.Projection(0), start);
Node* proj1 = NewMockNode(common.Projection(1), start);
EXPECT_EQ(proj0, NodeProperties::FindProjection(start, 0));
EXPECT_EQ(proj1, NodeProperties::FindProjection(start, 1));
EXPECT_THAT(NodeProperties::FindProjection(start, 2), IsNull());
......@@ -76,9 +86,9 @@ TEST_F(NodePropertiesTest, FindProjection) {
TEST_F(NodePropertiesTest, CollectControlProjections_Branch) {
Node* result[2];
CommonOperatorBuilder common(zone());
Node* branch = Node::New(zone(), 1, common.Branch(), 0, nullptr, false);
Node* if_false = Node::New(zone(), 2, common.IfFalse(), 1, &branch, false);
Node* if_true = Node::New(zone(), 3, common.IfTrue(), 1, &branch, false);
Node* branch = NewMockNode(common.Branch());
Node* if_false = NewMockNode(common.IfFalse(), branch);
Node* if_true = NewMockNode(common.IfTrue(), branch);
NodeProperties::CollectControlProjections(branch, result, arraysize(result));
EXPECT_EQ(if_true, result[0]);
EXPECT_EQ(if_false, result[1]);
......@@ -88,10 +98,9 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Branch) {
TEST_F(NodePropertiesTest, CollectControlProjections_Call) {
Node* result[2];
CommonOperatorBuilder common(zone());
IfExceptionHint h = IfExceptionHint::kLocallyUncaught;
Node* call = Node::New(zone(), 1, &kMockCallOperator, 0, nullptr, false);
Node* if_ex = Node::New(zone(), 2, common.IfException(h), 1, &call, false);
Node* if_ok = Node::New(zone(), 3, common.IfSuccess(), 1, &call, false);
Node* call = NewMockNode(&kMockCallOperator);
Node* if_ex = NewMockNode(common.IfException(kNoHint), call, call);
Node* if_ok = NewMockNode(common.IfSuccess(), call);
NodeProperties::CollectControlProjections(call, result, arraysize(result));
EXPECT_EQ(if_ok, result[0]);
EXPECT_EQ(if_ex, result[1]);
......@@ -101,10 +110,10 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Call) {
TEST_F(NodePropertiesTest, CollectControlProjections_Switch) {
Node* result[3];
CommonOperatorBuilder common(zone());
Node* sw = Node::New(zone(), 1, common.Switch(3), 0, nullptr, false);
Node* if_default = Node::New(zone(), 2, common.IfDefault(), 1, &sw, false);
Node* if_value1 = Node::New(zone(), 3, common.IfValue(1), 1, &sw, false);
Node* if_value2 = Node::New(zone(), 4, common.IfValue(2), 1, &sw, false);
Node* sw = NewMockNode(common.Switch(3));
Node* if_default = NewMockNode(common.IfDefault(), sw);
Node* if_value1 = NewMockNode(common.IfValue(1), sw);
Node* if_value2 = NewMockNode(common.IfValue(2), sw);
NodeProperties::CollectControlProjections(sw, result, arraysize(result));
EXPECT_THAT(result[0], AnyOf(if_value1, if_value2));
EXPECT_THAT(result[1], AnyOf(if_value1, if_value2));
......
......@@ -1060,11 +1060,11 @@ TARGET_TEST_F(SchedulerTest, CallException) {
Node* c1 = graph()->NewNode(&kMockCall, start);
Node* ok1 = graph()->NewNode(common()->IfSuccess(), c1);
Node* ex1 = graph()->NewNode(
common()->IfException(IfExceptionHint::kLocallyUncaught), c1);
common()->IfException(IfExceptionHint::kLocallyUncaught), c1, c1);
Node* c2 = graph()->NewNode(&kMockCall, ok1);
Node* ok2 = graph()->NewNode(common()->IfSuccess(), c2);
Node* ex2 = graph()->NewNode(
common()->IfException(IfExceptionHint::kLocallyUncaught), c2);
common()->IfException(IfExceptionHint::kLocallyUncaught), c2, c2);
Node* hdl = graph()->NewNode(common()->Merge(2), ex1, ex2);
Node* m = graph()->NewNode(common()->Merge(2), ok2, hdl);
Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), c2, p0, m);
......
......@@ -60,7 +60,7 @@ TEST_F(TailCallOptimizationTest, CallCodeObject1) {
graph()->start(), graph()->start());
Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
Node* if_exception = graph()->NewNode(
common()->IfException(IfExceptionHint::kLocallyUncaught), call);
common()->IfException(IfExceptionHint::kLocallyUncaught), call, call);
Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
Node* end = graph()->NewNode(common()->End(1), if_exception);
graph()->SetEnd(end);
......@@ -126,7 +126,7 @@ TEST_F(TailCallOptimizationTest, CallJSFunction1) {
graph()->start(), graph()->start());
Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
Node* if_exception = graph()->NewNode(
common()->IfException(IfExceptionHint::kLocallyUncaught), call);
common()->IfException(IfExceptionHint::kLocallyUncaught), call, call);
Node* ret = graph()->NewNode(common()->Return(), call, call, if_success);
Node* end = graph()->NewNode(common()->End(1), if_exception);
graph()->SetEnd(end);
......
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