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/runtime/symbol_info.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend::x64;
|
||||
using namespace alloy::backend::x64::lir;
|
||||
|
@ -72,7 +74,7 @@ void LIRBuilder::Dump(StringBuffer* str) {
|
|||
continue;
|
||||
}
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
@ -84,7 +86,22 @@ void LIRBuilder::Dump(StringBuffer* str) {
|
|||
} else {
|
||||
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");
|
||||
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 {
|
||||
return current_block_;
|
||||
}
|
||||
|
@ -192,65 +292,87 @@ LIRInstr* LIRBuilder::AppendInstr(
|
|||
instr->block = block;
|
||||
instr->opcode = &opcode_info;
|
||||
instr->flags = flags;
|
||||
instr->arg_types = {
|
||||
LIROperandType::NONE,
|
||||
LIROperandType::NONE,
|
||||
LIROperandType::NONE,
|
||||
LIROperandType::NONE
|
||||
};
|
||||
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, ...) {
|
||||
char buffer[1024];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
xevsnprintfa(buffer, 1024, format, 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);
|
||||
instr->arg[0].string = (char*)p;
|
||||
}
|
||||
|
||||
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);
|
||||
instr->arg_offsets.arg0 =
|
||||
AppendOperand(instr, instr->arg_types.arg0, buffer);
|
||||
}
|
||||
|
|
|
@ -50,27 +50,124 @@ public:
|
|||
LIRBlock* AppendBlock();
|
||||
void EndBlock();
|
||||
|
||||
void Nop() { AppendInstr(LIR_OPCODE_NOP_info, 0); }
|
||||
|
||||
void Comment(const char* format, ...);
|
||||
void Nop();
|
||||
void SourceOffset(uint64_t offset);
|
||||
void SourceOffset(uintptr_t offset) { AppendInstr(LIR_OPCODE_SOURCE_OFFSET_info, 0, offset); }
|
||||
void DebugBreak() { AppendInstr(LIR_OPCODE_DEBUG_BREAK_info, 0); }
|
||||
void Trap() { AppendInstr(LIR_OPCODE_TRAP_info, 0); }
|
||||
|
||||
void DebugBreak();
|
||||
void Trap();
|
||||
template<typename A0, typename A1>
|
||||
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);
|
||||
void Test(int16_t a, int16_t b);
|
||||
void Test(int32_t a, int32_t b);
|
||||
void Test(int64_t a, int64_t b);
|
||||
void Test(hir::Value* a, hir::Value* b);
|
||||
|
||||
void JumpEQ(LIRLabel* label);
|
||||
void JumpNE(LIRLabel* label);
|
||||
template<typename A0>
|
||||
void Jump(A0& target) { AppendInstr(LIR_OPCODE_JUMP_info, 0, target); }
|
||||
void JumpEQ(LIRLabel* target) { AppendInstr(LIR_OPCODE_JUMP_EQ_info, 0, target); }
|
||||
void JumpNE(LIRLabel* target) { AppendInstr(LIR_OPCODE_JUMP_NE_info, 0, target); }
|
||||
|
||||
private:
|
||||
void DumpArg(StringBuffer* str, LIROperandType type, intptr_t ptr);
|
||||
|
||||
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:
|
||||
X64Backend* backend_;
|
||||
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 {
|
||||
|
||||
|
||||
enum LIRRegister {
|
||||
REG8, REG16, REG32, REG64, REGXMM,
|
||||
|
||||
enum class LIRRegisterName : uint32_t {
|
||||
AL, AX, EAX, RAX,
|
||||
BL, BX, EBX, RBX,
|
||||
CL, CX, ECX, RCX,
|
||||
|
@ -63,22 +61,47 @@ enum LIRRegister {
|
|||
XMM13,
|
||||
XMM14,
|
||||
XMM15,
|
||||
|
||||
VREG0 = 0x10000000,
|
||||
};
|
||||
extern const char* register_names[74];
|
||||
|
||||
enum class LIRRegisterType : uint32_t {
|
||||
REG8,
|
||||
REG16,
|
||||
REG32,
|
||||
REG64,
|
||||
REGXMM,
|
||||
};
|
||||
|
||||
typedef union {
|
||||
runtime::FunctionInfo* symbol_info;
|
||||
LIRLabel* label;
|
||||
LIRRegister reg;
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
float f32;
|
||||
double f64;
|
||||
uint64_t offset;
|
||||
char* string;
|
||||
} LIROperand;
|
||||
typedef struct LIRRegister_s {
|
||||
LIRRegisterType type;
|
||||
union {
|
||||
uint32_t id;
|
||||
LIRRegisterName name;
|
||||
};
|
||||
struct LIRRegister_s(LIRRegisterType _type, uint32_t _id) :
|
||||
type(_type), id((uint32_t)LIRRegisterName::VREG0 + _id) {}
|
||||
struct LIRRegister_s(LIRRegisterType _type, LIRRegisterName _name) :
|
||||
type(_type), name(_name) {}
|
||||
bool is_virtual() const { return id > (uint32_t)LIRRegisterName::VREG0; }
|
||||
} LIRRegister;
|
||||
|
||||
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 {
|
||||
public:
|
||||
|
@ -89,8 +112,28 @@ public:
|
|||
const LIROpcodeInfo* opcode;
|
||||
uint16_t flags;
|
||||
|
||||
// TODO(benvanik): make this variable width?
|
||||
LIROperand arg[4];
|
||||
struct {
|
||||
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 {
|
||||
LIR_OPCODE_COMMENT,
|
||||
LIR_OPCODE_NOP,
|
||||
|
||||
LIR_OPCODE_COMMENT,
|
||||
LIR_OPCODE_SOURCE_OFFSET,
|
||||
|
||||
LIR_OPCODE_DEBUG_BREAK,
|
||||
LIR_OPCODE_TRAP,
|
||||
|
||||
LIR_OPCODE_MOV,
|
||||
LIR_OPCODE_MOV_ZX,
|
||||
LIR_OPCODE_MOV_SX,
|
||||
|
||||
LIR_OPCODE_TEST,
|
||||
|
||||
LIR_OPCODE_JUMP,
|
||||
LIR_OPCODE_JUMP_EQ,
|
||||
LIR_OPCODE_JUMP_NE,
|
||||
|
||||
|
|
|
@ -7,26 +7,23 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_COMMENT,
|
||||
"comment",
|
||||
LIR_OPCODE_FLAG_IGNORE)
|
||||
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_NOP,
|
||||
"nop",
|
||||
LIR_OPCODE_FLAG_IGNORE)
|
||||
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_COMMENT,
|
||||
"comment",
|
||||
LIR_OPCODE_FLAG_IGNORE)
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_SOURCE_OFFSET,
|
||||
"source_offset",
|
||||
LIR_OPCODE_FLAG_IGNORE | LIR_OPCODE_FLAG_HIDE)
|
||||
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_DEBUG_BREAK,
|
||||
"debug_break",
|
||||
0)
|
||||
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_TRAP,
|
||||
"trap",
|
||||
|
@ -36,17 +33,28 @@ DEFINE_OPCODE(
|
|||
LIR_OPCODE_MOV,
|
||||
"mov",
|
||||
0)
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_MOV_ZX,
|
||||
"mov_zx",
|
||||
0)
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_MOV_SX,
|
||||
"mov_sx",
|
||||
0)
|
||||
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_TEST,
|
||||
"test",
|
||||
0)
|
||||
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_JUMP,
|
||||
"jump",
|
||||
0)
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_JUMP_EQ,
|
||||
"jump_eq",
|
||||
0)
|
||||
|
||||
DEFINE_OPCODE(
|
||||
LIR_OPCODE_JUMP_NE,
|
||||
"jump_ne",
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
'lir_block.h',
|
||||
'lir_builder.cc',
|
||||
'lir_builder.h',
|
||||
'lir_instr.cc',
|
||||
'lir_instr.h',
|
||||
'lir_label.h',
|
||||
'lir_opcodes.cc',
|
||||
|
|
|
@ -90,7 +90,11 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
});
|
||||
|
||||
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
|
||||
lb.MarkLabel(skip_label);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -102,7 +106,11 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
});
|
||||
|
||||
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
|
||||
lb.MarkLabel(skip_label);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -124,19 +132,24 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_BRANCH, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
auto target = (LIRLabel*)instr->src1.label->tag;
|
||||
lb.Jump(target);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
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;
|
||||
return true;
|
||||
});
|
||||
|
||||
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;
|
||||
return true;
|
||||
});
|
||||
|
@ -146,31 +159,31 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_ASSIGN, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
lb.Mov(instr->dest, instr->src1.value);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_CAST, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
lb.Mov(instr->dest, instr->src1.value);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_ZERO_EXTEND, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
lb.MovZX(instr->dest, instr->src1.value);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SIGN_EXTEND, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
lb.MovSX(instr->dest, instr->src1.value);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_TRUNCATE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
lb.Mov(instr->dest, instr->src1.value);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -222,13 +235,19 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// --------------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
return true;
|
||||
});
|
||||
|
||||
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;
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef 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>
|
||||
|
||||
#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_
|
||||
#define ALLOY_COMPILER_PASSES_SIMPLIFICATION_PASS_H_
|
||||
#ifndef ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REDUNDANT_MOV_PASS_H_
|
||||
#define ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REDUNDANT_MOV_PASS_H_
|
||||
|
||||
#include <alloy/backend/x64/optimizer/optimizer_pass.h>
|
||||
|
||||
|
@ -36,4 +36,4 @@ public:
|
|||
} // 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.
|
||||
{
|
||||
'sources': [
|
||||
'reachability_pass.cc',
|
||||
'reachability_pass.h',
|
||||
'redundant_mov_pass.cc',
|
||||
'redundant_mov_pass.h',
|
||||
],
|
||||
|
|
|
@ -61,6 +61,7 @@ int X64Assembler::Initialize() {
|
|||
|
||||
optimizer_ = new Optimizer(backend_->runtime());
|
||||
optimizer_->AddPass(new passes::RedundantMovPass());
|
||||
optimizer_->AddPass(new passes::ReachabilityPass());
|
||||
|
||||
emitter_ = new X64Emitter(x64_backend_);
|
||||
|
||||
|
|
|
@ -159,5 +159,65 @@ int XbyakGenerator::Emit(LIRBuilder* builder) {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <alloy/hir/block.h>
|
||||
#include <alloy/hir/instr.h>
|
||||
#include <alloy/hir/label.h>
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::hir;
|
||||
|
@ -120,10 +121,13 @@ void HIRBuilder::DumpOp(
|
|||
}
|
||||
break;
|
||||
case OPCODE_SIG_TYPE_O:
|
||||
str->Append("+%d", op->offset);
|
||||
str->Append("+%lld", op->offset);
|
||||
break;
|
||||
case OPCODE_SIG_TYPE_S:
|
||||
str->Append("<function>");
|
||||
if (true) {
|
||||
auto target = op->symbol_info;
|
||||
str->Append(target->name() ? target->name() : "<fn>");
|
||||
}
|
||||
break;
|
||||
case OPCODE_SIG_TYPE_V:
|
||||
DumpValue(str, op->value);
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
Instr* def;
|
||||
Use* use_head;
|
||||
|
||||
// TODO(benvanik): remove to shrink size.
|
||||
void* tag;
|
||||
|
||||
Use* AddUse(Arena* arena, Instr* instr);
|
||||
|
|
Loading…
Reference in New Issue