Emitting more x64.
This commit is contained in:
parent
2468645bf2
commit
88b631b160
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include <alloy/backend/x64/lir/lir_builder.h>
|
#include <alloy/backend/x64/lir/lir_builder.h>
|
||||||
|
|
||||||
|
#include <alloy/runtime/symbol_info.h>
|
||||||
|
|
||||||
using namespace alloy;
|
using namespace alloy;
|
||||||
using namespace alloy::backend::x64;
|
using namespace alloy::backend::x64;
|
||||||
using namespace alloy::backend::x64::lir;
|
using namespace alloy::backend::x64::lir;
|
||||||
|
@ -72,7 +74,7 @@ void LIRBuilder::Dump(StringBuffer* str) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (i->opcode == &LIR_OPCODE_COMMENT_info) {
|
if (i->opcode == &LIR_OPCODE_COMMENT_info) {
|
||||||
str->Append(" ; %s\n", i->arg[0].string);
|
str->Append(" ; %s\n", i->arg0<const char>());
|
||||||
i = i->next;
|
i = i->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +86,22 @@ void LIRBuilder::Dump(StringBuffer* str) {
|
||||||
} else {
|
} else {
|
||||||
str->Append("%s", info->name);
|
str->Append("%s", info->name);
|
||||||
}
|
}
|
||||||
// TODO(benvanik): args based on signature
|
if (i->arg0_type() != LIROperandType::NONE) {
|
||||||
|
str->Append(" ");
|
||||||
|
DumpArg(str, i->arg0_type(), (intptr_t)i + i->arg_offsets.arg0);
|
||||||
|
}
|
||||||
|
if (i->arg1_type() != LIROperandType::NONE) {
|
||||||
|
str->Append(", ");
|
||||||
|
DumpArg(str, i->arg1_type(), (intptr_t)i + i->arg_offsets.arg1);
|
||||||
|
}
|
||||||
|
if (i->arg2_type() != LIROperandType::NONE) {
|
||||||
|
str->Append(", ");
|
||||||
|
DumpArg(str, i->arg2_type(), (intptr_t)i + i->arg_offsets.arg2);
|
||||||
|
}
|
||||||
|
if (i->arg3_type() != LIROperandType::NONE) {
|
||||||
|
str->Append(", ");
|
||||||
|
DumpArg(str, i->arg3_type(), (intptr_t)i + i->arg_offsets.arg3);
|
||||||
|
}
|
||||||
str->Append("\n");
|
str->Append("\n");
|
||||||
i = i->next;
|
i = i->next;
|
||||||
}
|
}
|
||||||
|
@ -93,6 +110,89 @@ void LIRBuilder::Dump(StringBuffer* str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LIRBuilder::DumpArg(StringBuffer* str, LIROperandType type,
|
||||||
|
intptr_t ptr) {
|
||||||
|
switch (type) {
|
||||||
|
case LIROperandType::NONE:
|
||||||
|
break;
|
||||||
|
case LIROperandType::FUNCTION:
|
||||||
|
if (true) {
|
||||||
|
auto target = (*(runtime::FunctionInfo**)ptr);
|
||||||
|
str->Append(target->name() ? target->name() : "<fn>");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIROperandType::LABEL:
|
||||||
|
if (true) {
|
||||||
|
auto target = (*(LIRLabel**)ptr);
|
||||||
|
str->Append(target->name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIROperandType::OFFSET:
|
||||||
|
if (true) {
|
||||||
|
auto offset = (*(intptr_t*)ptr);
|
||||||
|
str->Append("+%lld", offset);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIROperandType::STRING:
|
||||||
|
if (true) {
|
||||||
|
str->Append((*(char**)ptr));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIROperandType::REGISTER:
|
||||||
|
if (true) {
|
||||||
|
LIRRegister* reg = (LIRRegister*)ptr;
|
||||||
|
if (reg->is_virtual()) {
|
||||||
|
switch (reg->type) {
|
||||||
|
case LIRRegisterType::REG8:
|
||||||
|
str->Append("v%d.i8", reg->id & 0x00FFFFFF);
|
||||||
|
break;
|
||||||
|
case LIRRegisterType::REG16:
|
||||||
|
str->Append("v%d.i16", reg->id & 0x00FFFFFF);
|
||||||
|
break;
|
||||||
|
case LIRRegisterType::REG32:
|
||||||
|
str->Append("v%d.i32", reg->id & 0x00FFFFFF);
|
||||||
|
break;
|
||||||
|
case LIRRegisterType::REG64:
|
||||||
|
str->Append("v%d.i64", reg->id & 0x00FFFFFF);
|
||||||
|
break;
|
||||||
|
case LIRRegisterType::REGXMM:
|
||||||
|
str->Append("v%d.xmm", reg->id & 0x00FFFFFF);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
str->Append(lir::register_names[(int)reg->name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIROperandType::INT8_CONSTANT:
|
||||||
|
str->Append("%X", *(int8_t*)ptr);
|
||||||
|
break;
|
||||||
|
case LIROperandType::INT16_CONSTANT:
|
||||||
|
str->Append("%X", *(int16_t*)ptr);
|
||||||
|
break;
|
||||||
|
case LIROperandType::INT32_CONSTANT:
|
||||||
|
str->Append("%X", *(int32_t*)ptr);
|
||||||
|
break;
|
||||||
|
case LIROperandType::INT64_CONSTANT:
|
||||||
|
str->Append("%X", *(int64_t*)ptr);
|
||||||
|
break;
|
||||||
|
case LIROperandType::FLOAT32_CONSTANT:
|
||||||
|
str->Append("%F", *(float*)ptr);
|
||||||
|
break;
|
||||||
|
case LIROperandType::FLOAT64_CONSTANT:
|
||||||
|
str->Append("%F", *(double*)ptr);
|
||||||
|
break;
|
||||||
|
case LIROperandType::VEC128_CONSTANT:
|
||||||
|
if (true) {
|
||||||
|
vec128_t* value = (vec128_t*)ptr;
|
||||||
|
str->Append("(%F,%F,%F,%F)",
|
||||||
|
value->x, value->y, value->z, value->w);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: XEASSERTALWAYS(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LIRBlock* LIRBuilder::current_block() const {
|
LIRBlock* LIRBuilder::current_block() const {
|
||||||
return current_block_;
|
return current_block_;
|
||||||
}
|
}
|
||||||
|
@ -192,65 +292,87 @@ LIRInstr* LIRBuilder::AppendInstr(
|
||||||
instr->block = block;
|
instr->block = block;
|
||||||
instr->opcode = &opcode_info;
|
instr->opcode = &opcode_info;
|
||||||
instr->flags = flags;
|
instr->flags = flags;
|
||||||
|
instr->arg_types = {
|
||||||
|
LIROperandType::NONE,
|
||||||
|
LIROperandType::NONE,
|
||||||
|
LIROperandType::NONE,
|
||||||
|
LIROperandType::NONE
|
||||||
|
};
|
||||||
return instr;
|
return instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t LIRBuilder::AppendOperand(
|
||||||
|
LIRInstr* instr, LIROperandType& type, const char* value) {
|
||||||
|
type = LIROperandType::STRING;
|
||||||
|
size_t length = xestrlena(value);
|
||||||
|
auto ptr = (char*)arena_->Alloc(length + 1);
|
||||||
|
xe_copy_struct(ptr, value, length + 1);
|
||||||
|
return (uint8_t)((intptr_t)ptr - (intptr_t)instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t LIRBuilder::AppendOperand(
|
||||||
|
LIRInstr* instr, LIROperandType& type, hir::Value* value) {
|
||||||
|
if (value->IsConstant()) {
|
||||||
|
switch (value->type) {
|
||||||
|
case hir::INT8_TYPE:
|
||||||
|
return AppendOperand(instr, type, value->constant.i8);
|
||||||
|
case hir::INT16_TYPE:
|
||||||
|
return AppendOperand(instr, type, value->constant.i16);
|
||||||
|
case hir::INT32_TYPE:
|
||||||
|
return AppendOperand(instr, type, value->constant.i32);
|
||||||
|
case hir::INT64_TYPE:
|
||||||
|
return AppendOperand(instr, type, value->constant.i64);
|
||||||
|
case hir::FLOAT32_TYPE:
|
||||||
|
return AppendOperand(instr, type, value->constant.f32);
|
||||||
|
case hir::FLOAT64_TYPE:
|
||||||
|
return AppendOperand(instr, type, value->constant.f64);
|
||||||
|
case hir::VEC128_TYPE:
|
||||||
|
return AppendOperand(instr, type, value->constant.v128);
|
||||||
|
default:
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LIRRegisterType reg_type;
|
||||||
|
switch (value->type) {
|
||||||
|
case hir::INT8_TYPE:
|
||||||
|
reg_type = LIRRegisterType::REG8;
|
||||||
|
break;
|
||||||
|
case hir::INT16_TYPE:
|
||||||
|
reg_type = LIRRegisterType::REG16;
|
||||||
|
break;
|
||||||
|
case hir::INT32_TYPE:
|
||||||
|
reg_type = LIRRegisterType::REG32;
|
||||||
|
break;
|
||||||
|
case hir::INT64_TYPE:
|
||||||
|
reg_type = LIRRegisterType::REG64;
|
||||||
|
break;
|
||||||
|
case hir::FLOAT32_TYPE:
|
||||||
|
reg_type = LIRRegisterType::REGXMM;
|
||||||
|
break;
|
||||||
|
case hir::FLOAT64_TYPE:
|
||||||
|
reg_type = LIRRegisterType::REGXMM;
|
||||||
|
break;
|
||||||
|
case hir::VEC128_TYPE:
|
||||||
|
reg_type = LIRRegisterType::REGXMM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Make it uniqueish by putting it +20000000
|
||||||
|
uint32_t reg_id = 0x20000000 + value->ordinal;
|
||||||
|
return AppendOperand(instr, type, LIRRegister(reg_type, reg_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LIRBuilder::Comment(const char* format, ...) {
|
void LIRBuilder::Comment(const char* format, ...) {
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
xevsnprintfa(buffer, 1024, format, args);
|
xevsnprintfa(buffer, 1024, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
size_t len = xestrlena(buffer);
|
|
||||||
if (!len) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
void* p = arena_->Alloc(len + 1);
|
|
||||||
xe_copy_struct(p, buffer, len + 1);
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_COMMENT_info);
|
auto instr = AppendInstr(LIR_OPCODE_COMMENT_info);
|
||||||
instr->arg[0].string = (char*)p;
|
instr->arg_offsets.arg0 =
|
||||||
}
|
AppendOperand(instr, instr->arg_types.arg0, buffer);
|
||||||
|
|
||||||
void LIRBuilder::Nop() {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_NOP_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::SourceOffset(uint64_t offset) {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_SOURCE_OFFSET_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::DebugBreak() {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_DEBUG_BREAK_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::Trap() {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_TRAP_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::Test(int8_t a, int8_t b) {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_TEST_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::Test(int16_t a, int16_t b) {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_TEST_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::Test(int32_t a, int32_t b) {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_TEST_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::Test(int64_t a, int64_t b) {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_TEST_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::Test(hir::Value* a, hir::Value* b) {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_TEST_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::JumpEQ(LIRLabel* label) {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_JUMP_EQ_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LIRBuilder::JumpNE(LIRLabel* label) {
|
|
||||||
auto instr = AppendInstr(LIR_OPCODE_JUMP_NE_info);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,27 +50,124 @@ public:
|
||||||
LIRBlock* AppendBlock();
|
LIRBlock* AppendBlock();
|
||||||
void EndBlock();
|
void EndBlock();
|
||||||
|
|
||||||
|
void Nop() { AppendInstr(LIR_OPCODE_NOP_info, 0); }
|
||||||
|
|
||||||
void Comment(const char* format, ...);
|
void Comment(const char* format, ...);
|
||||||
void Nop();
|
void SourceOffset(uintptr_t offset) { AppendInstr(LIR_OPCODE_SOURCE_OFFSET_info, 0, offset); }
|
||||||
void SourceOffset(uint64_t offset);
|
void DebugBreak() { AppendInstr(LIR_OPCODE_DEBUG_BREAK_info, 0); }
|
||||||
|
void Trap() { AppendInstr(LIR_OPCODE_TRAP_info, 0); }
|
||||||
|
|
||||||
void DebugBreak();
|
template<typename A0, typename A1>
|
||||||
void Trap();
|
void Mov(A0& a, A1& b) { AppendInstr(LIR_OPCODE_MOV_info, 0, a, b); }
|
||||||
|
template<typename A0, typename A1, typename A2>
|
||||||
|
void Mov(A0& a, A1& b, A2& c) { AppendInstr(LIR_OPCODE_MOV_info, 0, a, b, c); }
|
||||||
|
template<typename A0, typename A1>
|
||||||
|
void MovZX(A0& a, A1& b) { AppendInstr(LIR_OPCODE_MOV_ZX_info, 0, a, b); }
|
||||||
|
template<typename A0, typename A1>
|
||||||
|
void MovSX(A0& a, A1& b) { AppendInstr(LIR_OPCODE_MOV_ZX_info, 0, a, b); }
|
||||||
|
|
||||||
void Mov();
|
template<typename A0, typename A1>
|
||||||
|
void Test(A0& a, A1& b) { AppendInstr(LIR_OPCODE_TEST_info, 0, a, b); }
|
||||||
|
|
||||||
void Test(int8_t a, int8_t b);
|
template<typename A0>
|
||||||
void Test(int16_t a, int16_t b);
|
void Jump(A0& target) { AppendInstr(LIR_OPCODE_JUMP_info, 0, target); }
|
||||||
void Test(int32_t a, int32_t b);
|
void JumpEQ(LIRLabel* target) { AppendInstr(LIR_OPCODE_JUMP_EQ_info, 0, target); }
|
||||||
void Test(int64_t a, int64_t b);
|
void JumpNE(LIRLabel* target) { AppendInstr(LIR_OPCODE_JUMP_NE_info, 0, target); }
|
||||||
void Test(hir::Value* a, hir::Value* b);
|
|
||||||
|
|
||||||
void JumpEQ(LIRLabel* label);
|
|
||||||
void JumpNE(LIRLabel* label);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void DumpArg(StringBuffer* str, LIROperandType type, intptr_t ptr);
|
||||||
|
|
||||||
LIRInstr* AppendInstr(const LIROpcodeInfo& opcode, uint16_t flags = 0);
|
LIRInstr* AppendInstr(const LIROpcodeInfo& opcode, uint16_t flags = 0);
|
||||||
|
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(runtime::FunctionInfo*) { return LIROperandType::FUNCTION; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(LIRLabel*) { return LIROperandType::LABEL; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(uintptr_t) { return LIROperandType::OFFSET; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(const char*) { return LIROperandType::STRING; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(LIRRegister&) { return LIROperandType::REGISTER; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(int8_t) { return LIROperandType::INT8_CONSTANT; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(int16_t) { return LIROperandType::INT16_CONSTANT; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(int32_t) { return LIROperandType::INT32_CONSTANT; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(int64_t) { return LIROperandType::INT64_CONSTANT; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(float) { return LIROperandType::FLOAT32_CONSTANT; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(double) { return LIROperandType::FLOAT64_CONSTANT; }
|
||||||
|
XEFORCEINLINE LIROperandType GetOperandType(vec128_t&) { return LIROperandType::VEC128_CONSTANT; }
|
||||||
|
LIROperandType GetOperandType(hir::Value* value) {
|
||||||
|
if (value->IsConstant()) {
|
||||||
|
switch (value->type) {
|
||||||
|
case hir::INT8_TYPE:
|
||||||
|
return LIROperandType::INT8_CONSTANT;
|
||||||
|
case hir::INT16_TYPE:
|
||||||
|
return LIROperandType::INT16_CONSTANT;
|
||||||
|
case hir::INT32_TYPE:
|
||||||
|
return LIROperandType::INT32_CONSTANT;
|
||||||
|
case hir::INT64_TYPE:
|
||||||
|
return LIROperandType::INT64_CONSTANT;
|
||||||
|
case hir::FLOAT32_TYPE:
|
||||||
|
return LIROperandType::FLOAT32_CONSTANT;
|
||||||
|
case hir::FLOAT64_TYPE:
|
||||||
|
return LIROperandType::FLOAT64_CONSTANT;
|
||||||
|
case hir::VEC128_TYPE:
|
||||||
|
return LIROperandType::VEC128_CONSTANT;
|
||||||
|
default:
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
return LIROperandType::INT8_CONSTANT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return LIROperandType::REGISTER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
uint8_t AppendOperand(LIRInstr* instr, LIROperandType& type, T& value) {
|
||||||
|
type = GetOperandType(value);
|
||||||
|
auto ptr = arena_->Alloc<T>();
|
||||||
|
*ptr = value;
|
||||||
|
return (uint8_t)((intptr_t)ptr - (intptr_t)instr);
|
||||||
|
}
|
||||||
|
uint8_t AppendOperand(LIRInstr* instr, LIROperandType& type, const char* value);
|
||||||
|
uint8_t AppendOperand(LIRInstr* instr, LIROperandType& type, hir::Value* value);
|
||||||
|
|
||||||
|
template<typename A0>
|
||||||
|
LIRInstr* AppendInstr(const LIROpcodeInfo& opcode, uint16_t flags, A0& arg0) {
|
||||||
|
auto instr = AppendInstr(opcode, flags);
|
||||||
|
instr->arg_offsets.arg0 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg0, arg0);
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
template<typename A0, typename A1>
|
||||||
|
LIRInstr* AppendInstr(const LIROpcodeInfo& opcode, uint16_t flags, A0& arg0, A1& arg1) {
|
||||||
|
auto instr = AppendInstr(opcode, flags);
|
||||||
|
instr->arg_offsets.arg0 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg0, arg0);
|
||||||
|
instr->arg_offsets.arg1 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg1, arg1);
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
template<typename A0, typename A1, typename A2>
|
||||||
|
LIRInstr* AppendInstr(const LIROpcodeInfo& opcode, uint16_t flags, A0& arg0, A1& arg1, A2& arg2) {
|
||||||
|
auto instr = AppendInstr(opcode, flags);
|
||||||
|
instr->arg_offsets.arg0 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg0, arg0);
|
||||||
|
instr->arg_offsets.arg1 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg1, arg1);
|
||||||
|
instr->arg_offsets.arg2 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg2, arg2);
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
template<typename A0, typename A1, typename A2, typename A3>
|
||||||
|
LIRInstr* AppendInstr(const LIROpcodeInfo& opcode, uint16_t flags, A0& arg0, A1& arg1, A2& arg2, A3& arg3) {
|
||||||
|
auto instr = AppendInstr(opcode, flags);
|
||||||
|
instr->arg_offsets.arg0 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg0, arg0);
|
||||||
|
instr->arg_offsets.arg1 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg1, arg1);
|
||||||
|
instr->arg_offsets.arg2 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg2, arg2);
|
||||||
|
instr->arg_offsets.arg3 =
|
||||||
|
AppendOperand(instr, instr->arg_types.arg3, arg3);
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
X64Backend* backend_;
|
X64Backend* backend_;
|
||||||
Arena* arena_;
|
Arena* arena_;
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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/backend/x64/lir/lir_instr.h>
|
||||||
|
|
||||||
|
using namespace alloy;
|
||||||
|
using namespace alloy::backend::x64::lir;
|
||||||
|
|
||||||
|
|
||||||
|
namespace alloy {
|
||||||
|
namespace backend {
|
||||||
|
namespace x64 {
|
||||||
|
namespace lir {
|
||||||
|
const char* register_names[] = {
|
||||||
|
"al", "ax", "eax", "rax",
|
||||||
|
"bl", "bx", "ebx", "rbx",
|
||||||
|
"cl", "cx", "ecx", "rcx",
|
||||||
|
"dl", "dx", "edx", "rdx",
|
||||||
|
"r8b", "r8w", "r8d", "r8",
|
||||||
|
"r9b", "r9w", "r9d", "r9",
|
||||||
|
"r10b", "r10w", "r10d", "r10",
|
||||||
|
"r11b", "r11w", "r11d", "r11",
|
||||||
|
"r12b", "r12w", "r12d", "r12",
|
||||||
|
"r13b", "r13w", "r13d", "r13",
|
||||||
|
"r14b", "r14w", "r14d", "r14",
|
||||||
|
"r15b", "r15w", "r15d", "r15",
|
||||||
|
|
||||||
|
"sil", "si", "esi", "rsi",
|
||||||
|
"dil", "di", "edi", "rdi",
|
||||||
|
|
||||||
|
"rbp",
|
||||||
|
"rsp",
|
||||||
|
|
||||||
|
"xmm0",
|
||||||
|
"xmm1",
|
||||||
|
"xmm2",
|
||||||
|
"xmm3",
|
||||||
|
"xmm4",
|
||||||
|
"xmm5",
|
||||||
|
"xmm6",
|
||||||
|
"xmm7",
|
||||||
|
"xmm8",
|
||||||
|
"xmm9",
|
||||||
|
"xmm10",
|
||||||
|
"xmm11",
|
||||||
|
"xmm12",
|
||||||
|
"xmm13",
|
||||||
|
"xmm14",
|
||||||
|
"xmm15",
|
||||||
|
};
|
||||||
|
} // namespace lir
|
||||||
|
} // namespace x64
|
||||||
|
} // namespace backend
|
||||||
|
} // namespace alloy
|
||||||
|
|
||||||
|
|
||||||
|
void LIRInstr::Remove() {
|
||||||
|
if (next) {
|
||||||
|
next->prev = prev;
|
||||||
|
}
|
||||||
|
if (prev) {
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
if (block->instr_head == this) {
|
||||||
|
block->instr_head = next;
|
||||||
|
}
|
||||||
|
if (block->instr_tail == this) {
|
||||||
|
block->instr_tail = prev;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,9 +25,7 @@ namespace x64 {
|
||||||
namespace lir {
|
namespace lir {
|
||||||
|
|
||||||
|
|
||||||
enum LIRRegister {
|
enum class LIRRegisterName : uint32_t {
|
||||||
REG8, REG16, REG32, REG64, REGXMM,
|
|
||||||
|
|
||||||
AL, AX, EAX, RAX,
|
AL, AX, EAX, RAX,
|
||||||
BL, BX, EBX, RBX,
|
BL, BX, EBX, RBX,
|
||||||
CL, CX, ECX, RCX,
|
CL, CX, ECX, RCX,
|
||||||
|
@ -63,22 +61,47 @@ enum LIRRegister {
|
||||||
XMM13,
|
XMM13,
|
||||||
XMM14,
|
XMM14,
|
||||||
XMM15,
|
XMM15,
|
||||||
|
|
||||||
|
VREG0 = 0x10000000,
|
||||||
|
};
|
||||||
|
extern const char* register_names[74];
|
||||||
|
|
||||||
|
enum class LIRRegisterType : uint32_t {
|
||||||
|
REG8,
|
||||||
|
REG16,
|
||||||
|
REG32,
|
||||||
|
REG64,
|
||||||
|
REGXMM,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef union {
|
typedef struct LIRRegister_s {
|
||||||
runtime::FunctionInfo* symbol_info;
|
LIRRegisterType type;
|
||||||
LIRLabel* label;
|
union {
|
||||||
LIRRegister reg;
|
uint32_t id;
|
||||||
int8_t i8;
|
LIRRegisterName name;
|
||||||
int16_t i16;
|
};
|
||||||
int32_t i32;
|
struct LIRRegister_s(LIRRegisterType _type, uint32_t _id) :
|
||||||
int64_t i64;
|
type(_type), id((uint32_t)LIRRegisterName::VREG0 + _id) {}
|
||||||
float f32;
|
struct LIRRegister_s(LIRRegisterType _type, LIRRegisterName _name) :
|
||||||
double f64;
|
type(_type), name(_name) {}
|
||||||
uint64_t offset;
|
bool is_virtual() const { return id > (uint32_t)LIRRegisterName::VREG0; }
|
||||||
char* string;
|
} LIRRegister;
|
||||||
} LIROperand;
|
|
||||||
|
|
||||||
|
enum class LIROperandType : uint8_t {
|
||||||
|
NONE = 0,
|
||||||
|
FUNCTION,
|
||||||
|
LABEL,
|
||||||
|
OFFSET,
|
||||||
|
STRING,
|
||||||
|
REGISTER,
|
||||||
|
INT8_CONSTANT,
|
||||||
|
INT16_CONSTANT,
|
||||||
|
INT32_CONSTANT,
|
||||||
|
INT64_CONSTANT,
|
||||||
|
FLOAT32_CONSTANT,
|
||||||
|
FLOAT64_CONSTANT,
|
||||||
|
VEC128_CONSTANT,
|
||||||
|
};
|
||||||
|
|
||||||
class LIRInstr {
|
class LIRInstr {
|
||||||
public:
|
public:
|
||||||
|
@ -89,8 +112,28 @@ public:
|
||||||
const LIROpcodeInfo* opcode;
|
const LIROpcodeInfo* opcode;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
|
|
||||||
// TODO(benvanik): make this variable width?
|
struct {
|
||||||
LIROperand arg[4];
|
LIROperandType arg0;
|
||||||
|
LIROperandType arg1;
|
||||||
|
LIROperandType arg2;
|
||||||
|
LIROperandType arg3;
|
||||||
|
} arg_types;
|
||||||
|
struct {
|
||||||
|
uint8_t arg0;
|
||||||
|
uint8_t arg1;
|
||||||
|
uint8_t arg2;
|
||||||
|
uint8_t arg3;
|
||||||
|
} arg_offsets;
|
||||||
|
LIROperandType arg0_type() const { return arg_types.arg0; }
|
||||||
|
LIROperandType arg1_type() const { return arg_types.arg1; }
|
||||||
|
LIROperandType arg2_type() const { return arg_types.arg2; }
|
||||||
|
LIROperandType arg3_type() const { return arg_types.arg3; }
|
||||||
|
template<typename T> T* arg0() { return (T*)(((uint8_t*)this) + arg_offsets.arg0); }
|
||||||
|
template<typename T> T* arg1() { return (T*)(((uint8_t*)this) + arg_offsets.arg1); }
|
||||||
|
template<typename T> T* arg2() { return (T*)(((uint8_t*)this) + arg_offsets.arg2); }
|
||||||
|
template<typename T> T* arg3() { return (T*)(((uint8_t*)this) + arg_offsets.arg3); }
|
||||||
|
|
||||||
|
void Remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,18 +20,20 @@ namespace lir {
|
||||||
|
|
||||||
|
|
||||||
enum LIROpcode {
|
enum LIROpcode {
|
||||||
LIR_OPCODE_COMMENT,
|
|
||||||
LIR_OPCODE_NOP,
|
LIR_OPCODE_NOP,
|
||||||
|
|
||||||
|
LIR_OPCODE_COMMENT,
|
||||||
LIR_OPCODE_SOURCE_OFFSET,
|
LIR_OPCODE_SOURCE_OFFSET,
|
||||||
|
|
||||||
LIR_OPCODE_DEBUG_BREAK,
|
LIR_OPCODE_DEBUG_BREAK,
|
||||||
LIR_OPCODE_TRAP,
|
LIR_OPCODE_TRAP,
|
||||||
|
|
||||||
LIR_OPCODE_MOV,
|
LIR_OPCODE_MOV,
|
||||||
|
LIR_OPCODE_MOV_ZX,
|
||||||
|
LIR_OPCODE_MOV_SX,
|
||||||
|
|
||||||
LIR_OPCODE_TEST,
|
LIR_OPCODE_TEST,
|
||||||
|
|
||||||
|
LIR_OPCODE_JUMP,
|
||||||
LIR_OPCODE_JUMP_EQ,
|
LIR_OPCODE_JUMP_EQ,
|
||||||
LIR_OPCODE_JUMP_NE,
|
LIR_OPCODE_JUMP_NE,
|
||||||
|
|
||||||
|
|
|
@ -7,26 +7,23 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
|
||||||
LIR_OPCODE_COMMENT,
|
|
||||||
"comment",
|
|
||||||
LIR_OPCODE_FLAG_IGNORE)
|
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
LIR_OPCODE_NOP,
|
LIR_OPCODE_NOP,
|
||||||
"nop",
|
"nop",
|
||||||
LIR_OPCODE_FLAG_IGNORE)
|
LIR_OPCODE_FLAG_IGNORE)
|
||||||
|
|
||||||
|
DEFINE_OPCODE(
|
||||||
|
LIR_OPCODE_COMMENT,
|
||||||
|
"comment",
|
||||||
|
LIR_OPCODE_FLAG_IGNORE)
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
LIR_OPCODE_SOURCE_OFFSET,
|
LIR_OPCODE_SOURCE_OFFSET,
|
||||||
"source_offset",
|
"source_offset",
|
||||||
LIR_OPCODE_FLAG_IGNORE | LIR_OPCODE_FLAG_HIDE)
|
LIR_OPCODE_FLAG_IGNORE | LIR_OPCODE_FLAG_HIDE)
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
LIR_OPCODE_DEBUG_BREAK,
|
LIR_OPCODE_DEBUG_BREAK,
|
||||||
"debug_break",
|
"debug_break",
|
||||||
0)
|
0)
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
LIR_OPCODE_TRAP,
|
LIR_OPCODE_TRAP,
|
||||||
"trap",
|
"trap",
|
||||||
|
@ -36,17 +33,28 @@ DEFINE_OPCODE(
|
||||||
LIR_OPCODE_MOV,
|
LIR_OPCODE_MOV,
|
||||||
"mov",
|
"mov",
|
||||||
0)
|
0)
|
||||||
|
DEFINE_OPCODE(
|
||||||
|
LIR_OPCODE_MOV_ZX,
|
||||||
|
"mov_zx",
|
||||||
|
0)
|
||||||
|
DEFINE_OPCODE(
|
||||||
|
LIR_OPCODE_MOV_SX,
|
||||||
|
"mov_sx",
|
||||||
|
0)
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
LIR_OPCODE_TEST,
|
LIR_OPCODE_TEST,
|
||||||
"test",
|
"test",
|
||||||
0)
|
0)
|
||||||
|
|
||||||
|
DEFINE_OPCODE(
|
||||||
|
LIR_OPCODE_JUMP,
|
||||||
|
"jump",
|
||||||
|
0)
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
LIR_OPCODE_JUMP_EQ,
|
LIR_OPCODE_JUMP_EQ,
|
||||||
"jump_eq",
|
"jump_eq",
|
||||||
0)
|
0)
|
||||||
|
|
||||||
DEFINE_OPCODE(
|
DEFINE_OPCODE(
|
||||||
LIR_OPCODE_JUMP_NE,
|
LIR_OPCODE_JUMP_NE,
|
||||||
"jump_ne",
|
"jump_ne",
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
'lir_block.h',
|
'lir_block.h',
|
||||||
'lir_builder.cc',
|
'lir_builder.cc',
|
||||||
'lir_builder.h',
|
'lir_builder.h',
|
||||||
|
'lir_instr.cc',
|
||||||
'lir_instr.h',
|
'lir_instr.h',
|
||||||
'lir_label.h',
|
'lir_label.h',
|
||||||
'lir_opcodes.cc',
|
'lir_opcodes.cc',
|
||||||
|
|
|
@ -90,7 +90,11 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
||||||
});
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_CALL_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_CALL_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
|
auto skip_label = lb.NewLocalLabel();
|
||||||
|
lb.Test(instr->src1.value, instr->src1.value);
|
||||||
|
lb.JumpNE(skip_label);
|
||||||
// TODO
|
// TODO
|
||||||
|
lb.MarkLabel(skip_label);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -102,7 +106,11 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
||||||
});
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_CALL_INDIRECT_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_CALL_INDIRECT_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
|
auto skip_label = lb.NewLocalLabel();
|
||||||
|
lb.Test(instr->src1.value, instr->src1.value);
|
||||||
|
lb.JumpNE(skip_label);
|
||||||
// TODO
|
// TODO
|
||||||
|
lb.MarkLabel(skip_label);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -124,19 +132,24 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
table->AddSequence(OPCODE_BRANCH, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_BRANCH, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
auto target = (LIRLabel*)instr->src1.label->tag;
|
||||||
|
lb.Jump(target);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_BRANCH_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_BRANCH_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
lb.Test(instr->src1.value, instr->src1.value);
|
||||||
|
auto target = (LIRLabel*)instr->src2.label->tag;
|
||||||
|
lb.JumpEQ(target);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_BRANCH_FALSE, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_BRANCH_FALSE, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
lb.Test(instr->src1.value, instr->src1.value);
|
||||||
|
auto target = (LIRLabel*)instr->src2.label->tag;
|
||||||
|
lb.JumpNE(target);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -146,31 +159,31 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
table->AddSequence(OPCODE_ASSIGN, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_ASSIGN, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
lb.Mov(instr->dest, instr->src1.value);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_CAST, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_CAST, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
lb.Mov(instr->dest, instr->src1.value);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_ZERO_EXTEND, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_ZERO_EXTEND, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
lb.MovZX(instr->dest, instr->src1.value);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_SIGN_EXTEND, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_SIGN_EXTEND, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
lb.MovSX(instr->dest, instr->src1.value);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_TRUNCATE, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_TRUNCATE, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
lb.Mov(instr->dest, instr->src1.value);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -222,13 +235,19 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
table->AddSequence(OPCODE_LOAD_CONTEXT, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_LOAD_CONTEXT, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
lb.Mov(
|
||||||
|
instr->dest,
|
||||||
|
LIRRegister(LIRRegisterType::REG64, LIRRegisterName::RCX),
|
||||||
|
instr->src1.offset);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
table->AddSequence(OPCODE_STORE_CONTEXT, [](LIRBuilder& lb, Instr*& instr) {
|
table->AddSequence(OPCODE_STORE_CONTEXT, [](LIRBuilder& lb, Instr*& instr) {
|
||||||
// TODO
|
lb.Mov(
|
||||||
|
LIRRegister(LIRRegisterType::REG64, LIRRegisterName::RCX),
|
||||||
|
instr->src1.offset,
|
||||||
|
instr->src2.value);
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#ifndef ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_
|
#ifndef ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_
|
||||||
#define ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_
|
#define ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_
|
||||||
|
|
||||||
|
#include <alloy/backend/x64/optimizer/passes/reachability_pass.h>
|
||||||
#include <alloy/backend/x64/optimizer/passes/redundant_mov_pass.h>
|
#include <alloy/backend/x64/optimizer/passes/redundant_mov_pass.h>
|
||||||
|
|
||||||
#endif // ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_
|
#endif // ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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/backend/x64/optimizer/passes/reachability_pass.h>
|
||||||
|
|
||||||
|
using namespace alloy;
|
||||||
|
using namespace alloy::backend::x64::lir;
|
||||||
|
using namespace alloy::backend::x64::optimizer;
|
||||||
|
using namespace alloy::backend::x64::optimizer::passes;
|
||||||
|
|
||||||
|
|
||||||
|
ReachabilityPass::ReachabilityPass() :
|
||||||
|
OptimizerPass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ReachabilityPass::~ReachabilityPass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReachabilityPass::Run(LIRBuilder* builder) {
|
||||||
|
// Run through blocks. If blocks have no incoming edges remove them.
|
||||||
|
// Afterwards, remove any unneeded jumps (jumping to the next block).
|
||||||
|
|
||||||
|
// TODO(benvanik): dead block removal.
|
||||||
|
|
||||||
|
auto block = builder->first_block();
|
||||||
|
while (block) {
|
||||||
|
auto tail = block->instr_tail;
|
||||||
|
if (tail && tail->opcode == &LIR_OPCODE_JUMP_info) {
|
||||||
|
// Jump. Check target.
|
||||||
|
if (tail->arg0_type() == LIROperandType::LABEL) {
|
||||||
|
auto target = *tail->arg0<LIRLabel*>();
|
||||||
|
if (target->block == block->next) {
|
||||||
|
// Jumping to subsequent block. Remove.
|
||||||
|
tail->Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block = block->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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_BACKEND_X64_OPTIMIZER_PASSES_REACHABILITY_PASS_H_
|
||||||
|
#define ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REACHABILITY_PASS_H_
|
||||||
|
|
||||||
|
#include <alloy/backend/x64/optimizer/optimizer_pass.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace alloy {
|
||||||
|
namespace backend {
|
||||||
|
namespace x64 {
|
||||||
|
namespace optimizer {
|
||||||
|
namespace passes {
|
||||||
|
|
||||||
|
|
||||||
|
class ReachabilityPass : public OptimizerPass {
|
||||||
|
public:
|
||||||
|
ReachabilityPass();
|
||||||
|
virtual ~ReachabilityPass();
|
||||||
|
|
||||||
|
virtual int Run(lir::LIRBuilder* builder);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace passes
|
||||||
|
} // namespace optimizer
|
||||||
|
} // namespace x64
|
||||||
|
} // namespace backend
|
||||||
|
} // namespace alloy
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REACHABILITY_PASS_H_
|
|
@ -7,8 +7,8 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ALLOY_COMPILER_PASSES_SIMPLIFICATION_PASS_H_
|
#ifndef ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REDUNDANT_MOV_PASS_H_
|
||||||
#define ALLOY_COMPILER_PASSES_SIMPLIFICATION_PASS_H_
|
#define ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REDUNDANT_MOV_PASS_H_
|
||||||
|
|
||||||
#include <alloy/backend/x64/optimizer/optimizer_pass.h>
|
#include <alloy/backend/x64/optimizer/optimizer_pass.h>
|
||||||
|
|
||||||
|
@ -36,4 +36,4 @@ public:
|
||||||
} // namespace alloy
|
} // namespace alloy
|
||||||
|
|
||||||
|
|
||||||
#endif // ALLOY_COMPILER_PASSES_SIMPLIFICATION_PASS_H_
|
#endif // ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REDUNDANT_MOV_PASS_H_
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||||
{
|
{
|
||||||
'sources': [
|
'sources': [
|
||||||
|
'reachability_pass.cc',
|
||||||
|
'reachability_pass.h',
|
||||||
'redundant_mov_pass.cc',
|
'redundant_mov_pass.cc',
|
||||||
'redundant_mov_pass.h',
|
'redundant_mov_pass.h',
|
||||||
],
|
],
|
||||||
|
|
|
@ -61,6 +61,7 @@ int X64Assembler::Initialize() {
|
||||||
|
|
||||||
optimizer_ = new Optimizer(backend_->runtime());
|
optimizer_ = new Optimizer(backend_->runtime());
|
||||||
optimizer_->AddPass(new passes::RedundantMovPass());
|
optimizer_->AddPass(new passes::RedundantMovPass());
|
||||||
|
optimizer_->AddPass(new passes::ReachabilityPass());
|
||||||
|
|
||||||
emitter_ = new X64Emitter(x64_backend_);
|
emitter_ = new X64Emitter(x64_backend_);
|
||||||
|
|
||||||
|
|
|
@ -159,5 +159,65 @@ int XbyakGenerator::Emit(LIRBuilder* builder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int XbyakGenerator::EmitInstruction(LIRInstr* instr) {
|
int XbyakGenerator::EmitInstruction(LIRInstr* instr) {
|
||||||
|
switch (instr->opcode->num) {
|
||||||
|
case LIR_OPCODE_NOP:
|
||||||
|
nop();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIR_OPCODE_COMMENT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIR_OPCODE_SOURCE_OFFSET:
|
||||||
|
break;
|
||||||
|
case LIR_OPCODE_DEBUG_BREAK:
|
||||||
|
// TODO(benvanik): replace with debugging primitive.
|
||||||
|
db(0xCC);
|
||||||
|
break;
|
||||||
|
case LIR_OPCODE_TRAP:
|
||||||
|
// TODO(benvanik): replace with debugging primitive.
|
||||||
|
db(0xCC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIR_OPCODE_MOV:
|
||||||
|
if (instr->arg1_type() == LIROperandType::OFFSET) {
|
||||||
|
// mov [reg+offset], value
|
||||||
|
mov(ptr[rax + *instr->arg1<intptr_t>()], rbx);
|
||||||
|
} else if (instr->arg2_type() == LIROperandType::OFFSET) {
|
||||||
|
// mov reg, [reg+offset]
|
||||||
|
mov(rbx, ptr[rax + *instr->arg2<intptr_t>()]);
|
||||||
|
} else {
|
||||||
|
// mov reg, reg
|
||||||
|
mov(rax, rbx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIR_OPCODE_MOV_ZX:
|
||||||
|
//mov
|
||||||
|
break;
|
||||||
|
case LIR_OPCODE_MOV_SX:
|
||||||
|
//mov
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIR_OPCODE_TEST:
|
||||||
|
if (instr->arg0_type() == LIROperandType::REGISTER) {
|
||||||
|
if (instr->arg1_type() == LIROperandType::REGISTER) {
|
||||||
|
//test(instr->arg0<LIRRegister>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIR_OPCODE_JUMP_EQ: {
|
||||||
|
auto target = (*instr->arg0<LIRLabel*>());
|
||||||
|
je(target->name, T_NEAR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LIR_OPCODE_JUMP_NE: {
|
||||||
|
auto target = (*instr->arg0<LIRLabel*>());
|
||||||
|
jne(target->name, T_NEAR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Unhandled.
|
||||||
|
break;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <alloy/hir/block.h>
|
#include <alloy/hir/block.h>
|
||||||
#include <alloy/hir/instr.h>
|
#include <alloy/hir/instr.h>
|
||||||
#include <alloy/hir/label.h>
|
#include <alloy/hir/label.h>
|
||||||
|
#include <alloy/runtime/symbol_info.h>
|
||||||
|
|
||||||
using namespace alloy;
|
using namespace alloy;
|
||||||
using namespace alloy::hir;
|
using namespace alloy::hir;
|
||||||
|
@ -120,10 +121,13 @@ void HIRBuilder::DumpOp(
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPCODE_SIG_TYPE_O:
|
case OPCODE_SIG_TYPE_O:
|
||||||
str->Append("+%d", op->offset);
|
str->Append("+%lld", op->offset);
|
||||||
break;
|
break;
|
||||||
case OPCODE_SIG_TYPE_S:
|
case OPCODE_SIG_TYPE_S:
|
||||||
str->Append("<function>");
|
if (true) {
|
||||||
|
auto target = op->symbol_info;
|
||||||
|
str->Append(target->name() ? target->name() : "<fn>");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case OPCODE_SIG_TYPE_V:
|
case OPCODE_SIG_TYPE_V:
|
||||||
DumpValue(str, op->value);
|
DumpValue(str, op->value);
|
||||||
|
|
|
@ -64,6 +64,7 @@ public:
|
||||||
Instr* def;
|
Instr* def;
|
||||||
Use* use_head;
|
Use* use_head;
|
||||||
|
|
||||||
|
// TODO(benvanik): remove to shrink size.
|
||||||
void* tag;
|
void* tag;
|
||||||
|
|
||||||
Use* AddUse(Arena* arena, Instr* instr);
|
Use* AddUse(Arena* arena, Instr* instr);
|
||||||
|
|
Loading…
Reference in New Issue