diff --git a/src/alloy/backend/x64/lir/lir_builder.cc b/src/alloy/backend/x64/lir/lir_builder.cc index f683a1bac..52e888582 100644 --- a/src/alloy/backend/x64/lir/lir_builder.cc +++ b/src/alloy/backend/x64/lir/lir_builder.cc @@ -9,6 +9,8 @@ #include +#include + 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()); 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() : ""); + } + 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); } diff --git a/src/alloy/backend/x64/lir/lir_builder.h b/src/alloy/backend/x64/lir/lir_builder.h index be7e9e2e3..d52a2a611 100644 --- a/src/alloy/backend/x64/lir/lir_builder.h +++ b/src/alloy/backend/x64/lir/lir_builder.h @@ -49,28 +49,125 @@ 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 + void Mov(A0& a, A1& b) { AppendInstr(LIR_OPCODE_MOV_info, 0, a, b); } + template + void Mov(A0& a, A1& b, A2& c) { AppendInstr(LIR_OPCODE_MOV_info, 0, a, b, c); } + template + void MovZX(A0& a, A1& b) { AppendInstr(LIR_OPCODE_MOV_ZX_info, 0, a, b); } + template + void MovSX(A0& a, A1& b) { AppendInstr(LIR_OPCODE_MOV_ZX_info, 0, a, b); } - void Mov(); + template + 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 + 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 + uint8_t AppendOperand(LIRInstr* instr, LIROperandType& type, T& value) { + type = GetOperandType(value); + auto ptr = arena_->Alloc(); + *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 + 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 + 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 + 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 + 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_; diff --git a/src/alloy/backend/x64/lir/lir_instr.cc b/src/alloy/backend/x64/lir/lir_instr.cc new file mode 100644 index 000000000..ebed724f7 --- /dev/null +++ b/src/alloy/backend/x64/lir/lir_instr.cc @@ -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 + +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; + } +} diff --git a/src/alloy/backend/x64/lir/lir_instr.h b/src/alloy/backend/x64/lir/lir_instr.h index 6d3841f4c..720257457 100644 --- a/src/alloy/backend/x64/lir/lir_instr.h +++ b/src/alloy/backend/x64/lir/lir_instr.h @@ -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 T* arg0() { return (T*)(((uint8_t*)this) + arg_offsets.arg0); } + template T* arg1() { return (T*)(((uint8_t*)this) + arg_offsets.arg1); } + template T* arg2() { return (T*)(((uint8_t*)this) + arg_offsets.arg2); } + template T* arg3() { return (T*)(((uint8_t*)this) + arg_offsets.arg3); } + + void Remove(); }; diff --git a/src/alloy/backend/x64/lir/lir_opcodes.h b/src/alloy/backend/x64/lir/lir_opcodes.h index c86ee1a53..94d2291a2 100644 --- a/src/alloy/backend/x64/lir/lir_opcodes.h +++ b/src/alloy/backend/x64/lir/lir_opcodes.h @@ -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, diff --git a/src/alloy/backend/x64/lir/lir_opcodes.inl b/src/alloy/backend/x64/lir/lir_opcodes.inl index 9ce9dfcf2..906bab43d 100644 --- a/src/alloy/backend/x64/lir/lir_opcodes.inl +++ b/src/alloy/backend/x64/lir/lir_opcodes.inl @@ -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", diff --git a/src/alloy/backend/x64/lir/sources.gypi b/src/alloy/backend/x64/lir/sources.gypi index 7384e318d..df897c23b 100644 --- a/src/alloy/backend/x64/lir/sources.gypi +++ b/src/alloy/backend/x64/lir/sources.gypi @@ -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', diff --git a/src/alloy/backend/x64/lowering/lowering_sequences.cc b/src/alloy/backend/x64/lowering/lowering_sequences.cc index 0c9e25a5a..76eb10e74 100644 --- a/src/alloy/backend/x64/lowering/lowering_sequences.cc +++ b/src/alloy/backend/x64/lowering/lowering_sequences.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; }); diff --git a/src/alloy/backend/x64/optimizer/optimizer_passes.h b/src/alloy/backend/x64/optimizer/optimizer_passes.h index 2c2a0e5dd..6e1bb559c 100644 --- a/src/alloy/backend/x64/optimizer/optimizer_passes.h +++ b/src/alloy/backend/x64/optimizer/optimizer_passes.h @@ -10,6 +10,7 @@ #ifndef ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_ #define ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_ +#include #include #endif // ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_ diff --git a/src/alloy/backend/x64/optimizer/passes/reachability_pass.cc b/src/alloy/backend/x64/optimizer/passes/reachability_pass.cc new file mode 100644 index 000000000..77d542ecb --- /dev/null +++ b/src/alloy/backend/x64/optimizer/passes/reachability_pass.cc @@ -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 + +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(); + if (target->block == block->next) { + // Jumping to subsequent block. Remove. + tail->Remove(); + } + } + } + block = block->next; + } + + return 0; +} diff --git a/src/alloy/backend/x64/optimizer/passes/reachability_pass.h b/src/alloy/backend/x64/optimizer/passes/reachability_pass.h new file mode 100644 index 000000000..20f430d3c --- /dev/null +++ b/src/alloy/backend/x64/optimizer/passes/reachability_pass.h @@ -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 + + +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_ diff --git a/src/alloy/backend/x64/optimizer/passes/redundant_mov_pass.h b/src/alloy/backend/x64/optimizer/passes/redundant_mov_pass.h index 06796584d..7cac00fe4 100644 --- a/src/alloy/backend/x64/optimizer/passes/redundant_mov_pass.h +++ b/src/alloy/backend/x64/optimizer/passes/redundant_mov_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 @@ -36,4 +36,4 @@ public: } // namespace alloy -#endif // ALLOY_COMPILER_PASSES_SIMPLIFICATION_PASS_H_ +#endif // ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REDUNDANT_MOV_PASS_H_ diff --git a/src/alloy/backend/x64/optimizer/passes/sources.gypi b/src/alloy/backend/x64/optimizer/passes/sources.gypi index 4e1d4d4ef..933cc3bff 100644 --- a/src/alloy/backend/x64/optimizer/passes/sources.gypi +++ b/src/alloy/backend/x64/optimizer/passes/sources.gypi @@ -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', ], diff --git a/src/alloy/backend/x64/x64_assembler.cc b/src/alloy/backend/x64/x64_assembler.cc index 7a115e82b..ee123c1f2 100644 --- a/src/alloy/backend/x64/x64_assembler.cc +++ b/src/alloy/backend/x64/x64_assembler.cc @@ -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_); diff --git a/src/alloy/backend/x64/x64_emitter.cc b/src/alloy/backend/x64/x64_emitter.cc index 7d865b915..8f26e5a19 100644 --- a/src/alloy/backend/x64/x64_emitter.cc +++ b/src/alloy/backend/x64/x64_emitter.cc @@ -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()], rbx); + } else if (instr->arg2_type() == LIROperandType::OFFSET) { + // mov reg, [reg+offset] + mov(rbx, ptr[rax + *instr->arg2()]); + } 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()) + } + } + break; + + case LIR_OPCODE_JUMP_EQ: { + auto target = (*instr->arg0()); + je(target->name, T_NEAR); + break; + } + case LIR_OPCODE_JUMP_NE: { + auto target = (*instr->arg0()); + jne(target->name, T_NEAR); + break; + } + default: + // Unhandled. + break; + } return 0; } diff --git a/src/alloy/hir/hir_builder.cc b/src/alloy/hir/hir_builder.cc index 04a02eb04..a46b3fbfe 100644 --- a/src/alloy/hir/hir_builder.cc +++ b/src/alloy/hir/hir_builder.cc @@ -12,6 +12,7 @@ #include #include #include +#include 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(""); + if (true) { + auto target = op->symbol_info; + str->Append(target->name() ? target->name() : ""); + } break; case OPCODE_SIG_TYPE_V: DumpValue(str, op->value); diff --git a/src/alloy/hir/value.h b/src/alloy/hir/value.h index d96b800fa..8bf9f0135 100644 --- a/src/alloy/hir/value.h +++ b/src/alloy/hir/value.h @@ -64,6 +64,7 @@ public: Instr* def; Use* use_head; + // TODO(benvanik): remove to shrink size. void* tag; Use* AddUse(Arena* arena, Instr* instr);