HIR->LIR flow.

This commit is contained in:
Ben Vanik 2013-12-29 23:51:51 -08:00
parent cd9172ed62
commit 08cff81f6a
11 changed files with 394 additions and 52 deletions

View File

@ -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 <alloy/core.h>
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_

View File

@ -16,12 +16,20 @@ using namespace alloy::backend::x64::lir;
LIRBuilder::LIRBuilder(X64Backend* backend) : LIRBuilder::LIRBuilder(X64Backend* backend) :
backend_(backend) { backend_(backend) {
arena_ = new Arena();
Reset();
} }
LIRBuilder::~LIRBuilder() { LIRBuilder::~LIRBuilder() {
Reset();
delete arena_;
} }
void LIRBuilder::Reset() { void LIRBuilder::Reset() {
next_label_id_ = 0;
block_head_ = block_tail_ = NULL;
current_block_ = NULL;
arena_->Reset();
} }
int LIRBuilder::Finalize() { int LIRBuilder::Finalize() {
@ -29,4 +37,140 @@ int LIRBuilder::Finalize() {
} }
void LIRBuilder::Dump(StringBuffer* str) { void LIRBuilder::Dump(StringBuffer* str) {
uint32_t block_ordinal = 0;
auto block = block_head_;
while (block) {
if (block == block_head_) {
str->Append("<entry>:\n");
} else if (!block->label_head) {
str->Append("<block%d>:\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<LIRLabel>();
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<LIRBlock>();
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<LIRInstr>();
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;
} }

View File

@ -11,6 +11,9 @@
#define ALLOY_BACKEND_X64_LIR_LIR_BUILDER_H_ #define ALLOY_BACKEND_X64_LIR_LIR_BUILDER_H_
#include <alloy/core.h> #include <alloy/core.h>
#include <alloy/backend/x64/lir/lir_block.h>
#include <alloy/backend/x64/lir/lir_instr.h>
#include <alloy/backend/x64/lir/lir_label.h>
#include <alloy/backend/x64/lir/lir_opcodes.h> #include <alloy/backend/x64/lir/lir_opcodes.h>
@ -33,9 +36,28 @@ public:
Arena* arena() const { return arena_; } 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: protected:
X64Backend* backend_; X64Backend* backend_;
Arena* arena_; Arena* arena_;
uint32_t next_label_id_;
LIRBlock* block_head_;
LIRBlock* block_tail_;
LIRBlock* current_block_;
}; };

View File

@ -11,17 +11,85 @@
#define ALLOY_BACKEND_X64_LIR_LIR_INSTR_H_ #define ALLOY_BACKEND_X64_LIR_LIR_INSTR_H_
#include <alloy/core.h> #include <alloy/core.h>
#include <alloy/backend/x64/lir/lir_block.h>
#include <alloy/backend/x64/lir/lir_label.h>
#include <alloy/backend/x64/lir/lir_opcodes.h> #include <alloy/backend/x64/lir/lir_opcodes.h>
namespace alloy { namespace runtime { class FunctionInfo; } }
namespace alloy { namespace alloy {
namespace backend { namespace backend {
namespace x64 { namespace x64 {
namespace lir { 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 { class LIRInstr {
public: 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];
}; };

View File

@ -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 <alloy/core.h>
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_

View File

@ -1,9 +1,11 @@
# Copyright 2013 Ben Vanik. All Rights Reserved. # Copyright 2013 Ben Vanik. All Rights Reserved.
{ {
'sources': [ 'sources': [
'lir_block.h',
'lir_builder.cc', 'lir_builder.cc',
'lir_builder.h', 'lir_builder.h',
'lir_instr.h', 'lir_instr.h',
'lir_label.h',
'lir_opcodes.cc', 'lir_opcodes.cc',
'lir_opcodes.h', 'lir_opcodes.h',
'lir_opcodes.inl', 'lir_opcodes.inl',

View File

@ -395,46 +395,6 @@ public:
#include <alloy/backend/x64/lowering/lowering_lir_opcodes.inl> #include <alloy/backend/x64/lowering/lowering_lir_opcodes.inl>
} }
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) { void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
Translate<tuple< Translate<tuple<

View File

@ -43,14 +43,60 @@ void LoweringTable::AddSequence(hir::Opcode starting_opcode, FnWrapper* fn) {
lookup_[starting_opcode] = fn; lookup_[starting_opcode] = fn;
} }
int LoweringTable::Process(lir::LIRBuilder* builder) { int LoweringTable::Process(
/*LIRInstr* instr = 0; hir::HIRBuilder* hir_builder, lir::LIRBuilder* lir_builder) {
auto fn = lookup_[instr->opcode->num]; lir_builder->EndBlock();
while (fn) {
if ((*fn)(builder, instr)) { // Translate all labels ahead of time.
return true; // 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; return 0;
} }

View File

@ -11,15 +11,15 @@
#define ALLOY_BACKEND_X64_X64_LOWERING_LOWERING_TABLE_H_ #define ALLOY_BACKEND_X64_X64_LOWERING_LOWERING_TABLE_H_
#include <alloy/core.h> #include <alloy/core.h>
#include <alloy/backend/x64/lir/lir_builder.h>
#include <alloy/backend/x64/lir/lir_instr.h> #include <alloy/backend/x64/lir/lir_instr.h>
#include <alloy/hir/instr.h> #include <alloy/hir/hir_builder.h>
namespace alloy { namespace alloy {
namespace backend { namespace backend {
namespace x64 { namespace x64 {
class X64Backend; class X64Backend;
namespace lir { class LIRBuilder; }
namespace lowering { namespace lowering {
@ -30,7 +30,7 @@ public:
int Initialize(); int Initialize();
int Process(lir::LIRBuilder* builder); int Process(hir::HIRBuilder* hir_builder, lir::LIRBuilder* lir_builder);
public: public:
class FnWrapper { class FnWrapper {

View File

@ -75,7 +75,7 @@ int X64Assembler::Assemble(
// Lower HIR -> LIR. // Lower HIR -> LIR.
auto lowering_table = x64_backend_->lowering_table(); auto lowering_table = x64_backend_->lowering_table();
result = lowering_table->Process(builder_); result = lowering_table->Process(hir_builder, builder_);
XEEXPECTZERO(result); XEEXPECTZERO(result);
// Stash raw LIR. // Stash raw LIR.
@ -98,6 +98,15 @@ int X64Assembler::Assemble(
// Emit machine code. // Emit machine code.
// TODO(benvanik): 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); X64Function* fn = new X64Function(symbol_info);
fn->set_debug_info(debug_info); fn->set_debug_info(debug_info);

View File

@ -46,6 +46,7 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) :
Backend* backend = frontend->runtime()->backend(); Backend* backend = frontend->runtime()->backend();
assembler_ = backend->CreateAssembler(); assembler_ = backend->CreateAssembler();
assembler_->Initialize();
} }
PPCTranslator::~PPCTranslator() { PPCTranslator::~PPCTranslator() {