[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_);
|
current_control_);
|
||||||
label->effect_ = graph()->NewNode(common()->EffectPhi(2), current_effect_,
|
label->effect_ = graph()->NewNode(common()->EffectPhi(2), current_effect_,
|
||||||
current_effect_, label->control_);
|
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++) {
|
for (size_t i = 0; i < sizeof...(vars); i++) {
|
||||||
label->bindings_[i] = graph()->NewNode(
|
label->bindings_[i] = graph()->NewNode(
|
||||||
common()->Phi(label->representations_[i], 2), var_array[i + 1],
|
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* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1);
|
||||||
Node* eloop =
|
Node* eloop =
|
||||||
graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop);
|
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(
|
Node* index = graph()->NewNode(
|
||||||
common()->Phi(MachineRepresentation::kTagged, 2),
|
common()->Phi(MachineRepresentation::kTagged, 2),
|
||||||
jsgraph()->OneConstant(),
|
jsgraph()->OneConstant(),
|
||||||
@ -1414,6 +1416,8 @@ Reduction JSBuiltinReducer::ReduceCollectionIteratorNext(
|
|||||||
graph()->NewNode(common()->Loop(2), control, control);
|
graph()->NewNode(common()->Loop(2), control, control);
|
||||||
Node* eloop = effect =
|
Node* eloop = effect =
|
||||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
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}.
|
// Check if reached the final table of the {receiver}.
|
||||||
Node* table = effect = graph()->NewNode(
|
Node* table = effect = graph()->NewNode(
|
||||||
@ -1502,6 +1506,8 @@ Reduction JSBuiltinReducer::ReduceCollectionIteratorNext(
|
|||||||
Node* loop = graph()->NewNode(common()->Loop(2), control, control);
|
Node* loop = graph()->NewNode(common()->Loop(2), control, control);
|
||||||
Node* eloop =
|
Node* eloop =
|
||||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
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(
|
Node* iloop = graph()->NewNode(
|
||||||
common()->Phi(MachineRepresentation::kTagged, 2), index, index, loop);
|
common()->Phi(MachineRepresentation::kTagged, 2), index, index, loop);
|
||||||
NodeProperties::SetType(iloop, type_cache_.kFixedArrayLengthType);
|
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* loop = control = graph()->NewNode(common()->Loop(2), control, control);
|
||||||
Node* eloop = effect =
|
Node* eloop = effect =
|
||||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
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(
|
Node* vloop = k = graph()->NewNode(
|
||||||
common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
|
common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
|
||||||
checkpoint_params[3] = k;
|
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
|
// Since {check_throw} is an unconditional throw, it's impossible to
|
||||||
// return a successful completion. Therefore, we simply connect the successful
|
// return a successful completion. Therefore, we simply connect the successful
|
||||||
// completion to the graph end.
|
// completion to the graph end.
|
||||||
Node* terminate =
|
Node* throw_node =
|
||||||
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
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);
|
ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect, control);
|
||||||
return Replace(jsgraph()->UndefinedConstant());
|
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* loop = control = graph()->NewNode(common()->Loop(2), control, control);
|
||||||
Node* eloop = effect =
|
Node* eloop = effect =
|
||||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
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(
|
Node* vloop = k = graph()->NewNode(
|
||||||
common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
|
common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
|
||||||
checkpoint_params[4] = k;
|
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
|
// Since {check_throw} is an unconditional throw, it's impossible to
|
||||||
// return a successful completion. Therefore, we simply connect the successful
|
// return a successful completion. Therefore, we simply connect the successful
|
||||||
// completion to the graph end.
|
// completion to the graph end.
|
||||||
Node* terminate =
|
Node* throw_node =
|
||||||
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
||||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
|
||||||
|
|
||||||
ReplaceWithValue(node, a, effect, control);
|
ReplaceWithValue(node, a, effect, control);
|
||||||
return Replace(a);
|
return Replace(a);
|
||||||
@ -1323,6 +1327,8 @@ Reduction JSCallReducer::ReduceArrayFilter(Handle<JSFunction> function,
|
|||||||
Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
|
Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
|
||||||
Node* eloop = effect =
|
Node* eloop = effect =
|
||||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
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(
|
Node* vloop = k = graph()->NewNode(
|
||||||
common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
|
common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop);
|
||||||
Node* v_to_loop = to = graph()->NewNode(
|
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
|
// Since {check_throw} is an unconditional throw, it's impossible to
|
||||||
// return a successful completion. Therefore, we simply connect the successful
|
// return a successful completion. Therefore, we simply connect the successful
|
||||||
// completion to the graph end.
|
// completion to the graph end.
|
||||||
Node* terminate =
|
Node* throw_node =
|
||||||
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
||||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
|
||||||
|
|
||||||
ReplaceWithValue(node, a, effect, control);
|
ReplaceWithValue(node, a, effect, control);
|
||||||
return Replace(a);
|
return Replace(a);
|
||||||
@ -1881,9 +1887,9 @@ Reduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread(
|
|||||||
// The above %ThrowTypeError runtime call is an unconditional throw, making
|
// The above %ThrowTypeError runtime call is an unconditional throw, making
|
||||||
// it impossible to return a successful completion in this case. We simply
|
// it impossible to return a successful completion in this case. We simply
|
||||||
// connect the successful completion to the graph end.
|
// connect the successful completion to the graph end.
|
||||||
Node* terminate =
|
Node* throw_node =
|
||||||
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
graph()->NewNode(common()->Throw(), check_throw, check_fail);
|
||||||
NodeProperties::MergeControlToEnd(graph(), common(), terminate);
|
NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
|
||||||
|
|
||||||
Reduction const reduction = ReduceJSConstruct(node);
|
Reduction const reduction = ReduceJSConstruct(node);
|
||||||
return reduction.Changed() ? reduction : Changed(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* loop = control = graph()->NewNode(common()->Loop(2), control, control);
|
||||||
Node* eloop = effect =
|
Node* eloop = effect =
|
||||||
graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
|
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(
|
Node* vloop = value = graph()->NewNode(
|
||||||
common()->Phi(MachineRepresentation::kTagged, 2), value, value, loop);
|
common()->Phi(MachineRepresentation::kTagged, 2), value, value, loop);
|
||||||
NodeProperties::SetType(vloop, Type::NonInternal());
|
NodeProperties::SetType(vloop, Type::NonInternal());
|
||||||
|
@ -316,7 +316,22 @@ void Verifier::Visitor::Check(Node* node) {
|
|||||||
// Type is empty.
|
// Type is empty.
|
||||||
CheckNotTyped(node);
|
CheckNotTyped(node);
|
||||||
break;
|
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:
|
case IrOpcode::kMerge:
|
||||||
CHECK_EQ(control_count, input_count);
|
CHECK_EQ(control_count, input_count);
|
||||||
// Type is empty.
|
// Type is empty.
|
||||||
|
Loading…
Reference in New Issue
Block a user