[Turboprop] Allow removal of multiple unreachable blocks that merge.
The scheduler could schedule unreachable nodes on two basic blocks that later merge. Update DCHECK in graph-assembler's basic block updater to only check for the self-containedness of unreachable basic blocks removed from the schedule after all the blocks have been re-written to allow for this case. BUG=chromium:1079446,v8:9684 Change-Id: I91899dbf389e4425542dbd2b1ca95c3f6ad79c05 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2196354 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Commit-Queue: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#67812}
This commit is contained in:
parent
8686ea8121
commit
d9828e4553
@ -21,6 +21,7 @@ class GraphAssembler::BasicBlockUpdater {
|
|||||||
public:
|
public:
|
||||||
BasicBlockUpdater(Schedule* schedule, Graph* graph,
|
BasicBlockUpdater(Schedule* schedule, Graph* graph,
|
||||||
CommonOperatorBuilder* common, Zone* temp_zone);
|
CommonOperatorBuilder* common, Zone* temp_zone);
|
||||||
|
~BasicBlockUpdater();
|
||||||
|
|
||||||
Node* AddNode(Node* node);
|
Node* AddNode(Node* node);
|
||||||
Node* AddNode(Node* node, BasicBlock* to);
|
Node* AddNode(Node* node, BasicBlock* to);
|
||||||
@ -85,6 +86,9 @@ class GraphAssembler::BasicBlockUpdater {
|
|||||||
bool original_deferred_;
|
bool original_deferred_;
|
||||||
size_t original_node_count_;
|
size_t original_node_count_;
|
||||||
|
|
||||||
|
// Blocks which have been removed from the schedule due to being unreachable.
|
||||||
|
ZoneSet<BasicBlock*> unreachable_blocks_;
|
||||||
|
|
||||||
State state_;
|
State state_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,8 +107,20 @@ GraphAssembler::BasicBlockUpdater::BasicBlockUpdater(
|
|||||||
original_control_input_(nullptr),
|
original_control_input_(nullptr),
|
||||||
original_deferred_(false),
|
original_deferred_(false),
|
||||||
original_node_count_(graph->NodeCount()),
|
original_node_count_(graph->NodeCount()),
|
||||||
|
unreachable_blocks_(temp_zone),
|
||||||
state_(kUnchanged) {}
|
state_(kUnchanged) {}
|
||||||
|
|
||||||
|
GraphAssembler::BasicBlockUpdater::~BasicBlockUpdater() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Ensure that the set of blocks being removed from the schedule are self
|
||||||
|
// contained, i.e., all predecessors have been removed from these blocks.
|
||||||
|
for (BasicBlock* block : unreachable_blocks_) {
|
||||||
|
CHECK_EQ(block->PredecessorCount(), 0);
|
||||||
|
CHECK_EQ(block->SuccessorCount(), 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Node* GraphAssembler::BasicBlockUpdater::AddNode(Node* node) {
|
Node* GraphAssembler::BasicBlockUpdater::AddNode(Node* node) {
|
||||||
return AddNode(node, current_block_);
|
return AddNode(node, current_block_);
|
||||||
}
|
}
|
||||||
@ -269,13 +285,12 @@ void GraphAssembler::BasicBlockUpdater::AddGoto(BasicBlock* from,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GraphAssembler::BasicBlockUpdater::RemoveSuccessorsFromSchedule() {
|
void GraphAssembler::BasicBlockUpdater::RemoveSuccessorsFromSchedule() {
|
||||||
ZoneSet<BasicBlock*> blocks(temp_zone());
|
|
||||||
ZoneQueue<BasicBlock*> worklist(temp_zone());
|
ZoneQueue<BasicBlock*> worklist(temp_zone());
|
||||||
|
|
||||||
for (SuccessorInfo succ : saved_successors_) {
|
for (SuccessorInfo succ : saved_successors_) {
|
||||||
BasicBlock* block = succ.block;
|
BasicBlock* block = succ.block;
|
||||||
block->predecessors().erase(block->predecessors().begin() + succ.index);
|
block->predecessors().erase(block->predecessors().begin() + succ.index);
|
||||||
blocks.insert(block);
|
unreachable_blocks_.insert(block);
|
||||||
worklist.push(block);
|
worklist.push(block);
|
||||||
}
|
}
|
||||||
saved_successors_.clear();
|
saved_successors_.clear();
|
||||||
@ -283,10 +298,10 @@ void GraphAssembler::BasicBlockUpdater::RemoveSuccessorsFromSchedule() {
|
|||||||
// Walk through blocks until we get to the end node, then remove the path from
|
// Walk through blocks until we get to the end node, then remove the path from
|
||||||
// end, clearing their successors / predecessors.
|
// end, clearing their successors / predecessors.
|
||||||
// This works because the unreachable paths form self-contained control flow
|
// This works because the unreachable paths form self-contained control flow
|
||||||
// that doesn't re-merge with reachable control flow (checked below) and
|
// that doesn't re-merge with reachable control flow (checked in the
|
||||||
// DeadCodeElimination::ReduceEffectPhi preventing Unreachable from going into
|
// destructor) and DeadCodeElimination::ReduceEffectPhi preventing Unreachable
|
||||||
// an effect-phi. We would need to extend this if we need the ability to mark
|
// from going into an effect-phi. We would need to extend this if we need the
|
||||||
// control flow as unreachable later in the pipeline.
|
// ability to mark control flow as unreachable later in the pipeline.
|
||||||
while (!worklist.empty()) {
|
while (!worklist.empty()) {
|
||||||
BasicBlock* current = worklist.front();
|
BasicBlock* current = worklist.front();
|
||||||
worklist.pop();
|
worklist.pop();
|
||||||
@ -306,22 +321,13 @@ void GraphAssembler::BasicBlockUpdater::RemoveSuccessorsFromSchedule() {
|
|||||||
current->control_input());
|
current->control_input());
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, add successor to worklist if it's not already been seen.
|
// Otherwise, add successor to worklist if it's not already been seen.
|
||||||
if (blocks.insert(successor).second) {
|
if (unreachable_blocks_.insert(successor).second) {
|
||||||
worklist.push(successor);
|
worklist.push(successor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current->ClearSuccessors();
|
current->ClearSuccessors();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
// Ensure that the set of blocks being removed from the schedule are self
|
|
||||||
// contained, i.e., all predecessors have been removed from these blocks.
|
|
||||||
for (BasicBlock* block : blocks) {
|
|
||||||
CHECK_EQ(block->PredecessorCount(), 0);
|
|
||||||
CHECK_EQ(block->SuccessorCount(), 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphAssembler::BasicBlockUpdater::AddThrow(Node* node) {
|
void GraphAssembler::BasicBlockUpdater::AddThrow(Node* node) {
|
||||||
|
17
test/mjsunit/regress/regress-1079446.js
Normal file
17
test/mjsunit/regress/regress-1079446.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax --turboprop
|
||||||
|
|
||||||
|
arr = new Int16Array();
|
||||||
|
function foo() {
|
||||||
|
arr.__defineGetter__('a', function() { });
|
||||||
|
arr[0] = "123.12";
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(foo);
|
||||||
|
foo();
|
||||||
|
foo();
|
||||||
|
%OptimizeFunctionOnNextCall(foo);
|
||||||
|
foo();
|
Loading…
Reference in New Issue
Block a user