Oh my. Basic CFA/DFA, local variable support, misc fixes, etc.
This commit is contained in:
@@ -11,11 +11,14 @@
|
||||
#define ALLOY_COMPILER_COMPILER_PASSES_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/data_flow_analysis_pass.h>
|
||||
#include <alloy/compiler/passes/dead_code_elimination_pass.h>
|
||||
#include <alloy/compiler/passes/finalization_pass.h>
|
||||
//#include <alloy/compiler/passes/dead_store_elimination_pass.h>
|
||||
#include <alloy/compiler/passes/simplification_pass.h>
|
||||
#include <alloy/compiler/passes/validation_pass.h>
|
||||
#include <alloy/compiler/passes/value_reduction_pass.h>
|
||||
|
||||
// TODO:
|
||||
|
||||
72
src/alloy/compiler/passes/control_flow_analysis_pass.cc
Normal file
72
src/alloy/compiler/passes/control_flow_analysis_pass.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_analysis_pass.h>
|
||||
|
||||
#include <alloy/backend/backend.h>
|
||||
#include <alloy/compiler/compiler.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4267)
|
||||
#include <llvm/ADT/BitVector.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::compiler::passes;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
ControlFlowAnalysisPass::ControlFlowAnalysisPass() :
|
||||
CompilerPass() {
|
||||
}
|
||||
|
||||
ControlFlowAnalysisPass::~ControlFlowAnalysisPass() {
|
||||
}
|
||||
|
||||
int ControlFlowAnalysisPass::Run(HIRBuilder* builder) {
|
||||
// TODO(benvanik): reset edges for all blocks? Needed to be re-runnable.
|
||||
|
||||
// Add edges.
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
auto instr = block->instr_head;
|
||||
while (instr) {
|
||||
if (instr->opcode->flags & OPCODE_FLAG_BRANCH) {
|
||||
if (instr->opcode == &OPCODE_BRANCH_info) {
|
||||
auto label = instr->src1.label;
|
||||
builder->AddEdge(block, label->block, Edge::UNCONDITIONAL);
|
||||
} else if (instr->opcode == &OPCODE_BRANCH_TRUE_info ||
|
||||
instr->opcode == &OPCODE_BRANCH_FALSE_info) {
|
||||
auto label = instr->src2.label;
|
||||
builder->AddEdge(block, label->block, 0);
|
||||
}
|
||||
}
|
||||
instr = instr->next;
|
||||
}
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
// Mark dominators.
|
||||
block = builder->first_block();
|
||||
while (block) {
|
||||
if (block->incoming_edge_head &&
|
||||
!block->incoming_edge_head->incoming_next) {
|
||||
block->incoming_edge_head->flags |= Edge::DOMINATES;
|
||||
}
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
37
src/alloy/compiler/passes/control_flow_analysis_pass.h
Normal file
37
src/alloy/compiler/passes/control_flow_analysis_pass.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_ANALYSIS_PASS_H_
|
||||
#define ALLOY_COMPILER_PASSES_CONTROL_FLOW_ANALYSIS_PASS_H_
|
||||
|
||||
#include <alloy/compiler/compiler_pass.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
namespace passes {
|
||||
|
||||
|
||||
class ControlFlowAnalysisPass : public CompilerPass {
|
||||
public:
|
||||
ControlFlowAnalysisPass();
|
||||
virtual ~ControlFlowAnalysisPass();
|
||||
|
||||
virtual int Run(hir::HIRBuilder* builder);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
} // namespace passes
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_PASSES_CONTROL_FLOW_ANALYSIS_PASS_H_
|
||||
203
src/alloy/compiler/passes/data_flow_analysis_pass.cc
Normal file
203
src/alloy/compiler/passes/data_flow_analysis_pass.cc
Normal file
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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/data_flow_analysis_pass.h>
|
||||
|
||||
#include <alloy/backend/backend.h>
|
||||
#include <alloy/compiler/compiler.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4267)
|
||||
#include <llvm/ADT/BitVector.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::compiler::passes;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
DataFlowAnalysisPass::DataFlowAnalysisPass() :
|
||||
CompilerPass() {
|
||||
}
|
||||
|
||||
DataFlowAnalysisPass::~DataFlowAnalysisPass() {
|
||||
}
|
||||
|
||||
int DataFlowAnalysisPass::Run(HIRBuilder* builder) {
|
||||
auto arena = builder->arena();
|
||||
|
||||
// Linearize blocks so that we can detect cycles and propagate dependencies.
|
||||
uint32_t block_count = LinearizeBlocks(builder);
|
||||
|
||||
// Analyze value flow and add locals as needed.
|
||||
AnalyzeFlow(builder, block_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t DataFlowAnalysisPass::LinearizeBlocks(HIRBuilder* builder) {
|
||||
// TODO(benvanik): actually do this - we cheat now knowing that they are in
|
||||
// sequential order.
|
||||
uint32_t block_ordinal = 0;
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
block->ordinal = block_ordinal++;
|
||||
block = block->next;
|
||||
}
|
||||
return block_ordinal;
|
||||
}
|
||||
|
||||
void DataFlowAnalysisPass::AnalyzeFlow(HIRBuilder* builder,
|
||||
uint32_t block_count) {
|
||||
uint32_t max_value_estimate =
|
||||
builder->max_value_ordinal() + 1 + block_count * 4;
|
||||
|
||||
// Stash for value map. We may want to maintain this during building.
|
||||
auto arena = builder->arena();
|
||||
Value** value_map = (Value**)arena->Alloc(
|
||||
sizeof(Value*) * max_value_estimate);
|
||||
|
||||
// Allocate incoming bitvectors for use by blocks. We don't need outgoing
|
||||
// because they are only used during the block iteration.
|
||||
// Mapped by block ordinal.
|
||||
// TODO(benvanik): cache this list, grow as needed, etc.
|
||||
auto incoming_bitvectors = (llvm::BitVector**)arena->Alloc(
|
||||
sizeof(llvm::BitVector*) * block_count);
|
||||
for (auto n = 0u; n < block_count; n++) {
|
||||
incoming_bitvectors[n] = new llvm::BitVector(max_value_estimate);
|
||||
}
|
||||
|
||||
// Walk blocks in reverse and calculate incoming/outgoing values.
|
||||
auto block = builder->last_block();
|
||||
while (block) {
|
||||
// allocate bitsets based on max value number
|
||||
block->incoming_values = incoming_bitvectors[block->ordinal];
|
||||
auto& incoming_values = *block->incoming_values;
|
||||
|
||||
// Walk instructions and gather up incoming values.
|
||||
auto instr = block->instr_head;
|
||||
while (instr) {
|
||||
uint32_t signature = instr->opcode->signature;
|
||||
#define SET_INCOMING_VALUE(v) \
|
||||
if (v->def && v->def->block != block) { \
|
||||
incoming_values.set(v->ordinal); \
|
||||
} \
|
||||
XEASSERT(v->ordinal < max_value_estimate); \
|
||||
value_map[v->ordinal] = v;
|
||||
if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) {
|
||||
SET_INCOMING_VALUE(instr->src1.value);
|
||||
}
|
||||
if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) {
|
||||
SET_INCOMING_VALUE(instr->src2.value);
|
||||
}
|
||||
if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) {
|
||||
SET_INCOMING_VALUE(instr->src3.value);
|
||||
}
|
||||
#undef SET_INCOMING_VALUE
|
||||
instr = instr->next;
|
||||
}
|
||||
|
||||
// Add all successor incoming values to our outgoing, as we need to
|
||||
// pass them through.
|
||||
llvm::BitVector outgoing_values(max_value_estimate);
|
||||
auto outgoing_edge = block->outgoing_edge_head;
|
||||
while (outgoing_edge) {
|
||||
if (outgoing_edge->dest->ordinal > block->ordinal) {
|
||||
outgoing_values |= *outgoing_edge->dest->incoming_values;
|
||||
}
|
||||
outgoing_edge = outgoing_edge->outgoing_next;
|
||||
}
|
||||
incoming_values |= outgoing_values;
|
||||
|
||||
// Add stores for all outgoing values.
|
||||
auto outgoing_ordinal = outgoing_values.find_first();
|
||||
while (outgoing_ordinal != -1) {
|
||||
Value* src_value = value_map[outgoing_ordinal];
|
||||
XEASSERTNOTNULL(src_value);
|
||||
if (!src_value->local_slot) {
|
||||
src_value->local_slot = builder->AllocLocal(src_value->type);
|
||||
}
|
||||
builder->StoreLocal(src_value->local_slot, src_value);
|
||||
|
||||
// If we are in the block the value was defined in:
|
||||
if (src_value->def->block == block) {
|
||||
// Move the store to right after the def, or as soon after
|
||||
// as we can (respecting PAIRED flags).
|
||||
auto def_next = src_value->def->next;
|
||||
while (def_next && def_next->opcode->flags & OPCODE_FLAG_PAIRED_PREV) {
|
||||
def_next = def_next->next;
|
||||
}
|
||||
XEASSERTNOTNULL(def_next);
|
||||
builder->last_instr()->MoveBefore(def_next);
|
||||
|
||||
// We don't need it in the incoming list.
|
||||
incoming_values.reset(outgoing_ordinal);
|
||||
} else {
|
||||
// Eh, just throw at the end, before the first branch.
|
||||
auto tail = block->instr_tail;
|
||||
while (tail && tail->opcode->flags & OPCODE_FLAG_BRANCH) {
|
||||
tail = tail->prev;
|
||||
}
|
||||
XEASSERTNOTZERO(tail);
|
||||
builder->last_instr()->MoveBefore(tail->next);
|
||||
}
|
||||
|
||||
outgoing_ordinal = outgoing_values.find_next(outgoing_ordinal);
|
||||
}
|
||||
|
||||
// Add loads for all incoming values and rename them in the block.
|
||||
auto incoming_ordinal = incoming_values.find_first();
|
||||
while (incoming_ordinal != -1) {
|
||||
Value* src_value = value_map[incoming_ordinal];
|
||||
XEASSERTNOTNULL(src_value);
|
||||
if (!src_value->local_slot) {
|
||||
src_value->local_slot = builder->AllocLocal(src_value->type);
|
||||
}
|
||||
Value* local_value = builder->LoadLocal(src_value->local_slot);
|
||||
builder->last_instr()->MoveBefore(block->instr_head);
|
||||
|
||||
// Swap uses of original value with the local value.
|
||||
auto instr = block->instr_head;
|
||||
while (instr) {
|
||||
uint32_t signature = instr->opcode->signature;
|
||||
if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) {
|
||||
if (instr->src1.value == src_value) {
|
||||
instr->set_src1(local_value);
|
||||
}
|
||||
}
|
||||
if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) {
|
||||
if (instr->src2.value == src_value) {
|
||||
instr->set_src2(local_value);
|
||||
}
|
||||
}
|
||||
if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) {
|
||||
if (instr->src3.value == src_value) {
|
||||
instr->set_src3(local_value);
|
||||
}
|
||||
}
|
||||
instr = instr->next;
|
||||
}
|
||||
|
||||
incoming_ordinal = incoming_values.find_next(incoming_ordinal);
|
||||
}
|
||||
|
||||
block = block->prev;
|
||||
}
|
||||
|
||||
// Cleanup bitvectors.
|
||||
for (auto n = 0u; n < block_count; n++) {
|
||||
delete incoming_bitvectors[n];
|
||||
}
|
||||
}
|
||||
39
src/alloy/compiler/passes/data_flow_analysis_pass.h
Normal file
39
src/alloy/compiler/passes/data_flow_analysis_pass.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_DATA_FLOW_ANALYSIS_PASS_H_
|
||||
#define ALLOY_COMPILER_PASSES_DATA_FLOW_ANALYSIS_PASS_H_
|
||||
|
||||
#include <alloy/compiler/compiler_pass.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
namespace passes {
|
||||
|
||||
|
||||
class DataFlowAnalysisPass : public CompilerPass {
|
||||
public:
|
||||
DataFlowAnalysisPass();
|
||||
virtual ~DataFlowAnalysisPass();
|
||||
|
||||
virtual int Run(hir::HIRBuilder* builder);
|
||||
|
||||
private:
|
||||
uint32_t LinearizeBlocks(hir::HIRBuilder* builder);
|
||||
void AnalyzeFlow(hir::HIRBuilder* builder, uint32_t block_count);
|
||||
};
|
||||
|
||||
|
||||
} // namespace passes
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_PASSES_DATA_FLOW_ANALYSIS_PASS_H_
|
||||
@@ -59,20 +59,21 @@ int DeadCodeEliminationPass::Run(HIRBuilder* builder) {
|
||||
// all removed ops with NOP and then do a single pass that removes them
|
||||
// all.
|
||||
|
||||
bool any_removed = false;
|
||||
bool any_instr_removed = false;
|
||||
bool any_locals_removed = false;
|
||||
Block* block = builder->first_block();
|
||||
while (block) {
|
||||
// Walk instructions in reverse.
|
||||
Instr* i = block->instr_tail;
|
||||
while (i) {
|
||||
Instr* prev = i->prev;
|
||||
auto prev = i->prev;
|
||||
|
||||
const OpcodeInfo* opcode = i->opcode;
|
||||
uint32_t signature = opcode->signature;
|
||||
auto opcode = i->opcode;
|
||||
if (!(opcode->flags & OPCODE_FLAG_VOLATILE) &&
|
||||
i->dest && !i->dest->use_head) {
|
||||
// Has no uses and is not volatile. This instruction can die!
|
||||
MakeNopRecursive(i);
|
||||
any_removed = true;
|
||||
any_instr_removed = true;
|
||||
} else if (opcode == &OPCODE_ASSIGN_info) {
|
||||
// Assignment. These are useless, so just try to remove by completely
|
||||
// replacing the value.
|
||||
@@ -82,11 +83,31 @@ int DeadCodeEliminationPass::Run(HIRBuilder* builder) {
|
||||
i = prev;
|
||||
}
|
||||
|
||||
// Walk instructions forward.
|
||||
i = block->instr_head;
|
||||
while (i) {
|
||||
auto next = i->next;
|
||||
|
||||
auto opcode = i->opcode;
|
||||
if (opcode == &OPCODE_STORE_LOCAL_info) {
|
||||
// Check to see if the store has any interceeding uses after the load.
|
||||
// If not, it can be removed (as the local is just passing through the
|
||||
// function).
|
||||
// We do this after the previous pass so that removed code doesn't keep
|
||||
// the local alive.
|
||||
if (!CheckLocalUse(i)) {
|
||||
any_locals_removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
i = next;
|
||||
}
|
||||
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
// Remove all nops.
|
||||
if (any_removed) {
|
||||
if (any_instr_removed) {
|
||||
Block* block = builder->first_block();
|
||||
while (block) {
|
||||
Instr* i = block->instr_head;
|
||||
@@ -102,6 +123,21 @@ int DeadCodeEliminationPass::Run(HIRBuilder* builder) {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any locals that no longer have uses.
|
||||
if (any_locals_removed) {
|
||||
// TODO(benvanik): local removal/dealloc.
|
||||
auto locals = builder->locals();
|
||||
for (auto it = locals.begin(); it != locals.end();) {
|
||||
auto next = ++it;
|
||||
auto value = *it;
|
||||
if (!value->use_head) {
|
||||
// Unused, can be removed.
|
||||
locals.erase(it);
|
||||
}
|
||||
it = next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -150,3 +186,24 @@ void DeadCodeEliminationPass::ReplaceAssignment(Instr* i) {
|
||||
|
||||
i->Remove();
|
||||
}
|
||||
|
||||
bool DeadCodeEliminationPass::CheckLocalUse(Instr* i) {
|
||||
auto slot = i->src1.value;
|
||||
auto src = i->src2.value;
|
||||
|
||||
auto use = src->use_head;
|
||||
if (use) {
|
||||
auto use_instr = use->instr;
|
||||
if (use_instr->opcode != &OPCODE_LOAD_LOCAL_info) {
|
||||
// A valid use (probably). Keep it.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load/store are paired. They can both be removed.
|
||||
use_instr->Remove();
|
||||
}
|
||||
|
||||
i->Remove();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
private:
|
||||
void MakeNopRecursive(hir::Instr* i);
|
||||
void ReplaceAssignment(hir::Instr* i);
|
||||
bool CheckLocalUse(hir::Instr* i);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
'constant_propagation_pass.h',
|
||||
'context_promotion_pass.cc',
|
||||
'context_promotion_pass.h',
|
||||
'control_flow_analysis_pass.cc',
|
||||
'control_flow_analysis_pass.h',
|
||||
'data_flow_analysis_pass.cc',
|
||||
'data_flow_analysis_pass.h',
|
||||
'dead_code_elimination_pass.cc',
|
||||
'dead_code_elimination_pass.h',
|
||||
'finalization_pass.cc',
|
||||
@@ -13,6 +17,8 @@
|
||||
#'dead_store_elimination_pass.h',
|
||||
'simplification_pass.cc',
|
||||
'simplification_pass.h',
|
||||
'validation_pass.cc',
|
||||
'validation_pass.h',
|
||||
'value_reduction_pass.cc',
|
||||
'value_reduction_pass.h',
|
||||
],
|
||||
|
||||
99
src/alloy/compiler/passes/validation_pass.cc
Normal file
99
src/alloy/compiler/passes/validation_pass.cc
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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/validation_pass.h>
|
||||
|
||||
#include <alloy/backend/backend.h>
|
||||
#include <alloy/compiler/compiler.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::compiler::passes;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
ValidationPass::ValidationPass() :
|
||||
CompilerPass() {
|
||||
}
|
||||
|
||||
ValidationPass::~ValidationPass() {
|
||||
}
|
||||
|
||||
int ValidationPass::Run(HIRBuilder* builder) {
|
||||
StringBuffer str;
|
||||
builder->Dump(&str);
|
||||
printf(str.GetString());
|
||||
fflush(stdout);
|
||||
str.Reset();
|
||||
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
auto label = block->label_head;
|
||||
while (label) {
|
||||
XEASSERT(label->block == block);
|
||||
if (label->block != block) {
|
||||
return 1;
|
||||
}
|
||||
label = label->next;
|
||||
}
|
||||
|
||||
auto instr = block->instr_head;
|
||||
while (instr) {
|
||||
if (ValidateInstruction(block, instr)) {
|
||||
return 1;
|
||||
}
|
||||
instr = instr->next;
|
||||
}
|
||||
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ValidationPass::ValidateInstruction(Block* block, Instr* instr) {
|
||||
XEASSERT(instr->block == block);
|
||||
if (instr->block != block) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t signature = instr->opcode->signature;
|
||||
if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) {
|
||||
if (ValidateValue(block, instr, instr->src1.value)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) {
|
||||
if (ValidateValue(block, instr, instr->src2.value)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) {
|
||||
if (ValidateValue(block, instr, instr->src3.value)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ValidationPass::ValidateValue(Block* block, Instr* instr, Value* value) {
|
||||
if (value->def) {
|
||||
/*auto def = value->def;
|
||||
XEASSERT(def->block == block);
|
||||
if (def->block != block) {
|
||||
return 1;
|
||||
}*/
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
39
src/alloy/compiler/passes/validation_pass.h
Normal file
39
src/alloy/compiler/passes/validation_pass.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_VALIDATION_PASS_H_
|
||||
#define ALLOY_COMPILER_PASSES_VALIDATION_PASS_H_
|
||||
|
||||
#include <alloy/compiler/compiler_pass.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
namespace passes {
|
||||
|
||||
|
||||
class ValidationPass : public CompilerPass {
|
||||
public:
|
||||
ValidationPass();
|
||||
virtual ~ValidationPass();
|
||||
|
||||
virtual int Run(hir::HIRBuilder* builder);
|
||||
|
||||
private:
|
||||
int ValidateInstruction(hir::Block* block, hir::Instr* instr);
|
||||
int ValidateValue(hir::Block* block, hir::Instr* instr, hir::Value* value);
|
||||
};
|
||||
|
||||
|
||||
} // namespace passes
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_PASSES_VALIDATION_PASS_H_
|
||||
@@ -13,7 +13,11 @@
|
||||
#include <alloy/compiler/compiler.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
#include <bitset>
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4267)
|
||||
#include <llvm/ADT/BitVector.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
@@ -51,8 +55,7 @@ void ValueReductionPass::ComputeLastUse(Value* value) {
|
||||
int ValueReductionPass::Run(HIRBuilder* builder) {
|
||||
// Walk each block and reuse variable ordinals as much as possible.
|
||||
|
||||
// Let's hope this is enough.
|
||||
std::bitset<1024> ordinals;
|
||||
llvm::BitVector ordinals(builder->max_value_ordinal());
|
||||
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
@@ -82,7 +85,7 @@ int ValueReductionPass::Run(HIRBuilder* builder) {
|
||||
if (v->last_use == instr) {
|
||||
// Available.
|
||||
if (!instr->src1.value->IsConstant()) {
|
||||
ordinals.set(v->ordinal, false);
|
||||
ordinals.reset(v->ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +97,7 @@ int ValueReductionPass::Run(HIRBuilder* builder) {
|
||||
if (v->last_use == instr) {
|
||||
// Available.
|
||||
if (!instr->src2.value->IsConstant()) {
|
||||
ordinals.set(v->ordinal, false);
|
||||
ordinals.reset(v->ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +109,7 @@ int ValueReductionPass::Run(HIRBuilder* builder) {
|
||||
if (v->last_use == instr) {
|
||||
// Available.
|
||||
if (!instr->src3.value->IsConstant()) {
|
||||
ordinals.set(v->ordinal, false);
|
||||
ordinals.reset(v->ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +118,7 @@ int ValueReductionPass::Run(HIRBuilder* builder) {
|
||||
// source value ordinal.
|
||||
auto v = instr->dest;
|
||||
// Find a lower ordinal.
|
||||
for (auto n = 0; n < ordinals.size(); n++) {
|
||||
for (auto n = 0u; n < ordinals.size(); n++) {
|
||||
if (!ordinals.test(n)) {
|
||||
ordinals.set(n);
|
||||
v->ordinal = n;
|
||||
|
||||
Reference in New Issue
Block a user