Emitting more x64.

This commit is contained in:
Ben Vanik 2014-01-04 00:30:43 -08:00
parent 2468645bf2
commit 88b631b160
17 changed files with 633 additions and 109 deletions

View File

@ -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);
} }

View File

@ -49,28 +49,125 @@ 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_;

View File

@ -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;
}
}

View File

@ -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();
}; };

View File

@ -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,

View File

@ -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",

View File

@ -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',

View File

@ -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;
}); });

View File

@ -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_

View File

@ -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;
}

View File

@ -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_

View File

@ -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_

View File

@ -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',
], ],

View File

@ -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_);

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);