Basic ContextPromotionPass and some opcode info rearranging.
This commit is contained in:
@@ -15,9 +15,11 @@
|
||||
using namespace alloy;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
Compiler::Compiler() {
|
||||
Compiler::Compiler(Runtime* runtime) :
|
||||
runtime_(runtime) {
|
||||
alloy::tracing::WriteEvent(EventType::Init({
|
||||
}));
|
||||
}
|
||||
@@ -35,6 +37,7 @@ Compiler::~Compiler() {
|
||||
}
|
||||
|
||||
void Compiler::AddPass(Pass* pass) {
|
||||
pass->Initialize(this);
|
||||
passes_.push_back(pass);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/hir/function_builder.h>
|
||||
|
||||
namespace alloy { namespace runtime { class Runtime; } }
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
@@ -22,8 +24,10 @@ class Pass;
|
||||
|
||||
class Compiler {
|
||||
public:
|
||||
Compiler();
|
||||
Compiler(runtime::Runtime* runtime);
|
||||
~Compiler();
|
||||
|
||||
runtime::Runtime* runtime() const { return runtime_; }
|
||||
|
||||
void AddPass(Pass* pass);
|
||||
|
||||
@@ -32,6 +36,8 @@ public:
|
||||
int Compile(hir::FunctionBuilder* builder);
|
||||
|
||||
private:
|
||||
runtime::Runtime* runtime_;
|
||||
|
||||
typedef std::vector<Pass*> PassList;
|
||||
PassList passes_;
|
||||
};
|
||||
|
||||
@@ -9,12 +9,21 @@
|
||||
|
||||
#include <alloy/compiler/pass.h>
|
||||
|
||||
#include <alloy/compiler/compiler.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::compiler;
|
||||
|
||||
|
||||
Pass::Pass() {
|
||||
Pass::Pass() :
|
||||
runtime_(0), compiler_(0) {
|
||||
}
|
||||
|
||||
Pass::~Pass() {
|
||||
}
|
||||
|
||||
int Pass::Initialize(Compiler* compiler) {
|
||||
runtime_ = compiler->runtime();
|
||||
compiler_ = compiler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14,17 +14,27 @@
|
||||
|
||||
#include <alloy/hir/function_builder.h>
|
||||
|
||||
namespace alloy { namespace runtime { class Runtime; } }
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
|
||||
class Compiler;
|
||||
|
||||
|
||||
class Pass {
|
||||
public:
|
||||
Pass();
|
||||
virtual ~Pass();
|
||||
|
||||
virtual int Initialize(Compiler* compiler);
|
||||
|
||||
virtual int Run(hir::FunctionBuilder* builder) = 0;
|
||||
|
||||
protected:
|
||||
runtime::Runtime* runtime_;
|
||||
Compiler* compiler_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#define ALLOY_COMPILER_PASSES_H_
|
||||
|
||||
//#include <alloy/compiler/passes/constant_propagation_pass.h>
|
||||
//#include <alloy/compiler/passes/context_promotion_pass.h>
|
||||
#include <alloy/compiler/passes/context_promotion_pass.h>
|
||||
#include <alloy/compiler/passes/dead_code_elimination_pass.h>
|
||||
//#include <alloy/compiler/passes/dead_store_elimination_pass.h>
|
||||
#include <alloy/compiler/passes/simplification_pass.h>
|
||||
|
||||
109
src/alloy/compiler/passes/context_promotion_pass.cc
Normal file
109
src/alloy/compiler/passes/context_promotion_pass.cc
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <alloy/compiler/passes/context_promotion_pass.h>
|
||||
|
||||
#include <alloy/compiler/compiler.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::compiler::passes;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
ContextPromotionPass::ContextPromotionPass() :
|
||||
context_values_size_(0), context_values_(0),
|
||||
Pass() {
|
||||
}
|
||||
|
||||
ContextPromotionPass::~ContextPromotionPass() {
|
||||
if (context_values_) {
|
||||
xe_free(context_values_);
|
||||
}
|
||||
}
|
||||
|
||||
int ContextPromotionPass::Initialize(Compiler* compiler) {
|
||||
if (Pass::Initialize(compiler)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// This is a terrible implementation.
|
||||
ContextInfo* context_info = runtime_->frontend()->context_info();
|
||||
context_values_size_ = context_info->size() * sizeof(Value*);
|
||||
context_values_ = (Value**)xe_calloc(context_values_size_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ContextPromotionPass::Run(FunctionBuilder* builder) {
|
||||
// Like mem2reg, but because context memory is unaliasable it's easier to
|
||||
// check and convert LoadContext/StoreContext into value operations.
|
||||
// Example of load->value promotion:
|
||||
// v0 = load_context +100
|
||||
// store_context +200, v0
|
||||
// v1 = load_context +100 <-- replace with v1 = v0
|
||||
// store_context +200, v1
|
||||
//
|
||||
// It'd be possible in this stage to also remove redundant context stores:
|
||||
// Example of dead store elimination:
|
||||
// store_context +100, v0 <-- removed due to following store
|
||||
// store_context +100, v1
|
||||
// This is more generally done by DSE, however if it could be done here
|
||||
// instead as it may be faster (at least on the block-level).
|
||||
|
||||
// Process each block independently, for now.
|
||||
Block* block = builder->first_block();
|
||||
while (block) {
|
||||
PromoteBlock(block);
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ContextPromotionPass::PromoteBlock(Block* block) {
|
||||
// Clear the context values list.
|
||||
// TODO(benvanik): new data structure that isn't so stupid.
|
||||
// Bitvector of validity, perhaps?
|
||||
xe_zero_struct(context_values_, context_values_size_);
|
||||
|
||||
Instr* i = block->instr_head;
|
||||
while (i) {
|
||||
if (i->opcode == &OPCODE_LOAD_CONTEXT_info) {
|
||||
size_t offset = i->src1.offset;
|
||||
Value* previous_value = context_values_[offset];
|
||||
if (previous_value) {
|
||||
// Legit previous value, reuse.
|
||||
i->opcode = &hir::OPCODE_ASSIGN_info;
|
||||
i->set_src1(previous_value);
|
||||
} else {
|
||||
// Store the loaded value into the table.
|
||||
context_values_[offset] = i->dest;
|
||||
}
|
||||
} else if (i->opcode == &OPCODE_STORE_CONTEXT_info) {
|
||||
size_t offset = i->src1.offset;
|
||||
Value* value = i->src2.value;
|
||||
Value* previous_value = context_values_[offset];
|
||||
if (previous_value &&
|
||||
previous_value->def &&
|
||||
previous_value->def->opcode == &OPCODE_STORE_CONTEXT_info) {
|
||||
// Legit previous value from a useless store.
|
||||
// Remove the store entirely.
|
||||
previous_value->def->Remove();
|
||||
}
|
||||
// Store value into the table for later.
|
||||
context_values_[offset] = value;
|
||||
}
|
||||
|
||||
i = i->next;
|
||||
}
|
||||
}
|
||||
44
src/alloy/compiler/passes/context_promotion_pass.h
Normal file
44
src/alloy/compiler/passes/context_promotion_pass.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef ALLOY_COMPILER_PASSES_CONTEXT_PROMOTION_PASS_H_
|
||||
#define ALLOY_COMPILER_PASSES_CONTEXT_PROMOTION_PASS_H_
|
||||
|
||||
#include <alloy/compiler/pass.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
namespace passes {
|
||||
|
||||
|
||||
class ContextPromotionPass : public Pass {
|
||||
public:
|
||||
ContextPromotionPass();
|
||||
virtual ~ContextPromotionPass();
|
||||
|
||||
virtual int Initialize(Compiler* compiler);
|
||||
|
||||
virtual int Run(hir::FunctionBuilder* builder);
|
||||
|
||||
private:
|
||||
void PromoteBlock(hir::Block* block);
|
||||
|
||||
private:
|
||||
size_t context_values_size_;
|
||||
hir::Value** context_values_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace passes
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_PASSES_CONTEXT_PROMOTION_PASS_H_
|
||||
@@ -53,8 +53,6 @@ int DeadCodeEliminationPass::Run(FunctionBuilder* builder) {
|
||||
// all removed ops with NOP and then do a single pass that removes them
|
||||
// all.
|
||||
|
||||
const OpcodeInfo* nop = builder->GetNopOpcode();
|
||||
|
||||
bool any_removed = false;
|
||||
Block* block = builder->first_block();
|
||||
while (block) {
|
||||
@@ -67,7 +65,7 @@ int DeadCodeEliminationPass::Run(FunctionBuilder* builder) {
|
||||
if (!(opcode->flags & OPCODE_FLAG_VOLATILE) &&
|
||||
i->dest && !i->dest->use_head) {
|
||||
// Has no uses and is not volatile. This instruction can die!
|
||||
MakeNopRecursive(nop, i);
|
||||
MakeNopRecursive(i);
|
||||
any_removed = true;
|
||||
}
|
||||
|
||||
@@ -84,7 +82,7 @@ int DeadCodeEliminationPass::Run(FunctionBuilder* builder) {
|
||||
Instr* i = block->instr_head;
|
||||
while (i) {
|
||||
Instr* next = i->next;
|
||||
if (i->opcode->num == OPCODE_NOP) {
|
||||
if (i->opcode == &OPCODE_NOP_info) {
|
||||
// Nop - remove!
|
||||
i->Remove();
|
||||
}
|
||||
@@ -97,9 +95,8 @@ int DeadCodeEliminationPass::Run(FunctionBuilder* builder) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeadCodeEliminationPass::MakeNopRecursive(
|
||||
const OpcodeInfo* nop, Instr* i) {
|
||||
i->opcode = nop;
|
||||
void DeadCodeEliminationPass::MakeNopRecursive(Instr* i) {
|
||||
i->opcode = &hir::OPCODE_NOP_info;
|
||||
i->dest->def = NULL;
|
||||
i->dest = NULL;
|
||||
|
||||
@@ -113,7 +110,7 @@ void DeadCodeEliminationPass::MakeNopRecursive(
|
||||
if (!value->use_head) { \
|
||||
/* Value is now unused, so recursively kill it. */ \
|
||||
if (value->def && value->def != i) { \
|
||||
MakeNopRecursive(nop, value->def); \
|
||||
MakeNopRecursive(value->def); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
virtual int Run(hir::FunctionBuilder* builder);
|
||||
|
||||
private:
|
||||
void MakeNopRecursive(const hir::OpcodeInfo* nop, hir::Instr* i);
|
||||
void MakeNopRecursive(hir::Instr* i);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -65,13 +65,13 @@ int SimplificationPass::Run(FunctionBuilder* builder) {
|
||||
|
||||
Value* SimplificationPass::CheckValue(Value* value) {
|
||||
Instr* def = value->def;
|
||||
if (def && def->opcode->num == OPCODE_ASSIGN) {
|
||||
if (def && def->opcode == &OPCODE_ASSIGN_info) {
|
||||
// Value comes from an assignment - recursively find if it comes from
|
||||
// another assignment. It probably doesn't, if we already replaced it.
|
||||
Value* replacement = def->src1.value;
|
||||
while (true) {
|
||||
def = replacement->def;
|
||||
if (!def || def->opcode->num != OPCODE_ASSIGN) {
|
||||
if (!def || def->opcode != &OPCODE_ASSIGN_info) {
|
||||
break;
|
||||
}
|
||||
replacement = def->src1.value;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
'sources': [
|
||||
#'constant_propagation_pass.cc',
|
||||
#'constant_propagation_pass.h',
|
||||
#'context_promotion_pass.cc',
|
||||
#'context_promotion_pass.h',
|
||||
'context_promotion_pass.cc',
|
||||
'context_promotion_pass.h',
|
||||
'dead_code_elimination_pass.cc',
|
||||
'dead_code_elimination_pass.h',
|
||||
#'dead_store_elimination_pass.cc',
|
||||
|
||||
Reference in New Issue
Block a user