74 lines
2.4 KiB
C++
74 lines
2.4 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include "xenia/cpu/compiler/passes/control_flow_simplification_pass.h"
|
|
|
|
#include "xenia/cpu/backend/backend.h"
|
|
#include "xenia/cpu/compiler/compiler.h"
|
|
#include "xenia/cpu/processor.h"
|
|
#include "xenia/profiling.h"
|
|
|
|
namespace xe {
|
|
namespace cpu {
|
|
namespace compiler {
|
|
namespace passes {
|
|
|
|
// TODO(benvanik): remove when enums redefined.
|
|
using namespace xe::cpu::hir;
|
|
|
|
using xe::cpu::hir::Edge;
|
|
using xe::cpu::hir::HIRBuilder;
|
|
|
|
ControlFlowSimplificationPass::ControlFlowSimplificationPass()
|
|
: CompilerPass() {}
|
|
|
|
ControlFlowSimplificationPass::~ControlFlowSimplificationPass() {}
|
|
|
|
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.
|
|
bool merged_any = false;
|
|
block = builder->last_block();
|
|
while (block) {
|
|
auto prev_block = block->prev;
|
|
const uint32_t expected = Edge::DOMINATES | Edge::UNCONDITIONAL;
|
|
if (block->incoming_edge_head &&
|
|
(block->incoming_edge_head->flags & expected) == expected) {
|
|
// Dominated by the incoming block.
|
|
// If that block comes immediately before us then we can merge the
|
|
// two blocks (assuming it's not a volatile instruction like Trap).
|
|
if (block->prev == block->incoming_edge_head->src &&
|
|
block->prev->instr_tail &&
|
|
!(block->prev->instr_tail->opcode->flags & OPCODE_FLAG_VOLATILE)) {
|
|
builder->MergeAdjacentBlocks(block->prev, block);
|
|
merged_any = true;
|
|
}
|
|
}
|
|
block = prev_block;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace passes
|
|
} // namespace compiler
|
|
} // namespace cpu
|
|
} // namespace xe
|