Moving alloy/ into xenia/cpu/ to start simplifying things.
This commit is contained in:
147
src/xenia/cpu/compiler/passes/value_reduction_pass.cc
Normal file
147
src/xenia/cpu/compiler/passes/value_reduction_pass.cc
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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/value_reduction_pass.h"
|
||||
|
||||
#include "xenia/cpu/backend/backend.h"
|
||||
#include "xenia/cpu/compiler/compiler.h"
|
||||
#include "xenia/cpu/runtime/runtime.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
#if XE_COMPILER_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4267)
|
||||
#include <llvm/ADT/BitVector.h>
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#include <llvm/ADT/BitVector.h>
|
||||
#endif // XE_COMPILER_MSVC
|
||||
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
namespace compiler {
|
||||
namespace passes {
|
||||
|
||||
// TODO(benvanik): remove when enums redefined.
|
||||
using namespace xe::cpu::hir;
|
||||
|
||||
using xe::cpu::hir::HIRBuilder;
|
||||
using xe::cpu::hir::OpcodeInfo;
|
||||
using xe::cpu::hir::Value;
|
||||
|
||||
ValueReductionPass::ValueReductionPass() : CompilerPass() {}
|
||||
|
||||
ValueReductionPass::~ValueReductionPass() {}
|
||||
|
||||
void ValueReductionPass::ComputeLastUse(Value* value) {
|
||||
// TODO(benvanik): compute during construction?
|
||||
// Note that this list isn't sorted (unfortunately), so we have to scan
|
||||
// them all.
|
||||
uint32_t max_ordinal = 0;
|
||||
Value::Use* last_use = nullptr;
|
||||
auto use = value->use_head;
|
||||
while (use) {
|
||||
if (!last_use || use->instr->ordinal >= max_ordinal) {
|
||||
last_use = use;
|
||||
max_ordinal = use->instr->ordinal;
|
||||
}
|
||||
use = use->next;
|
||||
}
|
||||
value->last_use = last_use ? last_use->instr : nullptr;
|
||||
}
|
||||
|
||||
int ValueReductionPass::Run(HIRBuilder* builder) {
|
||||
// Walk each block and reuse variable ordinals as much as possible.
|
||||
|
||||
llvm::BitVector ordinals(builder->max_value_ordinal());
|
||||
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
// Reset used ordinals.
|
||||
ordinals.reset();
|
||||
|
||||
// Renumber all instructions to make liveness tracking easier.
|
||||
uint32_t instr_ordinal = 0;
|
||||
auto instr = block->instr_head;
|
||||
while (instr) {
|
||||
instr->ordinal = instr_ordinal++;
|
||||
instr = instr->next;
|
||||
}
|
||||
|
||||
instr = block->instr_head;
|
||||
while (instr) {
|
||||
const OpcodeInfo* info = instr->opcode;
|
||||
OpcodeSignatureType dest_type = GET_OPCODE_SIG_TYPE_DEST(info->signature);
|
||||
OpcodeSignatureType src1_type = GET_OPCODE_SIG_TYPE_SRC1(info->signature);
|
||||
OpcodeSignatureType src2_type = GET_OPCODE_SIG_TYPE_SRC2(info->signature);
|
||||
OpcodeSignatureType src3_type = GET_OPCODE_SIG_TYPE_SRC3(info->signature);
|
||||
if (src1_type == OPCODE_SIG_TYPE_V) {
|
||||
auto v = instr->src1.value;
|
||||
if (!v->last_use) {
|
||||
ComputeLastUse(v);
|
||||
}
|
||||
if (v->last_use == instr) {
|
||||
// Available.
|
||||
if (!instr->src1.value->IsConstant()) {
|
||||
ordinals.reset(v->ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src2_type == OPCODE_SIG_TYPE_V) {
|
||||
auto v = instr->src2.value;
|
||||
if (!v->last_use) {
|
||||
ComputeLastUse(v);
|
||||
}
|
||||
if (v->last_use == instr) {
|
||||
// Available.
|
||||
if (!instr->src2.value->IsConstant()) {
|
||||
ordinals.reset(v->ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src3_type == OPCODE_SIG_TYPE_V) {
|
||||
auto v = instr->src3.value;
|
||||
if (!v->last_use) {
|
||||
ComputeLastUse(v);
|
||||
}
|
||||
if (v->last_use == instr) {
|
||||
// Available.
|
||||
if (!instr->src3.value->IsConstant()) {
|
||||
ordinals.reset(v->ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dest_type == OPCODE_SIG_TYPE_V) {
|
||||
// Dest values are processed last, as they may be able to reuse a
|
||||
// source value ordinal.
|
||||
auto v = instr->dest;
|
||||
// Find a lower ordinal.
|
||||
for (auto n = 0u; n < ordinals.size(); n++) {
|
||||
if (!ordinals.test(n)) {
|
||||
ordinals.set(n);
|
||||
v->ordinal = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instr = instr->next;
|
||||
}
|
||||
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace passes
|
||||
} // namespace compiler
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
Reference in New Issue
Block a user