[turbofan] add Terminate nodes to all loops
This simplifies the existing invariant and enables loop-peeling on all loops. The main motivation is that it enables dead code elimination to always eagerly fold away branches even when this would create infinite loops. Bug: Change-Id: If4347f748f8d8735965771f66260a8f931b24132 Reviewed-on: https://chromium-review.googlesource.com/763531 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#49387}
This commit is contained in:
parent
aafdfba899
commit
0cdd84e230
@ -285,6 +285,9 @@ void GraphAssembler::MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label,
|
||||
current_control_);
|
||||
label->effect_ = graph()->NewNode(common()->EffectPhi(2), current_effect_,
|
||||
current_effect_, label->control_);
|
||||
Node* terminate = graph()->NewNode(common()->Terminate(), label->effect_,
|
||||
label->control_);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
for (size_t i = 0; i < sizeof...(vars); i++) {
|
||||
label->bindings_[i] = graph()->NewNode(
|
||||
common()->Phi(label->representations_[i], 2), var_array[i + 1],
|
||||
|
@ -1183,6 +1183,8 @@ Reduction JSBuiltinReducer::ReduceArrayShift(Node* node) {
|
||||
Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1);
|
||||
Node* eloop =
|
||||
graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop);
|
||||
Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
Node* index = graph()->NewNode(
|
||||
common()->Phi(MachineRepresentation::kTagged, 2),
|
||||
jsgraph()->OneConstant(),
|
||||
@ -1414,6 +1416,8 @@ Reduction JSBuiltinReducer::ReduceCollectionIteratorNext(
|
||||
graph()->NewNode(common()->Loop(2), control, control);
|
||||
Node* eloop = effect =
|
||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
||||
Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
|
||||
// Check if reached the final table of the {receiver}.
|
||||
Node* table = effect = graph()->NewNode(
|
||||
@ -1502,6 +1506,8 @@ Reduction JSBuiltinReducer::ReduceCollectionIteratorNext(
|
||||
Node* loop = graph()->NewNode(common()->Loop(2), control, control);
|
||||
Node* eloop =
|
||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
||||
Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
Node* iloop = graph()->NewNode(
|
||||
common()->Phi(MachineRepresentation::kTagged, 2), index, index, loop);
|
||||
NodeProperties::SetType(iloop, type_cache_.kFixedArrayLengthType);
|
||||
|
@ -935,6 +935,8 @@ Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
|
||||
Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
|
||||
Node* eloop = effect =
|
||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
||||
Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
Node* vloop = k = graph()->NewNode(
|
||||
common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
|
||||
checkpoint_params[3] = k;
|
||||
@ -1032,9 +1034,9 @@ Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
|
||||
// Since {check_throw} is an unconditional throw, it's impossible to
|
||||
// return a successful completion. Therefore, we simply connect the successful
|
||||
// completion to the graph end.
|
||||
Node* terminate =
|
||||
Node* throw_node =
|
||||
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
|
||||
|
||||
ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect, control);
|
||||
return Replace(jsgraph()->UndefinedConstant());
|
||||
@ -1135,6 +1137,8 @@ Reduction JSCallReducer::ReduceArrayMap(Handle<JSFunction> function,
|
||||
Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
|
||||
Node* eloop = effect =
|
||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
||||
Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
Node* vloop = k = graph()->NewNode(
|
||||
common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
|
||||
checkpoint_params[4] = k;
|
||||
@ -1208,9 +1212,9 @@ Reduction JSCallReducer::ReduceArrayMap(Handle<JSFunction> function,
|
||||
// Since {check_throw} is an unconditional throw, it's impossible to
|
||||
// return a successful completion. Therefore, we simply connect the successful
|
||||
// completion to the graph end.
|
||||
Node* terminate =
|
||||
Node* throw_node =
|
||||
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
|
||||
|
||||
ReplaceWithValue(node, a, effect, control);
|
||||
return Replace(a);
|
||||
@ -1323,6 +1327,8 @@ Reduction JSCallReducer::ReduceArrayFilter(Handle<JSFunction> function,
|
||||
Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
|
||||
Node* eloop = effect =
|
||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
||||
Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
Node* vloop = k = graph()->NewNode(
|
||||
common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
|
||||
Node* v_to_loop = to = graph()->NewNode(
|
||||
@ -1429,9 +1435,9 @@ Reduction JSCallReducer::ReduceArrayFilter(Handle<JSFunction> function,
|
||||
// Since {check_throw} is an unconditional throw, it's impossible to
|
||||
// return a successful completion. Therefore, we simply connect the successful
|
||||
// completion to the graph end.
|
||||
Node* terminate =
|
||||
Node* throw_node =
|
||||
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
|
||||
|
||||
ReplaceWithValue(node, a, effect, control);
|
||||
return Replace(a);
|
||||
@ -1881,9 +1887,9 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
|
||||
// The above %ThrowTypeError runtime call is an unconditional throw, making
|
||||
// it impossible to return a successful completion in this case. We simply
|
||||
// connect the successful completion to the graph end.
|
||||
Node* terminate =
|
||||
Node* throw_node =
|
||||
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
|
||||
|
||||
Reduction const reduction = ReduceJSConstruct(node);
|
||||
return reduction.Changed() ? reduction : Changed(node);
|
||||
|
@ -1113,6 +1113,8 @@ Reduction JSTypedLowering::ReduceJSHasInPrototypeChain(Node* node) {
|
||||
Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
|
||||
Node* eloop = effect =
|
||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
||||
Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
||||
Node* vloop = value = graph()->NewNode(
|
||||
common()->Phi(MachineRepresentation::kTagged, 2), value, value, loop);
|
||||
NodeProperties::SetType(vloop, Type::NonInternal());
|
||||
|
@ -316,7 +316,22 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
// Type is empty.
|
||||
CheckNotTyped(node);
|
||||
break;
|
||||
case IrOpcode::kLoop:
|
||||
case IrOpcode::kLoop: {
|
||||
CHECK_EQ(control_count, input_count);
|
||||
// Type is empty.
|
||||
CheckNotTyped(node);
|
||||
// All loops need to be connected to a {Terminate} node to ensure they
|
||||
// stay connected to the graph end.
|
||||
bool has_terminate = false;
|
||||
for (const Node* use : node->uses()) {
|
||||
if (use->opcode() == IrOpcode::kTerminate) {
|
||||
has_terminate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK(has_terminate);
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kMerge:
|
||||
CHECK_EQ(control_count, input_count);
|
||||
// Type is empty.
|
||||
|
Loading…
Reference in New Issue
Block a user