diff --git a/src/alloy/backend/x64/lir/lir_block.h b/src/alloy/backend/x64/lir/lir_block.h new file mode 100644 index 000000000..727171411 --- /dev/null +++ b/src/alloy/backend/x64/lir/lir_block.h @@ -0,0 +1,47 @@ +/** + ****************************************************************************** + * 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_LIR_LIR_BLOCK_H_ +#define ALLOY_BACKEND_X64_LIR_LIR_BLOCK_H_ + +#include + + +namespace alloy { +namespace backend { +namespace x64 { +namespace lir { + +class LIRBuilder; +class LIRInstr; +class LIRLabel; + + +class LIRBlock { +public: + Arena* arena; + + LIRBlock* next; + LIRBlock* prev; + + LIRLabel* label_head; + LIRLabel* label_tail; + + LIRInstr* instr_head; + LIRInstr* instr_tail; +}; + + +} // namespace lir +} // namespace x64 +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_X64_LIR_LIR_BLOCK_H_ diff --git a/src/alloy/backend/x64/lir/lir_builder.cc b/src/alloy/backend/x64/lir/lir_builder.cc index f92b64a37..a16e3dcb0 100644 --- a/src/alloy/backend/x64/lir/lir_builder.cc +++ b/src/alloy/backend/x64/lir/lir_builder.cc @@ -16,12 +16,20 @@ using namespace alloy::backend::x64::lir; LIRBuilder::LIRBuilder(X64Backend* backend) : backend_(backend) { + arena_ = new Arena(); + Reset(); } LIRBuilder::~LIRBuilder() { + Reset(); + delete arena_; } void LIRBuilder::Reset() { + next_label_id_ = 0; + block_head_ = block_tail_ = NULL; + current_block_ = NULL; + arena_->Reset(); } int LIRBuilder::Finalize() { @@ -29,4 +37,140 @@ int LIRBuilder::Finalize() { } void LIRBuilder::Dump(StringBuffer* str) { + uint32_t block_ordinal = 0; + auto block = block_head_; + while (block) { + if (block == block_head_) { + str->Append(":\n"); + } else if (!block->label_head) { + str->Append(":\n", block_ordinal); + } + block_ordinal++; + + auto label = block->label_head; + while (label) { + if (label->name) { + str->Append("%s:\n", label->name); + } else { + str->Append("label%d:\n", label->id); + } + label = label->next; + } + + auto i = block->instr_head; + while (i) { + if (i->opcode->flags & LIR_OPCODE_FLAG_HIDE) { + i = i->next; + continue; + } + + // TODO(benvanik): handle comment + + const LIROpcodeInfo* info = i->opcode; + str->Append(" "); + if (i->flags) { + str->Append("%s.%d", info->name, i->flags); + } else { + str->Append("%s", info->name); + } + // TODO(benvanik): args based on signature + str->Append("\n"); + i = i->next; + } + + block = block->next; + } +} + +LIRBlock* LIRBuilder::current_block() const { + return current_block_; +} + +LIRInstr* LIRBuilder::last_instr() const { + if (current_block_ && current_block_->instr_tail) { + return current_block_->instr_tail; + } else if (block_tail_) { + return block_tail_->instr_tail; + } + return NULL; +} + +LIRLabel* LIRBuilder::NewLabel() { + LIRLabel* label = arena_->Alloc(); + label->next = label->prev = NULL; + label->block = NULL; + label->id = next_label_id_++; + label->name = NULL; + return label; +} + +void LIRBuilder::MarkLabel(LIRLabel* label, LIRBlock* block) { + if (!block) { + if (current_block_ && current_block_->instr_tail) { + EndBlock(); + } + if (!current_block_) { + AppendBlock(); + } + block = current_block_; + } + label->block = block; + label->prev = block->label_tail; + label->next = NULL; + if (label->prev) { + label->prev->next = label; + block->label_tail = label; + } else { + block->label_head = block->label_tail = label; + } +} + +LIRBlock* LIRBuilder::AppendBlock() { + LIRBlock* block = arena_->Alloc(); + block->arena = arena_; + block->next = NULL; + block->prev = block_tail_; + if (block_tail_) { + block_tail_->next = block; + } + block_tail_ = block; + if (!block_head_) { + block_head_ = block; + } + current_block_ = block; + block->label_head = block->label_tail = NULL; + block->instr_head = block->instr_tail = NULL; + return block; +} + +void LIRBuilder::EndBlock() { + if (current_block_ && !current_block_->instr_tail) { + // Block never had anything added to it. Since it likely has an + // incoming edge, just keep it around. + return; + } + current_block_ = NULL; +} + +LIRInstr* LIRBuilder::AppendInstr( + const LIROpcodeInfo& opcode_info, uint16_t flags) { + if (!current_block_) { + AppendBlock(); + } + LIRBlock* block = current_block_; + + LIRInstr* instr = arena_->Alloc(); + instr->next = NULL; + instr->prev = block->instr_tail; + if (block->instr_tail) { + block->instr_tail->next = instr; + } + block->instr_tail = instr; + if (!block->instr_head) { + block->instr_head = instr; + } + instr->block = block; + instr->opcode = &opcode_info; + instr->flags = flags; + return instr; } diff --git a/src/alloy/backend/x64/lir/lir_builder.h b/src/alloy/backend/x64/lir/lir_builder.h index 46ddbfb35..0b1ecd04c 100644 --- a/src/alloy/backend/x64/lir/lir_builder.h +++ b/src/alloy/backend/x64/lir/lir_builder.h @@ -11,6 +11,9 @@ #define ALLOY_BACKEND_X64_LIR_LIR_BUILDER_H_ #include +#include +#include +#include #include @@ -33,9 +36,28 @@ public: Arena* arena() const { return arena_; } + LIRBlock* first_block() const { return block_head_; } + LIRBlock* current_block() const; + LIRInstr* last_instr() const; + + LIRLabel* NewLabel(); + void MarkLabel(LIRLabel* label, LIRBlock* block = 0); + + // TODO(benvanik): allocations + + LIRBlock* AppendBlock(); + void EndBlock(); + LIRInstr* AppendInstr(const LIROpcodeInfo& opcode, uint16_t flags); + protected: X64Backend* backend_; Arena* arena_; + + uint32_t next_label_id_; + + LIRBlock* block_head_; + LIRBlock* block_tail_; + LIRBlock* current_block_; }; diff --git a/src/alloy/backend/x64/lir/lir_instr.h b/src/alloy/backend/x64/lir/lir_instr.h index 0c72f23f4..53ddba3a5 100644 --- a/src/alloy/backend/x64/lir/lir_instr.h +++ b/src/alloy/backend/x64/lir/lir_instr.h @@ -11,17 +11,85 @@ #define ALLOY_BACKEND_X64_LIR_LIR_INSTR_H_ #include +#include +#include #include +namespace alloy { namespace runtime { class FunctionInfo; } } + + namespace alloy { namespace backend { namespace x64 { namespace lir { +enum LIRRegister { + REG8, REG16, REG32, REG64, REGXMM, + + 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, +}; + + class LIRInstr { public: + LIRBlock* block; + LIRInstr* next; + LIRInstr* prev; + + const LIROpcodeInfo* opcode; + uint16_t flags; + + 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; + } Op; + + // TODO(benvanik): make this variable width? + Op arg[4]; }; diff --git a/src/alloy/backend/x64/lir/lir_label.h b/src/alloy/backend/x64/lir/lir_label.h new file mode 100644 index 000000000..c35e19d7d --- /dev/null +++ b/src/alloy/backend/x64/lir/lir_label.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * 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_LIR_LIR_LABEL_H_ +#define ALLOY_BACKEND_X64_LIR_LIR_LABEL_H_ + +#include + + +namespace alloy { +namespace backend { +namespace x64 { +namespace lir { + +class LIRBlock; + + +class LIRLabel { +public: + LIRBlock* block; + LIRLabel* next; + LIRLabel* prev; + + uint32_t id; + char* name; + + void* tag; +}; + + +} // namespace lir +} // namespace x64 +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_X64_LIR_LIR_LABEL_H_ diff --git a/src/alloy/backend/x64/lir/sources.gypi b/src/alloy/backend/x64/lir/sources.gypi index d6b2f21e8..7384e318d 100644 --- a/src/alloy/backend/x64/lir/sources.gypi +++ b/src/alloy/backend/x64/lir/sources.gypi @@ -1,9 +1,11 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ + 'lir_block.h', 'lir_builder.cc', 'lir_builder.h', 'lir_instr.h', + 'lir_label.h', 'lir_opcodes.cc', 'lir_opcodes.h', 'lir_opcodes.inl', diff --git a/src/alloy/backend/x64/lowering/lowering_sequences.cc b/src/alloy/backend/x64/lowering/lowering_sequences.cc index 049c7dfd7..7d55a4f6c 100644 --- a/src/alloy/backend/x64/lowering/lowering_sequences.cc +++ b/src/alloy/backend/x64/lowering/lowering_sequences.cc @@ -395,46 +395,6 @@ public: #include } -enum { - REG8, REG16, REG32, REG64, REGXMM, - - 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, -}; - void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { Translateopcode->num]; - while (fn) { - if ((*fn)(builder, instr)) { - return true; +int LoweringTable::Process( + hir::HIRBuilder* hir_builder, lir::LIRBuilder* lir_builder) { + lir_builder->EndBlock(); + + // Translate all labels ahead of time. + // We stash them on tags to make things easier later on. + auto hir_block = hir_builder->first_block(); + while (hir_block) { + auto hir_label = hir_block->label_head; + while (hir_label) { + // TODO(benvanik): copy name to LIR label. + hir_label->tag = lir_builder->NewLabel(); + hir_label = hir_label->next; } - fn = fn->next; - }*/ + hir_block = hir_block->next; + } + + // Process each block. + hir_block = hir_builder->first_block(); + while (hir_block) { + // Force a new block. + lir_builder->AppendBlock(); + + // Mark labels. + auto hir_label = hir_block->label_head; + while (hir_label) { + auto lir_label = (lir::LIRLabel*)hir_label->tag; + lir_builder->MarkLabel(lir_label); + hir_label = hir_label->next; + } + + // Process instructions. + auto hir_instr = hir_block->instr_head; + while (hir_instr) { + bool processed = false; + auto fn = lookup_[hir_instr->opcode->num]; + while (fn) { + if ((*fn)(lir_builder, hir_instr)) { + processed = true; + break; + } + fn = fn->next; + } + if (!processed) { + // No sequence found! + XELOGE("Unable to process HIR opcode %s", hir_instr->opcode->name); + return 1; + hir_instr = hir_instr->next; + } + } + + lir_builder->EndBlock(); + hir_block = hir_block->next; + } + return 0; } \ No newline at end of file diff --git a/src/alloy/backend/x64/lowering/lowering_table.h b/src/alloy/backend/x64/lowering/lowering_table.h index 5b417ac88..821beed1a 100644 --- a/src/alloy/backend/x64/lowering/lowering_table.h +++ b/src/alloy/backend/x64/lowering/lowering_table.h @@ -11,15 +11,15 @@ #define ALLOY_BACKEND_X64_X64_LOWERING_LOWERING_TABLE_H_ #include +#include #include -#include +#include namespace alloy { namespace backend { namespace x64 { class X64Backend; -namespace lir { class LIRBuilder; } namespace lowering { @@ -30,7 +30,7 @@ public: int Initialize(); - int Process(lir::LIRBuilder* builder); + int Process(hir::HIRBuilder* hir_builder, lir::LIRBuilder* lir_builder); public: class FnWrapper { diff --git a/src/alloy/backend/x64/x64_assembler.cc b/src/alloy/backend/x64/x64_assembler.cc index 118a50e37..6ebdd1abd 100644 --- a/src/alloy/backend/x64/x64_assembler.cc +++ b/src/alloy/backend/x64/x64_assembler.cc @@ -75,7 +75,7 @@ int X64Assembler::Assemble( // Lower HIR -> LIR. auto lowering_table = x64_backend_->lowering_table(); - result = lowering_table->Process(builder_); + result = lowering_table->Process(hir_builder, builder_); XEEXPECTZERO(result); // Stash raw LIR. @@ -98,6 +98,15 @@ int X64Assembler::Assemble( // Emit machine code. // TODO(benvanik): machine code. + //result = emitter_->Emit(builder_, &machine_code, &length); + XEEXPECTZERO(result); + + // Stash generated machine code. + if (debug_info) { + //emitter_->Dump(&string_buffer_); + debug_info->set_machine_code_disasm(string_buffer_.ToString()); + string_buffer_.Reset(); + } X64Function* fn = new X64Function(symbol_info); fn->set_debug_info(debug_info); diff --git a/src/alloy/frontend/ppc/ppc_translator.cc b/src/alloy/frontend/ppc/ppc_translator.cc index 2a635290b..5f4810049 100644 --- a/src/alloy/frontend/ppc/ppc_translator.cc +++ b/src/alloy/frontend/ppc/ppc_translator.cc @@ -46,6 +46,7 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : Backend* backend = frontend->runtime()->backend(); assembler_ = backend->CreateAssembler(); + assembler_->Initialize(); } PPCTranslator::~PPCTranslator() {