Adding control flow simplification pass to compensate for lack of phi.
This commit is contained in:
parent
bba3315f58
commit
b02ce5e95e
|
@ -11,8 +11,9 @@
|
||||||
#define ALLOY_COMPILER_COMPILER_PASSES_H_
|
#define ALLOY_COMPILER_COMPILER_PASSES_H_
|
||||||
|
|
||||||
#include <alloy/compiler/passes/constant_propagation_pass.h>
|
#include <alloy/compiler/passes/constant_propagation_pass.h>
|
||||||
#include <alloy/compiler/passes/control_flow_analysis_pass.h>
|
|
||||||
#include <alloy/compiler/passes/context_promotion_pass.h>
|
#include <alloy/compiler/passes/context_promotion_pass.h>
|
||||||
|
#include <alloy/compiler/passes/control_flow_analysis_pass.h>
|
||||||
|
#include <alloy/compiler/passes/control_flow_simplification_pass.h>
|
||||||
#include <alloy/compiler/passes/data_flow_analysis_pass.h>
|
#include <alloy/compiler/passes/data_flow_analysis_pass.h>
|
||||||
#include <alloy/compiler/passes/dead_code_elimination_pass.h>
|
#include <alloy/compiler/passes/dead_code_elimination_pass.h>
|
||||||
//#include <alloy/compiler/passes/dead_store_elimination_pass.h>
|
//#include <alloy/compiler/passes/dead_store_elimination_pass.h>
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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 <alloy/compiler/passes/control_flow_simplification_pass.h>
|
||||||
|
|
||||||
|
#include <alloy/backend/backend.h>
|
||||||
|
#include <alloy/compiler/compiler.h>
|
||||||
|
#include <alloy/runtime/runtime.h>
|
||||||
|
|
||||||
|
namespace alloy {
|
||||||
|
namespace compiler {
|
||||||
|
namespace passes {
|
||||||
|
|
||||||
|
// TODO(benvanik): remove when enums redefined.
|
||||||
|
using namespace alloy::hir;
|
||||||
|
|
||||||
|
using alloy::hir::Edge;
|
||||||
|
using alloy::hir::HIRBuilder;
|
||||||
|
|
||||||
|
ControlFlowSimplificationPass::ControlFlowSimplificationPass()
|
||||||
|
: CompilerPass() {}
|
||||||
|
|
||||||
|
ControlFlowSimplificationPass::~ControlFlowSimplificationPass() {}
|
||||||
|
|
||||||
|
int ControlFlowSimplificationPass::Run(HIRBuilder* builder) {
|
||||||
|
SCOPE_profile_cpu_f("alloy");
|
||||||
|
|
||||||
|
// Walk backwards and merge blocks if possible.
|
||||||
|
bool merged_any = false;
|
||||||
|
auto 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 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace passes
|
||||||
|
} // namespace compiler
|
||||||
|
} // namespace alloy
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ALLOY_COMPILER_PASSES_CONTROL_FLOW_SIMPLIFICATION_PASS_H_
|
||||||
|
#define ALLOY_COMPILER_PASSES_CONTROL_FLOW_SIMPLIFICATION_PASS_H_
|
||||||
|
|
||||||
|
#include <alloy/compiler/compiler_pass.h>
|
||||||
|
|
||||||
|
namespace alloy {
|
||||||
|
namespace compiler {
|
||||||
|
namespace passes {
|
||||||
|
|
||||||
|
class ControlFlowSimplificationPass : public CompilerPass {
|
||||||
|
public:
|
||||||
|
ControlFlowSimplificationPass();
|
||||||
|
~ControlFlowSimplificationPass() override;
|
||||||
|
|
||||||
|
int Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace passes
|
||||||
|
} // namespace compiler
|
||||||
|
} // namespace alloy
|
||||||
|
|
||||||
|
#endif // ALLOY_COMPILER_PASSES_CONTROL_FLOW_SIMPLIFICATION_PASS_H_
|
|
@ -320,8 +320,7 @@ bool RegisterAllocationPass::TryAllocateRegister(Value* value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegisterAllocationPass::SpillOneRegister(HIRBuilder* builder,
|
bool RegisterAllocationPass::SpillOneRegister(HIRBuilder* builder, Block* block,
|
||||||
Block* block,
|
|
||||||
TypeName required_type) {
|
TypeName required_type) {
|
||||||
// Get the set that we will be picking from.
|
// Get the set that we will be picking from.
|
||||||
RegisterSetUsage* usage_set;
|
RegisterSetUsage* usage_set;
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
'context_promotion_pass.h',
|
'context_promotion_pass.h',
|
||||||
'control_flow_analysis_pass.cc',
|
'control_flow_analysis_pass.cc',
|
||||||
'control_flow_analysis_pass.h',
|
'control_flow_analysis_pass.h',
|
||||||
|
'control_flow_simplification_pass.cc',
|
||||||
|
'control_flow_simplification_pass.h',
|
||||||
'data_flow_analysis_pass.cc',
|
'data_flow_analysis_pass.cc',
|
||||||
'data_flow_analysis_pass.h',
|
'data_flow_analysis_pass.h',
|
||||||
'dead_code_elimination_pass.cc',
|
'dead_code_elimination_pass.cc',
|
||||||
|
|
|
@ -43,7 +43,10 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
|
||||||
|
|
||||||
bool validate = FLAGS_validate_hir;
|
bool validate = FLAGS_validate_hir;
|
||||||
|
|
||||||
// Build the CFG first.
|
// Merge blocks early. This will let us use more context in other passes.
|
||||||
|
// The CFG is required for simplification and dirtied by it.
|
||||||
|
compiler_->AddPass(std::make_unique<passes::ControlFlowAnalysisPass>());
|
||||||
|
compiler_->AddPass(std::make_unique<passes::ControlFlowSimplificationPass>());
|
||||||
compiler_->AddPass(std::make_unique<passes::ControlFlowAnalysisPass>());
|
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
|
||||||
|
|
|
@ -436,6 +436,88 @@ void HIRBuilder::AddEdge(Block* src, Block* dest, uint32_t flags) {
|
||||||
dest->incoming_edge_head = edge;
|
dest->incoming_edge_head = edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HIRBuilder::MergeAdjacentBlocks(Block* left, Block* right) {
|
||||||
|
assert_true(left->next == right && right->prev == left);
|
||||||
|
assert_true(!right->incoming_edge_head ||
|
||||||
|
right->incoming_edge_head->flags & Edge::DOMINATES);
|
||||||
|
|
||||||
|
// If the left block ends with a branch to the right block, drop it.
|
||||||
|
if (left->instr_tail &&
|
||||||
|
left->instr_tail->opcode->flags & OPCODE_FLAG_BRANCH) {
|
||||||
|
auto sig = left->instr_tail->opcode->signature;
|
||||||
|
if (GET_OPCODE_SIG_TYPE_SRC1(sig) == OPCODE_SIG_TYPE_L) {
|
||||||
|
if (left->instr_tail->src1.label->block == right) {
|
||||||
|
left->instr_tail->Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GET_OPCODE_SIG_TYPE_SRC2(sig) == OPCODE_SIG_TYPE_L) {
|
||||||
|
if (left->instr_tail->src2.label->block == right) {
|
||||||
|
left->instr_tail->Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through the right instructions and shift each one back into the left.
|
||||||
|
while (right->instr_head) {
|
||||||
|
auto instr = right->instr_head;
|
||||||
|
auto next = instr->next;
|
||||||
|
|
||||||
|
// Link into block list.
|
||||||
|
instr->next = nullptr;
|
||||||
|
instr->prev = left->instr_tail;
|
||||||
|
if (left->instr_tail) {
|
||||||
|
left->instr_tail->next = instr;
|
||||||
|
} else {
|
||||||
|
left->instr_head = left->instr_tail = instr;
|
||||||
|
}
|
||||||
|
left->instr_tail = instr;
|
||||||
|
|
||||||
|
// Unlink from old block list;
|
||||||
|
right->instr_head = next;
|
||||||
|
if (right->instr_tail == instr) {
|
||||||
|
right->instr_tail = nullptr;
|
||||||
|
}
|
||||||
|
if (next) {
|
||||||
|
next->prev = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update state.
|
||||||
|
instr->block = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move/remove labels.
|
||||||
|
// We only need to preserve named labels.
|
||||||
|
while (right->label_head) {
|
||||||
|
auto label = right->label_head;
|
||||||
|
if (label->name) {
|
||||||
|
// Label is named - move it.
|
||||||
|
label->block = left;
|
||||||
|
label->prev = left->label_tail;
|
||||||
|
if (left->label_tail) {
|
||||||
|
left->label_tail->next = label;
|
||||||
|
}
|
||||||
|
left->label_tail = label;
|
||||||
|
if (!left->label_head) {
|
||||||
|
left->label_head = label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
right->label_head = label->next;
|
||||||
|
if (right->label_tail == label) {
|
||||||
|
right->label_tail = nullptr;
|
||||||
|
}
|
||||||
|
label->next = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the right block from the block list.
|
||||||
|
left->next = right->next;
|
||||||
|
if (right->next) {
|
||||||
|
right->next->prev = left;
|
||||||
|
}
|
||||||
|
if (block_tail_ == right) {
|
||||||
|
block_tail_ = left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Block* HIRBuilder::AppendBlock() {
|
Block* HIRBuilder::AppendBlock() {
|
||||||
Block* block = arena_->Alloc<Block>();
|
Block* block = arena_->Alloc<Block>();
|
||||||
block->arena = arena_;
|
block->arena = arena_;
|
||||||
|
|
|
@ -61,6 +61,7 @@ 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 MergeAdjacentBlocks(Block* left, Block* right);
|
||||||
|
|
||||||
// static allocations:
|
// static allocations:
|
||||||
// Value* AllocStatic(size_t length);
|
// Value* AllocStatic(size_t length);
|
||||||
|
|
|
@ -108,13 +108,13 @@ DEFINE_OPCODE(
|
||||||
OPCODE_BRANCH_TRUE,
|
OPCODE_BRANCH_TRUE,
|
||||||
"branch_true",
|
"branch_true",
|
||||||
OPCODE_SIG_X_V_L,
|
OPCODE_SIG_X_V_L,
|
||||||
OPCODE_FLAG_BRANCH)
|
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
OPCODE_BRANCH_FALSE,
|
OPCODE_BRANCH_FALSE,
|
||||||
"branch_false",
|
"branch_false",
|
||||||
OPCODE_SIG_X_V_L,
|
OPCODE_SIG_X_V_L,
|
||||||
OPCODE_FLAG_BRANCH)
|
OPCODE_FLAG_BRANCH | OPCODE_FLAG_VOLATILE)
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
OPCODE_ASSIGN,
|
OPCODE_ASSIGN,
|
||||||
|
|
|
@ -663,8 +663,6 @@ spin:
|
||||||
|
|
||||||
SHIM_CALL RtlEnterCriticalSection_shim(
|
SHIM_CALL RtlEnterCriticalSection_shim(
|
||||||
PPCContext* ppc_state, KernelState* state) {
|
PPCContext* ppc_state, KernelState* state) {
|
||||||
SCOPE_profile_cpu_f("kernel");
|
|
||||||
|
|
||||||
uint32_t cs_ptr = SHIM_GET_ARG_32(0);
|
uint32_t cs_ptr = SHIM_GET_ARG_32(0);
|
||||||
|
|
||||||
// XELOGD("RtlEnterCriticalSection(%.8X)", cs_ptr);
|
// XELOGD("RtlEnterCriticalSection(%.8X)", cs_ptr);
|
||||||
|
|
Loading…
Reference in New Issue