Fixing CFG to remove unreachable blocks and properly maintain dominators.
This commit is contained in:
parent
10e8d0bd9b
commit
889f29c18a
|
@ -31,9 +31,21 @@ ControlFlowSimplificationPass::ControlFlowSimplificationPass()
|
||||||
ControlFlowSimplificationPass::~ControlFlowSimplificationPass() {}
|
ControlFlowSimplificationPass::~ControlFlowSimplificationPass() {}
|
||||||
|
|
||||||
bool ControlFlowSimplificationPass::Run(HIRBuilder* builder) {
|
bool ControlFlowSimplificationPass::Run(HIRBuilder* builder) {
|
||||||
|
// Walk forwards and kill any unreachable blocks.
|
||||||
|
// Do this before merging.
|
||||||
|
auto block = builder->first_block();
|
||||||
|
while (block) {
|
||||||
|
auto next_block = block->next;
|
||||||
|
if (!block->incoming_edge_head && block->prev) {
|
||||||
|
// Block is in the interior and has no incoming edges - kill it.
|
||||||
|
builder->RemoveBlock(block);
|
||||||
|
}
|
||||||
|
block = next_block;
|
||||||
|
}
|
||||||
|
|
||||||
// Walk backwards and merge blocks if possible.
|
// Walk backwards and merge blocks if possible.
|
||||||
bool merged_any = false;
|
bool merged_any = false;
|
||||||
auto block = builder->last_block();
|
block = builder->last_block();
|
||||||
while (block) {
|
while (block) {
|
||||||
auto prev_block = block->prev;
|
auto prev_block = block->prev;
|
||||||
const uint32_t expected = Edge::DOMINATES | Edge::UNCONDITIONAL;
|
const uint32_t expected = Edge::DOMINATES | Edge::UNCONDITIONAL;
|
||||||
|
|
|
@ -50,7 +50,6 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
|
||||||
// The CFG is required for simplification and dirtied by it.
|
// The CFG is required for simplification and dirtied by it.
|
||||||
compiler_->AddPass(std::make_unique<passes::ControlFlowAnalysisPass>());
|
compiler_->AddPass(std::make_unique<passes::ControlFlowAnalysisPass>());
|
||||||
compiler_->AddPass(std::make_unique<passes::ControlFlowSimplificationPass>());
|
compiler_->AddPass(std::make_unique<passes::ControlFlowSimplificationPass>());
|
||||||
compiler_->AddPass(std::make_unique<passes::ControlFlowAnalysisPass>());
|
|
||||||
|
|
||||||
// Passes are executed in the order they are added. Multiple of the same
|
// Passes are executed in the order they are added. Multiple of the same
|
||||||
// pass type may be used.
|
// pass type may be used.
|
||||||
|
|
|
@ -379,6 +379,8 @@ void HIRBuilder::InsertLabel(Label* label, Instr* prev_instr) {
|
||||||
Block* next_block = prev_instr->block->next;
|
Block* next_block = prev_instr->block->next;
|
||||||
|
|
||||||
Block* new_block = arena_->Alloc<Block>();
|
Block* new_block = arena_->Alloc<Block>();
|
||||||
|
new_block->ordinal = -1;
|
||||||
|
new_block->incoming_values = nullptr;
|
||||||
new_block->arena = arena_;
|
new_block->arena = arena_;
|
||||||
new_block->prev = prev_block;
|
new_block->prev = prev_block;
|
||||||
new_block->next = next_block;
|
new_block->next = next_block;
|
||||||
|
@ -433,16 +435,96 @@ void HIRBuilder::ResetLabelTags() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIRBuilder::AddEdge(Block* src, Block* dest, uint32_t flags) {
|
void HIRBuilder::AddEdge(Block* src, Block* dest, uint32_t flags) {
|
||||||
|
bool dest_was_dominated =
|
||||||
|
dest->incoming_edge_head && !dest->incoming_edge_head->incoming_next;
|
||||||
|
|
||||||
Edge* edge = arena_->Alloc<Edge>();
|
Edge* edge = arena_->Alloc<Edge>();
|
||||||
edge->src = src;
|
edge->src = src;
|
||||||
edge->dest = dest;
|
edge->dest = dest;
|
||||||
edge->flags = flags;
|
edge->flags = flags;
|
||||||
edge->outgoing_prev = NULL;
|
edge->outgoing_prev = nullptr;
|
||||||
edge->outgoing_next = src->outgoing_edge_head;
|
edge->outgoing_next = src->outgoing_edge_head;
|
||||||
|
if (edge->outgoing_next) {
|
||||||
|
edge->outgoing_next->outgoing_prev = edge;
|
||||||
|
}
|
||||||
src->outgoing_edge_head = edge;
|
src->outgoing_edge_head = edge;
|
||||||
edge->incoming_prev = NULL;
|
edge->incoming_prev = nullptr;
|
||||||
edge->incoming_next = dest->incoming_edge_head;
|
edge->incoming_next = dest->incoming_edge_head;
|
||||||
|
if (edge->incoming_next) {
|
||||||
|
edge->incoming_next->incoming_prev = edge;
|
||||||
|
}
|
||||||
dest->incoming_edge_head = edge;
|
dest->incoming_edge_head = edge;
|
||||||
|
|
||||||
|
if (dest_was_dominated) {
|
||||||
|
// If dest was previously dominated it no longer is.
|
||||||
|
auto edge = dest->incoming_edge_head;
|
||||||
|
while (edge) {
|
||||||
|
edge->flags &= ~Edge::DOMINATES;
|
||||||
|
edge = edge->incoming_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HIRBuilder::RemoveEdge(Block* src, Block* dest) {
|
||||||
|
auto edge = src->outgoing_edge_head;
|
||||||
|
while (edge) {
|
||||||
|
if (edge->dest == dest) {
|
||||||
|
RemoveEdge(edge);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
edge = edge->outgoing_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HIRBuilder::RemoveEdge(Edge* edge) {
|
||||||
|
if (edge->outgoing_prev) {
|
||||||
|
edge->outgoing_prev->outgoing_next = edge->outgoing_next;
|
||||||
|
}
|
||||||
|
if (edge->outgoing_next) {
|
||||||
|
edge->outgoing_next->outgoing_prev = edge->outgoing_prev;
|
||||||
|
}
|
||||||
|
if (edge == edge->src->outgoing_edge_head) {
|
||||||
|
edge->src->outgoing_edge_head = edge->outgoing_next;
|
||||||
|
}
|
||||||
|
if (edge->incoming_prev) {
|
||||||
|
edge->incoming_prev->incoming_next = edge->incoming_next;
|
||||||
|
}
|
||||||
|
if (edge->incoming_next) {
|
||||||
|
edge->incoming_next->incoming_prev = edge->incoming_prev;
|
||||||
|
}
|
||||||
|
if (edge == edge->dest->incoming_edge_head) {
|
||||||
|
edge->dest->incoming_edge_head = edge->incoming_next;
|
||||||
|
}
|
||||||
|
edge->incoming_next = edge->incoming_prev = nullptr;
|
||||||
|
edge->outgoing_next = edge->outgoing_prev = nullptr;
|
||||||
|
|
||||||
|
if (edge->dest->incoming_edge_head &&
|
||||||
|
!edge->dest->incoming_edge_head->incoming_next) {
|
||||||
|
// Dest is now dominated by the last remaining edge.
|
||||||
|
edge->dest->incoming_edge_head->flags |= Edge::DOMINATES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HIRBuilder::RemoveBlock(Block* block) {
|
||||||
|
while (block->incoming_edge_head) {
|
||||||
|
RemoveEdge(block->incoming_edge_head);
|
||||||
|
}
|
||||||
|
while (block->outgoing_edge_head) {
|
||||||
|
RemoveEdge(block->outgoing_edge_head);
|
||||||
|
}
|
||||||
|
if (block->prev) {
|
||||||
|
block->prev->next = block->next;
|
||||||
|
}
|
||||||
|
if (block->next) {
|
||||||
|
block->next->prev = block->prev;
|
||||||
|
}
|
||||||
|
if (block == block_head_) {
|
||||||
|
block_head_ = block->next;
|
||||||
|
}
|
||||||
|
if (block == block_tail_) {
|
||||||
|
block_tail_ = block->prev;
|
||||||
|
}
|
||||||
|
block->next = block->prev = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIRBuilder::MergeAdjacentBlocks(Block* left, Block* right) {
|
void HIRBuilder::MergeAdjacentBlocks(Block* left, Block* right) {
|
||||||
|
@ -481,7 +563,7 @@ void HIRBuilder::MergeAdjacentBlocks(Block* left, Block* right) {
|
||||||
}
|
}
|
||||||
left->instr_tail = instr;
|
left->instr_tail = instr;
|
||||||
|
|
||||||
// Unlink from old block list;
|
// Unlink from old block list.
|
||||||
right->instr_head = next;
|
right->instr_head = next;
|
||||||
if (right->instr_tail == instr) {
|
if (right->instr_tail == instr) {
|
||||||
right->instr_tail = nullptr;
|
right->instr_tail = nullptr;
|
||||||
|
@ -517,6 +599,19 @@ void HIRBuilder::MergeAdjacentBlocks(Block* left, Block* right) {
|
||||||
label->next = nullptr;
|
label->next = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove edge between left and right.
|
||||||
|
RemoveEdge(left, right);
|
||||||
|
|
||||||
|
// Move right's outgoing edges to left.
|
||||||
|
assert_null(right->incoming_edge_head);
|
||||||
|
auto edge = right->outgoing_edge_head;
|
||||||
|
while (edge) {
|
||||||
|
auto next_edge = edge->outgoing_next;
|
||||||
|
RemoveEdge(edge);
|
||||||
|
AddEdge(left, edge->dest, edge->flags);
|
||||||
|
edge = next_edge;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the right block from the block list.
|
// Remove the right block from the block list.
|
||||||
left->next = right->next;
|
left->next = right->next;
|
||||||
if (right->next) {
|
if (right->next) {
|
||||||
|
@ -529,6 +624,8 @@ void HIRBuilder::MergeAdjacentBlocks(Block* left, Block* right) {
|
||||||
|
|
||||||
Block* HIRBuilder::AppendBlock() {
|
Block* HIRBuilder::AppendBlock() {
|
||||||
Block* block = arena_->Alloc<Block>();
|
Block* block = arena_->Alloc<Block>();
|
||||||
|
block->ordinal = -1;
|
||||||
|
block->incoming_values = nullptr;
|
||||||
block->arena = arena_;
|
block->arena = arena_;
|
||||||
block->next = NULL;
|
block->next = NULL;
|
||||||
block->prev = block_tail_;
|
block->prev = block_tail_;
|
||||||
|
|
|
@ -60,6 +60,9 @@ class HIRBuilder {
|
||||||
void ResetLabelTags();
|
void ResetLabelTags();
|
||||||
|
|
||||||
void AddEdge(Block* src, Block* dest, uint32_t flags);
|
void AddEdge(Block* src, Block* dest, uint32_t flags);
|
||||||
|
void RemoveEdge(Block* src, Block* dest);
|
||||||
|
void RemoveEdge(Edge* edge);
|
||||||
|
void RemoveBlock(Block* block);
|
||||||
void MergeAdjacentBlocks(Block* left, Block* right);
|
void MergeAdjacentBlocks(Block* left, Block* right);
|
||||||
|
|
||||||
// static allocations:
|
// static allocations:
|
||||||
|
|
Loading…
Reference in New Issue