Commit a67b7aa2 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[turbofan] Only create Phis for live registers

In graph building, use liveness information to only create Phis
for live registers when merging two environments, or when preparing
a loop header. Similarly, only create loop exit value nodes for
live registers when exiting a loop.

Bug: v8:6701
Change-Id: Id6ac6a5518e6f1762530d871e92a46f42397928b
Reviewed-on: https://chromium-review.googlesource.com/615173
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47389}
parent 1a302730
...@@ -71,12 +71,14 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { ...@@ -71,12 +71,14 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
void SetContext(Node* new_context) { context_ = new_context; } void SetContext(Node* new_context) { context_ = new_context; }
Environment* Copy(); Environment* Copy();
void Merge(Environment* other); void Merge(Environment* other, const BytecodeLivenessState* liveness);
void FillWithOsrValues(); void FillWithOsrValues();
void PrepareForLoop(const BytecodeLoopAssignments& assignments); void PrepareForLoop(const BytecodeLoopAssignments& assignments,
const BytecodeLivenessState* liveness);
void PrepareForLoopExit(Node* loop, void PrepareForLoopExit(Node* loop,
const BytecodeLoopAssignments& assignments); const BytecodeLoopAssignments& assignments,
const BytecodeLivenessState* liveness);
private: private:
explicit Environment(const Environment* copy); explicit Environment(const Environment* copy);
...@@ -264,9 +266,9 @@ BytecodeGraphBuilder::Environment* BytecodeGraphBuilder::Environment::Copy() { ...@@ -264,9 +266,9 @@ BytecodeGraphBuilder::Environment* BytecodeGraphBuilder::Environment::Copy() {
return new (zone()) Environment(this); return new (zone()) Environment(this);
} }
void BytecodeGraphBuilder::Environment::Merge( void BytecodeGraphBuilder::Environment::Merge(
BytecodeGraphBuilder::Environment* other) { BytecodeGraphBuilder::Environment* other,
const BytecodeLivenessState* liveness) {
// Create a merge of the control dependencies of both environments and update // Create a merge of the control dependencies of both environments and update
// the current environment's control dependency accordingly. // the current environment's control dependency accordingly.
Node* control = builder()->MergeControl(GetControlDependency(), Node* control = builder()->MergeControl(GetControlDependency(),
...@@ -279,16 +281,44 @@ void BytecodeGraphBuilder::Environment::Merge( ...@@ -279,16 +281,44 @@ void BytecodeGraphBuilder::Environment::Merge(
other->GetEffectDependency(), control); other->GetEffectDependency(), control);
UpdateEffectDependency(effect); UpdateEffectDependency(effect);
// Introduce Phi nodes for values that have differing input at merge points, // Introduce Phi nodes for values that are live and have differing inputs at
// potentially extending an existing Phi node if possible. // the merge point, potentially extending an existing Phi node if possible.
context_ = builder()->MergeValue(context_, other->context_, control); context_ = builder()->MergeValue(context_, other->context_, control);
for (size_t i = 0; i < values_.size(); i++) { for (int i = 0; i < parameter_count(); i++) {
values_[i] = builder()->MergeValue(values_[i], other->values_[i], control); values_[i] = builder()->MergeValue(values_[i], other->values_[i], control);
} }
for (int i = 0; i < register_count(); i++) {
int index = register_base() + i;
if (liveness == nullptr || liveness->RegisterIsLive(i)) {
DCHECK_NE(values_[index], builder()->jsgraph()->OptimizedOutConstant());
DCHECK_NE(other->values_[index],
builder()->jsgraph()->OptimizedOutConstant());
values_[index] =
builder()->MergeValue(values_[index], other->values_[index], control);
} else {
values_[index] = builder()->jsgraph()->OptimizedOutConstant();
}
}
if (liveness == nullptr || liveness->AccumulatorIsLive()) {
DCHECK_NE(values_[accumulator_base()],
builder()->jsgraph()->OptimizedOutConstant());
DCHECK_NE(other->values_[accumulator_base()],
builder()->jsgraph()->OptimizedOutConstant());
values_[accumulator_base()] =
builder()->MergeValue(values_[accumulator_base()],
other->values_[accumulator_base()], control);
} else {
values_[accumulator_base()] = builder()->jsgraph()->OptimizedOutConstant();
}
} }
void BytecodeGraphBuilder::Environment::PrepareForLoop( void BytecodeGraphBuilder::Environment::PrepareForLoop(
const BytecodeLoopAssignments& assignments) { const BytecodeLoopAssignments& assignments,
const BytecodeLivenessState* liveness) {
// Create a control node for the loop header. // Create a control node for the loop header.
Node* control = builder()->NewLoop(); Node* control = builder()->NewLoop();
...@@ -296,7 +326,8 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop( ...@@ -296,7 +326,8 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop(
Node* effect = builder()->NewEffectPhi(1, GetEffectDependency(), control); Node* effect = builder()->NewEffectPhi(1, GetEffectDependency(), control);
UpdateEffectDependency(effect); UpdateEffectDependency(effect);
// Create Phis for any values that may be updated by the end of the loop. // Create Phis for any values that are live on entry to the loop and may be
// updated by the end of the loop.
context_ = builder()->NewPhi(1, context_, control); context_ = builder()->NewPhi(1, context_, control);
for (int i = 0; i < parameter_count(); i++) { for (int i = 0; i < parameter_count(); i++) {
if (assignments.ContainsParameter(i)) { if (assignments.ContainsParameter(i)) {
...@@ -304,11 +335,14 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop( ...@@ -304,11 +335,14 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop(
} }
} }
for (int i = 0; i < register_count(); i++) { for (int i = 0; i < register_count(); i++) {
if (assignments.ContainsLocal(i)) { if (assignments.ContainsLocal(i) &&
(liveness == nullptr || liveness->RegisterIsLive(i))) {
int index = register_base() + i; int index = register_base() + i;
values_[index] = builder()->NewPhi(1, values_[index], control); values_[index] = builder()->NewPhi(1, values_[index], control);
} }
} }
// The accumulator should not be live on entry.
DCHECK_IMPLIES(liveness != nullptr, !liveness->AccumulatorIsLive());
// Connect to the loop end. // Connect to the loop end.
Node* terminate = builder()->graph()->NewNode( Node* terminate = builder()->graph()->NewNode(
...@@ -347,7 +381,8 @@ bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate( ...@@ -347,7 +381,8 @@ bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate(
} }
void BytecodeGraphBuilder::Environment::PrepareForLoopExit( void BytecodeGraphBuilder::Environment::PrepareForLoopExit(
Node* loop, const BytecodeLoopAssignments& assignments) { Node* loop, const BytecodeLoopAssignments& assignments,
const BytecodeLivenessState* liveness) {
DCHECK_EQ(loop->opcode(), IrOpcode::kLoop); DCHECK_EQ(loop->opcode(), IrOpcode::kLoop);
Node* control = GetControlDependency(); Node* control = GetControlDependency();
...@@ -365,7 +400,8 @@ void BytecodeGraphBuilder::Environment::PrepareForLoopExit( ...@@ -365,7 +400,8 @@ void BytecodeGraphBuilder::Environment::PrepareForLoopExit(
// renaming confuses global object and native context specialization. // renaming confuses global object and native context specialization.
// We should only rename if the context is assigned in the loop. // We should only rename if the context is assigned in the loop.
// Rename the environment values if they were assigned in the loop. // Rename the environment values if they were assigned in the loop and are
// live after exiting the loop.
for (int i = 0; i < parameter_count(); i++) { for (int i = 0; i < parameter_count(); i++) {
if (assignments.ContainsParameter(i)) { if (assignments.ContainsParameter(i)) {
Node* rename = Node* rename =
...@@ -374,12 +410,18 @@ void BytecodeGraphBuilder::Environment::PrepareForLoopExit( ...@@ -374,12 +410,18 @@ void BytecodeGraphBuilder::Environment::PrepareForLoopExit(
} }
} }
for (int i = 0; i < register_count(); i++) { for (int i = 0; i < register_count(); i++) {
if (assignments.ContainsLocal(i)) { if (assignments.ContainsLocal(i) &&
(liveness == nullptr || liveness->RegisterIsLive(i))) {
Node* rename = graph()->NewNode(common()->LoopExitValue(), Node* rename = graph()->NewNode(common()->LoopExitValue(),
values_[register_base() + i], loop_exit); values_[register_base() + i], loop_exit);
values_[register_base() + i] = rename; values_[register_base() + i] = rename;
} }
} }
if (liveness == nullptr || liveness->AccumulatorIsLive()) {
Node* rename = graph()->NewNode(common()->LoopExitValue(),
values_[accumulator_base()], loop_exit);
values_[accumulator_base()] = rename;
}
} }
void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values,
...@@ -416,8 +458,9 @@ Node* BytecodeGraphBuilder::Environment::Checkpoint( ...@@ -416,8 +458,9 @@ Node* BytecodeGraphBuilder::Environment::Checkpoint(
bool accumulator_is_live = !liveness || liveness->AccumulatorIsLive(); bool accumulator_is_live = !liveness || liveness->AccumulatorIsLive();
Node* accumulator_state_value = Node* accumulator_state_value =
accumulator_is_live ? values()->at(accumulator_base()) accumulator_is_live && combine != OutputFrameStateCombine::PokeAt(0)
: builder()->jsgraph()->OptimizedOutConstant(); ? values()->at(accumulator_base())
: builder()->jsgraph()->OptimizedOutConstant();
const Operator* op = common()->FrameState( const Operator* op = common()->FrameState(
bailout_id, combine, builder()->frame_state_function_info()); bailout_id, combine, builder()->frame_state_function_info());
...@@ -1060,7 +1103,9 @@ BytecodeGraphBuilder::Environment* BytecodeGraphBuilder::CheckContextExtensions( ...@@ -1060,7 +1103,9 @@ BytecodeGraphBuilder::Environment* BytecodeGraphBuilder::CheckContextExtensions(
slow_environment = environment(); slow_environment = environment();
NewMerge(); NewMerge();
} else { } else {
slow_environment->Merge(environment()); slow_environment->Merge(environment(),
bytecode_analysis()->GetInLivenessFor(
bytecode_iterator().current_offset()));
} }
} }
...@@ -1110,7 +1155,9 @@ void BytecodeGraphBuilder::BuildLdaLookupContextSlot(TypeofMode typeof_mode) { ...@@ -1110,7 +1155,9 @@ void BytecodeGraphBuilder::BuildLdaLookupContextSlot(TypeofMode typeof_mode) {
environment()->BindAccumulator(value, Environment::kAttachFrameState); environment()->BindAccumulator(value, Environment::kAttachFrameState);
} }
fast_environment->Merge(environment()); fast_environment->Merge(environment(),
bytecode_analysis()->GetOutLivenessFor(
bytecode_iterator().current_offset()));
set_environment(fast_environment); set_environment(fast_environment);
mark_as_needing_eager_checkpoint(true); mark_as_needing_eager_checkpoint(true);
} }
...@@ -1160,7 +1207,9 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) { ...@@ -1160,7 +1207,9 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) {
environment()->BindAccumulator(value, Environment::kAttachFrameState); environment()->BindAccumulator(value, Environment::kAttachFrameState);
} }
fast_environment->Merge(environment()); fast_environment->Merge(environment(),
bytecode_analysis()->GetOutLivenessFor(
bytecode_iterator().current_offset()));
set_environment(fast_environment); set_environment(fast_environment);
mark_as_needing_eager_checkpoint(true); mark_as_needing_eager_checkpoint(true);
} }
...@@ -1851,7 +1900,8 @@ void BytecodeGraphBuilder::VisitInvokeIntrinsic() { ...@@ -1851,7 +1900,8 @@ void BytecodeGraphBuilder::VisitInvokeIntrinsic() {
} }
void BytecodeGraphBuilder::VisitThrow() { void BytecodeGraphBuilder::VisitThrow() {
BuildLoopExitsForFunctionExit(); BuildLoopExitsForFunctionExit(bytecode_analysis()->GetOutLivenessFor(
bytecode_iterator().current_offset()));
Node* value = environment()->LookupAccumulator(); Node* value = environment()->LookupAccumulator();
Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value); Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value);
environment()->BindAccumulator(call, Environment::kAttachFrameState); environment()->BindAccumulator(call, Environment::kAttachFrameState);
...@@ -1860,7 +1910,8 @@ void BytecodeGraphBuilder::VisitThrow() { ...@@ -1860,7 +1910,8 @@ void BytecodeGraphBuilder::VisitThrow() {
} }
void BytecodeGraphBuilder::VisitReThrow() { void BytecodeGraphBuilder::VisitReThrow() {
BuildLoopExitsForFunctionExit(); BuildLoopExitsForFunctionExit(bytecode_analysis()->GetOutLivenessFor(
bytecode_iterator().current_offset()));
Node* value = environment()->LookupAccumulator(); Node* value = environment()->LookupAccumulator();
NewNode(javascript()->CallRuntime(Runtime::kReThrow), value); NewNode(javascript()->CallRuntime(Runtime::kReThrow), value);
Node* control = NewNode(common()->Throw()); Node* control = NewNode(common()->Throw());
...@@ -2429,7 +2480,8 @@ void BytecodeGraphBuilder::VisitSetPendingMessage() { ...@@ -2429,7 +2480,8 @@ void BytecodeGraphBuilder::VisitSetPendingMessage() {
} }
void BytecodeGraphBuilder::VisitReturn() { void BytecodeGraphBuilder::VisitReturn() {
BuildLoopExitsForFunctionExit(); BuildLoopExitsForFunctionExit(bytecode_analysis()->GetInLivenessFor(
bytecode_iterator().current_offset()));
Node* pop_node = jsgraph()->ZeroConstant(); Node* pop_node = jsgraph()->ZeroConstant();
Node* control = Node* control =
NewNode(common()->Return(), pop_node, environment()->LookupAccumulator()); NewNode(common()->Return(), pop_node, environment()->LookupAccumulator());
...@@ -2588,7 +2640,8 @@ void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) { ...@@ -2588,7 +2640,8 @@ void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) {
if (it != merge_environments_.end()) { if (it != merge_environments_.end()) {
mark_as_needing_eager_checkpoint(true); mark_as_needing_eager_checkpoint(true);
if (environment() != nullptr) { if (environment() != nullptr) {
it->second->Merge(environment()); it->second->Merge(environment(),
bytecode_analysis()->GetInLivenessFor(current_offset));
} }
set_environment(it->second); set_environment(it->second);
} }
...@@ -2599,9 +2652,11 @@ void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) { ...@@ -2599,9 +2652,11 @@ void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) {
mark_as_needing_eager_checkpoint(true); mark_as_needing_eager_checkpoint(true);
const LoopInfo& loop_info = const LoopInfo& loop_info =
bytecode_analysis()->GetLoopInfoFor(current_offset); bytecode_analysis()->GetLoopInfoFor(current_offset);
const BytecodeLivenessState* liveness =
bytecode_analysis()->GetInLivenessFor(current_offset);
// Add loop header. // Add loop header.
environment()->PrepareForLoop(loop_info.assignments()); environment()->PrepareForLoop(loop_info.assignments(), liveness);
// Store a copy of the environment so we can connect merged back edge inputs // Store a copy of the environment so we can connect merged back edge inputs
// to the loop header. // to the loop header.
...@@ -2621,7 +2676,9 @@ void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) { ...@@ -2621,7 +2676,9 @@ void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) {
NewMerge(); NewMerge();
merge_environment = environment(); merge_environment = environment();
} else { } else {
merge_environment->Merge(environment()); // Merge any values which are live coming into the successor.
merge_environment->Merge(
environment(), bytecode_analysis()->GetInLivenessFor(target_offset));
} }
set_environment(nullptr); set_environment(nullptr);
} }
...@@ -2636,11 +2693,13 @@ void BytecodeGraphBuilder::BuildLoopExitsForBranch(int target_offset) { ...@@ -2636,11 +2693,13 @@ void BytecodeGraphBuilder::BuildLoopExitsForBranch(int target_offset) {
// Only build loop exits for forward edges. // Only build loop exits for forward edges.
if (target_offset > origin_offset) { if (target_offset > origin_offset) {
BuildLoopExitsUntilLoop( BuildLoopExitsUntilLoop(
bytecode_analysis()->GetLoopOffsetFor(target_offset)); bytecode_analysis()->GetLoopOffsetFor(target_offset),
bytecode_analysis()->GetInLivenessFor(target_offset));
} }
} }
void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) { void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(
int loop_offset, const BytecodeLivenessState* liveness) {
int origin_offset = bytecode_iterator().current_offset(); int origin_offset = bytecode_iterator().current_offset();
int current_loop = bytecode_analysis()->GetLoopOffsetFor(origin_offset); int current_loop = bytecode_analysis()->GetLoopOffsetFor(origin_offset);
// The limit_offset is the stop offset for building loop exists, used for OSR. // The limit_offset is the stop offset for building loop exists, used for OSR.
...@@ -2651,13 +2710,15 @@ void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) { ...@@ -2651,13 +2710,15 @@ void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) {
Node* loop_node = merge_environments_[current_loop]->GetControlDependency(); Node* loop_node = merge_environments_[current_loop]->GetControlDependency();
const LoopInfo& loop_info = const LoopInfo& loop_info =
bytecode_analysis()->GetLoopInfoFor(current_loop); bytecode_analysis()->GetLoopInfoFor(current_loop);
environment()->PrepareForLoopExit(loop_node, loop_info.assignments()); environment()->PrepareForLoopExit(loop_node, loop_info.assignments(),
liveness);
current_loop = loop_info.parent_offset(); current_loop = loop_info.parent_offset();
} }
} }
void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit() { void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit(
BuildLoopExitsUntilLoop(-1); const BytecodeLivenessState* liveness) {
BuildLoopExitsUntilLoop(-1, liveness);
} }
void BytecodeGraphBuilder::BuildJump() { void BytecodeGraphBuilder::BuildJump() {
......
...@@ -242,8 +242,9 @@ class BytecodeGraphBuilder { ...@@ -242,8 +242,9 @@ class BytecodeGraphBuilder {
// Builds loop exit nodes for every exited loop between the current bytecode // Builds loop exit nodes for every exited loop between the current bytecode
// offset and {target_offset}. // offset and {target_offset}.
void BuildLoopExitsForBranch(int target_offset); void BuildLoopExitsForBranch(int target_offset);
void BuildLoopExitsForFunctionExit(); void BuildLoopExitsForFunctionExit(const BytecodeLivenessState* liveness);
void BuildLoopExitsUntilLoop(int loop_offset); void BuildLoopExitsUntilLoop(int loop_offset,
const BytecodeLivenessState* liveness);
// Simulates entry and exit of exception handlers. // Simulates entry and exit of exception handlers.
void ExitThenEnterExceptionHandlers(int current_offset); void ExitThenEnterExceptionHandlers(int current_offset);
......
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