Deleting LIR and such, wiring up for HIR->x64.
This commit is contained in:
parent
55052b0d92
commit
8ae6053d0f
|
@ -1,47 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_
|
|
@ -1,378 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_builder.h>
|
||||
|
||||
#include <alloy/runtime/symbol_info.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend::x64;
|
||||
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() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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->local) {
|
||||
if (label->name) {
|
||||
str->Append(".%s:\n", label->name);
|
||||
} else {
|
||||
str->Append(".label%d:\n", label->id);
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
if (i->opcode == &LIR_OPCODE_COMMENT_info) {
|
||||
str->Append(" ; %s\n", i->arg0<const char>());
|
||||
i = i->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
const LIROpcodeInfo* info = i->opcode;
|
||||
str->Append(" ");
|
||||
if (i->flags) {
|
||||
str->Append("%s.%d", info->name, i->flags);
|
||||
} else {
|
||||
str->Append("%s", info->name);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
block = block->next;
|
||||
}
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
|
||||
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(const char* name, bool local) {
|
||||
LIRLabel* label = arena_->Alloc<LIRLabel>();
|
||||
label->next = label->prev = NULL;
|
||||
label->block = NULL;
|
||||
label->id = next_label_id_++;
|
||||
label->local = local;
|
||||
label->tag = NULL;
|
||||
if (!name) {
|
||||
char label_name[32] = "l";
|
||||
_itoa(label->id, label_name + 1, 10);
|
||||
name = label_name;
|
||||
}
|
||||
size_t label_length = xestrlena(name);
|
||||
label->name = (char*)arena_->Alloc(label_length + 1);
|
||||
xe_copy_struct(label->name, name, label_length + 1);
|
||||
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;
|
||||
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);
|
||||
auto instr = AppendInstr(LIR_OPCODE_COMMENT_info);
|
||||
instr->arg_offsets.arg0 =
|
||||
AppendOperand(instr, instr->arg_types.arg0, buffer);
|
||||
}
|
|
@ -1,189 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_BUILDER_H_
|
||||
#define ALLOY_BACKEND_X64_LIR_LIR_BUILDER_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/hir/value.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
class X64Backend;
|
||||
namespace lir {
|
||||
|
||||
|
||||
class LIRBuilder {
|
||||
public:
|
||||
LIRBuilder(X64Backend* backend);
|
||||
~LIRBuilder();
|
||||
|
||||
void Reset();
|
||||
int Finalize();
|
||||
|
||||
void Dump(StringBuffer* str);
|
||||
|
||||
Arena* arena() const { return arena_; }
|
||||
|
||||
LIRBlock* first_block() const { return block_head_; }
|
||||
LIRBlock* current_block() const;
|
||||
LIRInstr* last_instr() const;
|
||||
|
||||
LIRLabel* NewLabel(const char* name = 0, bool local = false);
|
||||
LIRLabel* NewLocalLabel() { return NewLabel(0, true); }
|
||||
void MarkLabel(LIRLabel* label, LIRBlock* block = 0);
|
||||
|
||||
// TODO(benvanik): allocations
|
||||
|
||||
LIRBlock* AppendBlock();
|
||||
void EndBlock();
|
||||
|
||||
void Nop() { AppendInstr(LIR_OPCODE_NOP_info, 0); }
|
||||
|
||||
void Comment(const char* format, ...);
|
||||
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); }
|
||||
|
||||
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); }
|
||||
|
||||
template<typename A0, typename A1>
|
||||
void Test(A0& a, A1& b) { AppendInstr(LIR_OPCODE_TEST_info, 0, a, b); }
|
||||
|
||||
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_;
|
||||
|
||||
uint32_t next_label_id_;
|
||||
|
||||
LIRBlock* block_head_;
|
||||
LIRBlock* block_tail_;
|
||||
LIRBlock* current_block_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lir
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_LIR_LIR_BUILDER_H_
|
|
@ -1,76 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_INSTR_H_
|
||||
#define ALLOY_BACKEND_X64_LIR_LIR_INSTR_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>
|
||||
|
||||
|
||||
namespace alloy { namespace runtime { class FunctionInfo; } }
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
namespace lir {
|
||||
|
||||
|
||||
enum class LIRRegisterName : uint32_t {
|
||||
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,
|
||||
|
||||
VREG0 = 0x10000000,
|
||||
};
|
||||
extern const char* register_names[74];
|
||||
|
||||
enum class LIRRegisterType : uint32_t {
|
||||
REG8,
|
||||
REG16,
|
||||
REG32,
|
||||
REG64,
|
||||
REGXMM,
|
||||
};
|
||||
|
||||
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:
|
||||
LIRBlock* block;
|
||||
LIRInstr* next;
|
||||
LIRInstr* prev;
|
||||
|
||||
const LIROpcodeInfo* opcode;
|
||||
uint16_t flags;
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
|
||||
} // namespace lir
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_LIR_LIR_INSTR_H_
|
|
@ -1,44 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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;
|
||||
bool local;
|
||||
|
||||
void* tag;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lir
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_LIR_LIR_LABEL_H_
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_opcodes.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend::x64::lir;
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
namespace lir {
|
||||
|
||||
#define DEFINE_OPCODE(num, string_name, flags) \
|
||||
static const LIROpcodeInfo num##_info = { flags, string_name, num, };
|
||||
#include <alloy/backend/x64/lir/lir_opcodes.inl>
|
||||
#undef DEFINE_OPCODE
|
||||
|
||||
const LIROpcodeInfo& GetOpcodeInfo(LIROpcode opcode) {
|
||||
static const LIROpcodeInfo* lookup[__LIR_OPCODE_MAX_VALUE] = {
|
||||
#define DEFINE_OPCODE(num, string_name, flags) \
|
||||
&num##_info,
|
||||
#include <alloy/backend/x64/lir/lir_opcodes.inl>
|
||||
#undef DEFINE_OPCODE
|
||||
};
|
||||
return *lookup[opcode];
|
||||
}
|
||||
|
||||
} // namespace lir
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
|
@ -1,73 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_OPCODES_H_
|
||||
#define ALLOY_BACKEND_X64_LIR_LIR_OPCODES_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
namespace lir {
|
||||
|
||||
|
||||
enum LIROpcode {
|
||||
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,
|
||||
|
||||
__LIR_OPCODE_MAX_VALUE, // Keep at end.
|
||||
};
|
||||
|
||||
enum LIROpcodeFlags {
|
||||
LIR_OPCODE_FLAG_BRANCH = (1 << 1),
|
||||
LIR_OPCODE_FLAG_MEMORY = (1 << 2),
|
||||
LIR_OPCODE_FLAG_COMMUNATIVE = (1 << 3),
|
||||
LIR_OPCODE_FLAG_VOLATILE = (1 << 4),
|
||||
LIR_OPCODE_FLAG_IGNORE = (1 << 5),
|
||||
LIR_OPCODE_FLAG_HIDE = (1 << 6),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t flags;
|
||||
const char* name;
|
||||
LIROpcode num;
|
||||
} LIROpcodeInfo;
|
||||
|
||||
|
||||
#define DEFINE_OPCODE(num, string_name, flags) \
|
||||
extern const LIROpcodeInfo num##_info;
|
||||
#include <alloy/backend/x64/lir/lir_opcodes.inl>
|
||||
#undef DEFINE_OPCODE
|
||||
|
||||
extern const LIROpcodeInfo& GetOpcodeInfo(LIROpcode opcode);
|
||||
|
||||
|
||||
} // namespace lir
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_LIR_LIR_OPCODES_H_
|
|
@ -1,61 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
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",
|
||||
0)
|
||||
|
||||
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",
|
||||
0)
|
|
@ -1,15 +0,0 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'lir_block.h',
|
||||
'lir_builder.cc',
|
||||
'lir_builder.h',
|
||||
'lir_instr.cc',
|
||||
'lir_instr.h',
|
||||
'lir_label.h',
|
||||
'lir_opcodes.cc',
|
||||
'lir_opcodes.h',
|
||||
'lir_opcodes.inl',
|
||||
'tracing.h',
|
||||
],
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_TRACING_H_
|
||||
#define ALLOY_BACKEND_X64_LIR_TRACING_H_
|
||||
|
||||
#include <alloy/backend/x64/tracing.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
namespace lir {
|
||||
|
||||
const uint32_t ALLOY_BACKEND_X64_LIR =
|
||||
alloy::backend::x64::EventType::ALLOY_BACKEND_X64_LIR;
|
||||
|
||||
|
||||
class EventType {
|
||||
public:
|
||||
enum {
|
||||
ALLOY_BACKEND_X64_LIR_FOO = ALLOY_BACKEND_X64_LIR | (1),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
} // namespace lir
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_LIR_TRACING_H_
|
|
@ -9,28 +9,42 @@
|
|||
|
||||
#include <alloy/backend/x64/lowering/lowering_sequences.h>
|
||||
|
||||
#include <alloy/backend/x64/x64_emitter.h>
|
||||
#include <alloy/backend/x64/lowering/lowering_table.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend::x64;
|
||||
using namespace alloy::backend::x64::lir;
|
||||
using namespace alloy::backend::x64::lowering;
|
||||
using namespace alloy::hir;
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
#define UNIMPLEMENTED_SEQ()
|
||||
|
||||
// TODO(benvanik): emit traces/printfs/etc
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
||||
// --------------------------------------------------------------------------
|
||||
// General
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_COMMENT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
char* str = (char*)instr->src1.offset;
|
||||
lb.Comment(str);
|
||||
table->AddSequence(OPCODE_COMMENT, [](X64Emitter& e, Instr*& instr) {
|
||||
//char* str = (char*)instr->src1.offset;
|
||||
//lb.Comment(str);
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_NOP, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.Nop();
|
||||
table->AddSequence(OPCODE_NOP, [](X64Emitter& e, Instr*& instr) {
|
||||
// If we got this, chances are we want it.
|
||||
e.nop();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -39,42 +53,53 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// Debugging
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_SOURCE_OFFSET, [](LIRBuilder& lb, Instr*& instr) {
|
||||
table->AddSequence(OPCODE_SOURCE_OFFSET, [](X64Emitter& e, Instr*& instr) {
|
||||
// TODO(benvanik): translate source offsets for mapping? We're just passing
|
||||
// down the original offset - it may be nice to have two.
|
||||
lb.SourceOffset(instr->src1.offset);
|
||||
//lb.SourceOffset(instr->src1.offset);
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_DEBUG_BREAK, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.DebugBreak();
|
||||
table->AddSequence(OPCODE_DEBUG_BREAK, [](X64Emitter& e, Instr*& instr) {
|
||||
// TODO(benvanik): insert a call to the debug break function to let the
|
||||
// debugger know.
|
||||
e.db(0xCC);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_DEBUG_BREAK_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
auto skip_label = lb.NewLocalLabel();
|
||||
lb.Test(instr->src1.value, instr->src1.value);
|
||||
lb.JumpNE(skip_label);
|
||||
lb.DebugBreak();
|
||||
lb.MarkLabel(skip_label);
|
||||
table->AddSequence(OPCODE_DEBUG_BREAK_TRUE, [](X64Emitter& e, Instr*& instr) {
|
||||
e.inLocalLabel();
|
||||
//e.test(e.rax, e.rax);
|
||||
e.jne(".x");
|
||||
// TODO(benvanik): insert a call to the debug break function to let the
|
||||
// debugger know.
|
||||
e.db(0xCC);
|
||||
e.L(".x");
|
||||
e.outLocalLabel();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_TRAP, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.Trap();
|
||||
table->AddSequence(OPCODE_TRAP, [](X64Emitter& e, Instr*& instr) {
|
||||
// TODO(benvanik): insert a call to the trap function to let the
|
||||
// debugger know.
|
||||
e.db(0xCC);
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_TRAP_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
auto skip_label = lb.NewLocalLabel();
|
||||
lb.Test(instr->src1.value, instr->src1.value);
|
||||
lb.JumpNE(skip_label);
|
||||
lb.Trap();
|
||||
lb.MarkLabel(skip_label);
|
||||
table->AddSequence(OPCODE_TRAP_TRUE, [](X64Emitter& e, Instr*& instr) {
|
||||
e.inLocalLabel();
|
||||
//e.test(rax, rax);
|
||||
e.jne(".x");
|
||||
// TODO(benvanik): insert a call to the trap function to let the
|
||||
// debugger know.
|
||||
e.db(0xCC);
|
||||
e.L(".x");
|
||||
e.outLocalLabel();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -83,46 +108,48 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// Calls
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_CALL, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_CALL, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
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);
|
||||
table->AddSequence(OPCODE_CALL_TRUE, [](X64Emitter& e, Instr*& instr) {
|
||||
//auto skip_label = lb.NewLocalLabel();
|
||||
//lb.Test(instr->src1.value, instr->src1.value);
|
||||
//lb.JumpNE(skip_label);
|
||||
//// TODO
|
||||
//lb.MarkLabel(skip_label);
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_CALL_INDIRECT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_CALL_INDIRECT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
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);
|
||||
table->AddSequence(OPCODE_CALL_INDIRECT_TRUE, [](X64Emitter& e, Instr*& instr) {
|
||||
//auto skip_label = lb.NewLocalLabel();
|
||||
//lb.Test(instr->src1.value, instr->src1.value);
|
||||
//lb.JumpNE(skip_label);
|
||||
//UNIMPLEMENTED_SEQ();
|
||||
//lb.MarkLabel(skip_label);
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_RETURN, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_RETURN, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SET_RETURN_ADDRESS, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_SET_RETURN_ADDRESS, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -131,25 +158,28 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// Branches
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_BRANCH, [](LIRBuilder& lb, Instr*& instr) {
|
||||
auto target = (LIRLabel*)instr->src1.label->tag;
|
||||
lb.Jump(target);
|
||||
table->AddSequence(OPCODE_BRANCH, [](X64Emitter& e, Instr*& instr) {
|
||||
/*auto target = (LIRLabel*)instr->src1.label->tag;
|
||||
lb.Jump(target);*/
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_BRANCH_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.Test(instr->src1.value, instr->src1.value);
|
||||
table->AddSequence(OPCODE_BRANCH_TRUE, [](X64Emitter& e, Instr*& instr) {
|
||||
/*lb.Test(instr->src1.value, instr->src1.value);
|
||||
auto target = (LIRLabel*)instr->src2.label->tag;
|
||||
lb.JumpEQ(target);
|
||||
lb.JumpEQ(target);*/
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_BRANCH_FALSE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.Test(instr->src1.value, instr->src1.value);
|
||||
table->AddSequence(OPCODE_BRANCH_FALSE, [](X64Emitter& e, Instr*& instr) {
|
||||
/*lb.Test(instr->src1.value, instr->src1.value);
|
||||
auto target = (LIRLabel*)instr->src2.label->tag;
|
||||
lb.JumpNE(target);
|
||||
lb.JumpNE(target);*/
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -158,56 +188,61 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// Types
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_ASSIGN, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.Mov(instr->dest, instr->src1.value);
|
||||
table->AddSequence(OPCODE_ASSIGN, [](X64Emitter& e, Instr*& instr) {
|
||||
//lb.Mov(instr->dest, instr->src1.value);
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_CAST, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.Mov(instr->dest, instr->src1.value);
|
||||
table->AddSequence(OPCODE_CAST, [](X64Emitter& e, Instr*& instr) {
|
||||
//lb.Mov(instr->dest, instr->src1.value);
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_ZERO_EXTEND, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.MovZX(instr->dest, instr->src1.value);
|
||||
table->AddSequence(OPCODE_ZERO_EXTEND, [](X64Emitter& e, Instr*& instr) {
|
||||
//lb.MovZX(instr->dest, instr->src1.value);
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SIGN_EXTEND, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.MovSX(instr->dest, instr->src1.value);
|
||||
table->AddSequence(OPCODE_SIGN_EXTEND, [](X64Emitter& e, Instr*& instr) {
|
||||
//lb.MovSX(instr->dest, instr->src1.value);
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_TRUNCATE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.Mov(instr->dest, instr->src1.value);
|
||||
table->AddSequence(OPCODE_TRUNCATE, [](X64Emitter& e, Instr*& instr) {
|
||||
//lb.Mov(instr->dest, instr->src1.value);
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_CONVERT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_CONVERT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_ROUND, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_ROUND, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_CONVERT_I2F, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_VECTOR_CONVERT_I2F, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_CONVERT_F2I, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_VECTOR_CONVERT_F2I, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -218,20 +253,20 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
|
||||
// specials for zeroing/etc (xor/etc)
|
||||
|
||||
table->AddSequence(OPCODE_LOAD_VECTOR_SHL, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_LOAD_VECTOR_SHL, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_LOAD_VECTOR_SHR, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_LOAD_VECTOR_SHR, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_LOAD_CLOCK, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_LOAD_CLOCK, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -240,20 +275,22 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// Context
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_LOAD_CONTEXT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.Mov(
|
||||
table->AddSequence(OPCODE_LOAD_CONTEXT, [](X64Emitter& e, Instr*& instr) {
|
||||
/*lb.Mov(
|
||||
instr->dest,
|
||||
LIRRegister(LIRRegisterType::REG64, LIRRegisterName::RCX),
|
||||
instr->src1.offset);
|
||||
instr->src1.offset);*/
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_STORE_CONTEXT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
lb.Mov(
|
||||
table->AddSequence(OPCODE_STORE_CONTEXT, [](X64Emitter& e, Instr*& instr) {
|
||||
/*lb.Mov(
|
||||
LIRRegister(LIRRegisterType::REG64, LIRRegisterName::RCX),
|
||||
instr->src1.offset,
|
||||
instr->src2.value);
|
||||
instr->src2.value);*/
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -262,24 +299,26 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// Memory
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_LOAD, [](LIRBuilder& lb, Instr*& instr) {
|
||||
table->AddSequence(OPCODE_LOAD, [](X64Emitter& e, Instr*& instr) {
|
||||
// TODO(benvanik): dynamic register access check
|
||||
// mov reg, [membase + address.32]
|
||||
// TODO(benvanik): special for f32/f64/v128
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_STORE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
table->AddSequence(OPCODE_STORE, [](X64Emitter& e, Instr*& instr) {
|
||||
// TODO(benvanik): dynamic register access check
|
||||
// mov [membase + address.32], reg
|
||||
// TODO(benvanik): special for f32/f64/v128
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_PREFETCH, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_PREFETCH, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -288,134 +327,140 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// Comparisons
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_MAX, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_MAX, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_MIN, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_MIN, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SELECT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_SELECT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_IS_TRUE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_IS_TRUE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_IS_FALSE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_IS_FALSE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_EQ, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_EQ, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_NE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_NE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_SLT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_SLT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_SLE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_SLE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_SGT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_SGT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_SGE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_SGE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_ULT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_ULT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_ULE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_ULE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_UGT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_UGT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_UGE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_UGE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_DID_CARRY, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_DID_CARRY, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_DID_OVERFLOW, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_DID_OVERFLOW, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_EQ, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_DID_SATURATE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_SGT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_EQ, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_SGE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_SGT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_UGT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_SGE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_UGE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_UGT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_COMPARE_UGE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -424,200 +469,218 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// Math
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_ADD, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_ADD, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_ADD_CARRY, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_ADD_CARRY, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SUB, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_SUB, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_MUL, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_MUL, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_DIV, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_MUL_HI, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_MUL_ADD, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_DIV, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_MUL_SUB, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_MUL_ADD, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_NEG, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_MUL_SUB, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_ABS, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_NEG, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SQRT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_ABS, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_RSQRT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_SQRT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_POW2, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_RSQRT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_LOG2, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_POW2, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_DOT_PRODUCT_3, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_LOG2, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_DOT_PRODUCT_4, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_DOT_PRODUCT_3, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_AND, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_DOT_PRODUCT_4, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_OR, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_AND, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_XOR, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_OR, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_NOT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_XOR, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SHL, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_NOT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_SHL, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_SHL, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SHR, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_VECTOR_SHL, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_SHR, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_SHR, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SHA, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_VECTOR_SHR, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_VECTOR_SHA, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_SHA, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_ROTATE_LEFT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_VECTOR_SHA, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_BYTE_SWAP, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_ROTATE_LEFT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_CNTLZ, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_BYTE_SWAP, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_INSERT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_CNTLZ, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_EXTRACT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_INSERT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SPLAT, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_EXTRACT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_PERMUTE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_SPLAT, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SWIZZLE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_PERMUTE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_SWIZZLE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_PACK, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_UNPACK, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
@ -626,26 +689,26 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) {
|
|||
// Atomic
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
table->AddSequence(OPCODE_COMPARE_EXCHANGE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_COMPARE_EXCHANGE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_ATOMIC_EXCHANGE, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_ATOMIC_EXCHANGE, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_ATOMIC_ADD, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_ATOMIC_ADD, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
||||
table->AddSequence(OPCODE_ATOMIC_SUB, [](LIRBuilder& lb, Instr*& instr) {
|
||||
// TODO
|
||||
table->AddSequence(OPCODE_ATOMIC_SUB, [](X64Emitter& e, Instr*& instr) {
|
||||
UNIMPLEMENTED_SEQ();
|
||||
instr = instr->next;
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -45,59 +45,25 @@ void LoweringTable::AddSequence(hir::Opcode starting_opcode, sequence_fn_t fn) {
|
|||
lookup_[starting_opcode] = new_entry;
|
||||
}
|
||||
|
||||
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) {
|
||||
auto lir_label = lir_builder->NewLabel(hir_label->name);
|
||||
hir_label->tag = lir_label;
|
||||
hir_label = hir_label->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 entry = lookup_[hir_instr->opcode->num];
|
||||
while (entry) {
|
||||
if ((*entry->fn)(*lir_builder, hir_instr)) {
|
||||
processed = true;
|
||||
break;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
if (!processed) {
|
||||
// No sequence found!
|
||||
XELOGE("Unable to process HIR opcode %s", hir_instr->opcode->name);
|
||||
return 1;
|
||||
hir_instr = hir_instr->next;
|
||||
int LoweringTable::ProcessBlock(X64Emitter& e, hir::Block* block) {
|
||||
// Process instructions.
|
||||
auto instr = block->instr_head;
|
||||
while (instr) {
|
||||
bool processed = false;
|
||||
auto entry = lookup_[instr->opcode->num];
|
||||
while (entry) {
|
||||
if ((*entry->fn)(e, instr)) {
|
||||
processed = true;
|
||||
break;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
if (!processed) {
|
||||
// No sequence found!
|
||||
XELOGE("Unable to process HIR opcode %s", instr->opcode->name);
|
||||
return 1;
|
||||
instr = instr->next;
|
||||
}
|
||||
|
||||
lir_builder->EndBlock();
|
||||
hir_block = hir_block->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#define ALLOY_BACKEND_X64_X64_LOWERING_LOWERING_TABLE_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/backend/x64/lir/lir_builder.h>
|
||||
#include <alloy/backend/x64/lir/lir_instr.h>
|
||||
#include <alloy/hir/hir_builder.h>
|
||||
|
||||
|
||||
|
@ -20,6 +18,7 @@ namespace alloy {
|
|||
namespace backend {
|
||||
namespace x64 {
|
||||
class X64Backend;
|
||||
class X64Emitter;
|
||||
namespace lowering {
|
||||
|
||||
|
||||
|
@ -30,10 +29,10 @@ public:
|
|||
|
||||
int Initialize();
|
||||
|
||||
int Process(hir::HIRBuilder* hir_builder, lir::LIRBuilder* lir_builder);
|
||||
int ProcessBlock(X64Emitter& e, hir::Block* block);
|
||||
|
||||
public:
|
||||
typedef bool(*sequence_fn_t)(lir::LIRBuilder& lb, hir::Instr*& instr);
|
||||
typedef bool(*sequence_fn_t)(X64Emitter& e, hir::Instr*& instr);
|
||||
void AddSequence(hir::Opcode starting_opcode, sequence_fn_t fn);
|
||||
|
||||
private:
|
||||
|
@ -43,6 +42,8 @@ private:
|
|||
sequence_fn_entry_t* next;
|
||||
};
|
||||
|
||||
// NOTE: this class is shared by multiple threads and is not thread safe.
|
||||
// Do not modify anything after init.
|
||||
X64Backend* backend_;
|
||||
sequence_fn_entry_t* lookup_[hir::__OPCODE_MAX_VALUE];
|
||||
};
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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/optimizer.h>
|
||||
|
||||
#include <alloy/backend/x64/tracing.h>
|
||||
#include <alloy/backend/x64/optimizer/optimizer_pass.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend::x64::lir;
|
||||
using namespace alloy::backend::x64::optimizer;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
Optimizer::Optimizer(Runtime* runtime) :
|
||||
runtime_(runtime) {
|
||||
alloy::tracing::WriteEvent(EventType::Init({
|
||||
}));
|
||||
}
|
||||
|
||||
Optimizer::~Optimizer() {
|
||||
Reset();
|
||||
|
||||
for (auto it = passes_.begin(); it != passes_.end(); ++it) {
|
||||
OptimizerPass* pass = *it;
|
||||
delete pass;
|
||||
}
|
||||
|
||||
alloy::tracing::WriteEvent(EventType::Deinit({
|
||||
}));
|
||||
}
|
||||
|
||||
void Optimizer::AddPass(OptimizerPass* pass) {
|
||||
pass->Initialize(this);
|
||||
passes_.push_back(pass);
|
||||
}
|
||||
|
||||
void Optimizer::Reset() {
|
||||
}
|
||||
|
||||
int Optimizer::Optimize(LIRBuilder* builder) {
|
||||
// TODO(benvanik): sophisticated stuff. Run passes in parallel, run until they
|
||||
// stop changing things, etc.
|
||||
for (auto it = passes_.begin(); it != passes_.end(); ++it) {
|
||||
OptimizerPass* pass = *it;
|
||||
if (pass->Run(builder)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_OPTIMIZER_H_
|
||||
#define ALLOY_BACKEND_X64_OPTIMIZER_OPTIMIZER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
#include <alloy/backend/x64/lir/lir_builder.h>
|
||||
|
||||
namespace alloy { namespace runtime { class Runtime; } }
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
namespace optimizer {
|
||||
|
||||
class OptimizerPass;
|
||||
|
||||
|
||||
class Optimizer {
|
||||
public:
|
||||
Optimizer(runtime::Runtime* runtime);
|
||||
~Optimizer();
|
||||
|
||||
runtime::Runtime* runtime() const { return runtime_; }
|
||||
|
||||
void AddPass(OptimizerPass* pass);
|
||||
|
||||
void Reset();
|
||||
|
||||
int Optimize(lir::LIRBuilder* builder);
|
||||
|
||||
private:
|
||||
runtime::Runtime* runtime_;
|
||||
|
||||
typedef std::vector<OptimizerPass*> PassList;
|
||||
PassList passes_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace optimizer
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_OPTIMIZER_OPTIMIZER_H_
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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/optimizer_pass.h>
|
||||
|
||||
#include <alloy/backend/x64/optimizer/optimizer.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend::x64::optimizer;
|
||||
|
||||
|
||||
OptimizerPass::OptimizerPass() :
|
||||
runtime_(0), optimizer_(0) {
|
||||
}
|
||||
|
||||
OptimizerPass::~OptimizerPass() {
|
||||
}
|
||||
|
||||
int OptimizerPass::Initialize(Optimizer* optimizer) {
|
||||
runtime_ = optimizer->runtime();
|
||||
optimizer_ = optimizer;
|
||||
return 0;
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_OPTIMIZER_PASS_H_
|
||||
#define ALLOY_BACKEND_X64_OPTIMIZER_OPTIMIZER_PASS_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <alloy/backend/x64/lir/lir_builder.h>
|
||||
|
||||
namespace alloy { namespace runtime { class Runtime; } }
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
namespace optimizer {
|
||||
|
||||
class Optimizer;
|
||||
|
||||
|
||||
class OptimizerPass {
|
||||
public:
|
||||
OptimizerPass();
|
||||
virtual ~OptimizerPass();
|
||||
|
||||
virtual int Initialize(Optimizer* optimizer);
|
||||
|
||||
virtual int Run(lir::LIRBuilder* builder) = 0;
|
||||
|
||||
protected:
|
||||
runtime::Runtime* runtime_;
|
||||
Optimizer* optimizer_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace optimizer
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_OPTIMIZER_OPTIMIZER_PASS_H_
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_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/register_allocation_pass.h>
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_OPTIMIZER_PASSES_H_
|
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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.
|
||||
|
||||
// Remove unneeded jumps.
|
||||
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;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_
|
|
@ -1,27 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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/redundant_mov_pass.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend::x64::lir;
|
||||
using namespace alloy::backend::x64::optimizer;
|
||||
using namespace alloy::backend::x64::optimizer::passes;
|
||||
|
||||
|
||||
RedundantMovPass::RedundantMovPass() :
|
||||
OptimizerPass() {
|
||||
}
|
||||
|
||||
RedundantMovPass::~RedundantMovPass() {
|
||||
}
|
||||
|
||||
int RedundantMovPass::Run(LIRBuilder* builder) {
|
||||
return 0;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_REDUNDANT_MOV_PASS_H_
|
||||
#define ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REDUNDANT_MOV_PASS_H_
|
||||
|
||||
#include <alloy/backend/x64/optimizer/optimizer_pass.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
namespace optimizer {
|
||||
namespace passes {
|
||||
|
||||
|
||||
class RedundantMovPass : public OptimizerPass {
|
||||
public:
|
||||
RedundantMovPass();
|
||||
virtual ~RedundantMovPass();
|
||||
|
||||
virtual int Run(lir::LIRBuilder* builder);
|
||||
};
|
||||
|
||||
|
||||
} // namespace passes
|
||||
} // namespace optimizer
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REDUNDANT_MOV_PASS_H_
|
|
@ -1,27 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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/register_allocation_pass.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend::x64::lir;
|
||||
using namespace alloy::backend::x64::optimizer;
|
||||
using namespace alloy::backend::x64::optimizer::passes;
|
||||
|
||||
|
||||
RegisterAllocationPass::RegisterAllocationPass() :
|
||||
OptimizerPass() {
|
||||
}
|
||||
|
||||
RegisterAllocationPass::~RegisterAllocationPass() {
|
||||
}
|
||||
|
||||
int RegisterAllocationPass::Run(LIRBuilder* builder) {
|
||||
return 0;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_REGISTER_ALLOCATION_PASS_H_
|
||||
#define ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REGISTER_ALLOCATION_PASS_H_
|
||||
|
||||
#include <alloy/backend/x64/optimizer/optimizer_pass.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
namespace optimizer {
|
||||
namespace passes {
|
||||
|
||||
|
||||
class RegisterAllocationPass : public OptimizerPass {
|
||||
public:
|
||||
RegisterAllocationPass();
|
||||
virtual ~RegisterAllocationPass();
|
||||
|
||||
virtual int Run(lir::LIRBuilder* builder);
|
||||
};
|
||||
|
||||
|
||||
} // namespace passes
|
||||
} // namespace optimizer
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_OPTIMIZER_PASSES_REGISTER_ALLOCATION_PASS_H_
|
|
@ -1,11 +0,0 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'reachability_pass.cc',
|
||||
'reachability_pass.h',
|
||||
'redundant_mov_pass.cc',
|
||||
'redundant_mov_pass.h',
|
||||
'register_allocation_pass.cc',
|
||||
'register_allocation_pass.h',
|
||||
],
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'optimizer.cc',
|
||||
'optimizer.h',
|
||||
'optimizer_pass.cc',
|
||||
'optimizer_pass.h',
|
||||
'optimizer_passes.h',
|
||||
'tracing.h',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
'passes/sources.gypi',
|
||||
],
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_TRACING_H_
|
||||
#define ALLOY_BACKEND_X64_OPTIMIZER_TRACING_H_
|
||||
|
||||
#include <alloy/backend/x64/tracing.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
namespace x64 {
|
||||
namespace optimizer {
|
||||
|
||||
const uint32_t ALLOY_BACKEND_X64_OPTIMIZER =
|
||||
alloy::backend::x64::EventType::ALLOY_BACKEND_X64_OPTIMIZER;
|
||||
|
||||
|
||||
class EventType {
|
||||
public:
|
||||
enum {
|
||||
ALLOY_BACKEND_X64_OPTIMIZER_INIT = ALLOY_BACKEND_X64_OPTIMIZER | (1),
|
||||
ALLOY_BACKEND_X64_OPTIMIZER_DEINIT = ALLOY_BACKEND_X64_OPTIMIZER | (2),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_BACKEND_X64_OPTIMIZER_INIT;
|
||||
} Init;
|
||||
typedef struct {
|
||||
static const uint32_t event_type = ALLOY_BACKEND_X64_OPTIMIZER_DEINIT;
|
||||
} Deinit;
|
||||
};
|
||||
|
||||
|
||||
} // namespace optimizer
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_BACKEND_X64_OPTIMIZER_TRACING_H_
|
|
@ -15,8 +15,6 @@
|
|||
],
|
||||
|
||||
'includes': [
|
||||
'lir/sources.gypi',
|
||||
'lowering/sources.gypi',
|
||||
'optimizer/sources.gypi',
|
||||
],
|
||||
}
|
||||
|
|
|
@ -30,9 +30,6 @@ public:
|
|||
ALLOY_BACKEND_X64_ASSEMBLER = ALLOY_BACKEND_X64 | (1 << 20),
|
||||
ALLOY_BACKEND_X64_ASSEMBLER_INIT = ALLOY_BACKEND_X64_ASSEMBLER | (1),
|
||||
ALLOY_BACKEND_X64_ASSEMBLER_DEINIT = ALLOY_BACKEND_X64_ASSEMBLER | (2),
|
||||
|
||||
ALLOY_BACKEND_X64_LIR = ALLOY_BACKEND_X64 | (2 << 20),
|
||||
ALLOY_BACKEND_X64_OPTIMIZER = ALLOY_BACKEND_X64 | (3 << 20),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -13,10 +13,6 @@
|
|||
#include <alloy/backend/x64/x64_backend.h>
|
||||
#include <alloy/backend/x64/x64_emitter.h>
|
||||
#include <alloy/backend/x64/x64_function.h>
|
||||
#include <alloy/backend/x64/lir/lir_builder.h>
|
||||
#include <alloy/backend/x64/lowering/lowering_table.h>
|
||||
#include <alloy/backend/x64/optimizer/optimizer.h>
|
||||
#include <alloy/backend/x64/optimizer/optimizer_passes.h>
|
||||
#include <alloy/hir/hir_builder.h>
|
||||
#include <alloy/hir/label.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
@ -28,16 +24,12 @@ namespace BE {
|
|||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::backend::x64;
|
||||
using namespace alloy::backend::x64::lir;
|
||||
using namespace alloy::backend::x64::optimizer;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
X64Assembler::X64Assembler(X64Backend* backend) :
|
||||
x64_backend_(backend),
|
||||
builder_(0),
|
||||
optimizer_(0),
|
||||
emitter_(0),
|
||||
Assembler(backend) {
|
||||
}
|
||||
|
@ -47,8 +39,6 @@ X64Assembler::~X64Assembler() {
|
|||
}));
|
||||
|
||||
delete emitter_;
|
||||
delete optimizer_;
|
||||
delete builder_;
|
||||
}
|
||||
|
||||
int X64Assembler::Initialize() {
|
||||
|
@ -57,14 +47,8 @@ int X64Assembler::Initialize() {
|
|||
return result;
|
||||
}
|
||||
|
||||
builder_ = new LIRBuilder(x64_backend_);
|
||||
|
||||
optimizer_ = new Optimizer(backend_->runtime());
|
||||
optimizer_->AddPass(new passes::RegisterAllocationPass());
|
||||
optimizer_->AddPass(new passes::RedundantMovPass());
|
||||
optimizer_->AddPass(new passes::ReachabilityPass());
|
||||
|
||||
emitter_ = new X64Emitter(x64_backend_);
|
||||
emitter_ = new X64Emitter(x64_backend_,
|
||||
new XbyakAllocator());
|
||||
|
||||
alloy::tracing::WriteEvent(EventType::AssemblerInit({
|
||||
}));
|
||||
|
@ -73,45 +57,20 @@ int X64Assembler::Initialize() {
|
|||
}
|
||||
|
||||
void X64Assembler::Reset() {
|
||||
builder_->Reset();
|
||||
optimizer_->Reset();
|
||||
string_buffer_.Reset();
|
||||
Assembler::Reset();
|
||||
}
|
||||
|
||||
int X64Assembler::Assemble(
|
||||
FunctionInfo* symbol_info, HIRBuilder* hir_builder,
|
||||
FunctionInfo* symbol_info, HIRBuilder* builder,
|
||||
uint32_t debug_info_flags, DebugInfo* debug_info,
|
||||
Function** out_function) {
|
||||
int result = 0;
|
||||
|
||||
// Lower HIR -> LIR.
|
||||
auto lowering_table = x64_backend_->lowering_table();
|
||||
result = lowering_table->Process(hir_builder, builder_);
|
||||
XEEXPECTZERO(result);
|
||||
|
||||
// Stash raw LIR.
|
||||
if (debug_info_flags & DEBUG_INFO_RAW_LIR_DISASM) {
|
||||
builder_->Dump(&string_buffer_);
|
||||
debug_info->set_raw_lir_disasm(string_buffer_.ToString());
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
// Optimize LIR.
|
||||
result = optimizer_->Optimize(builder_);
|
||||
XEEXPECTZERO(result);
|
||||
|
||||
// Stash optimized LIR.
|
||||
if (debug_info_flags & DEBUG_INFO_LIR_DISASM) {
|
||||
builder_->Dump(&string_buffer_);
|
||||
debug_info->set_lir_disasm(string_buffer_.ToString());
|
||||
string_buffer_.Reset();
|
||||
}
|
||||
|
||||
// Emit machine code.
|
||||
// Lower HIR -> x64.
|
||||
void* machine_code = 0;
|
||||
size_t code_size = 0;
|
||||
result = emitter_->Emit(builder_, machine_code, code_size);
|
||||
result = emitter_->Emit(builder, machine_code, code_size);
|
||||
XEEXPECTZERO(result);
|
||||
|
||||
// Stash generated machine code.
|
||||
|
|
|
@ -21,8 +21,6 @@ namespace x64 {
|
|||
|
||||
class X64Backend;
|
||||
class X64Emitter;
|
||||
namespace lir { class LIRBuilder; }
|
||||
namespace optimizer { class Optimizer; }
|
||||
|
||||
|
||||
class X64Assembler : public Assembler {
|
||||
|
@ -44,8 +42,6 @@ private:
|
|||
|
||||
private:
|
||||
X64Backend* x64_backend_;
|
||||
lir::LIRBuilder* builder_;
|
||||
optimizer::Optimizer* optimizer_;
|
||||
X64Emitter* emitter_;
|
||||
|
||||
StringBuffer string_buffer_;
|
||||
|
|
|
@ -11,14 +11,13 @@
|
|||
|
||||
#include <alloy/backend/x64/x64_backend.h>
|
||||
#include <alloy/backend/x64/x64_code_cache.h>
|
||||
#include <alloy/backend/x64/lir/lir_builder.h>
|
||||
|
||||
#include <third_party/xbyak/xbyak/xbyak.h>
|
||||
#include <alloy/backend/x64/lowering/lowering_table.h>
|
||||
#include <alloy/hir/hir_builder.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::backend::x64;
|
||||
using namespace alloy::backend::x64::lir;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
using namespace Xbyak;
|
||||
|
@ -28,35 +27,21 @@ namespace alloy {
|
|||
namespace backend {
|
||||
namespace x64 {
|
||||
|
||||
class XbyakAllocator : public Allocator {
|
||||
public:
|
||||
virtual bool useProtect() const { return false; }
|
||||
};
|
||||
|
||||
class XbyakGenerator : public CodeGenerator {
|
||||
public:
|
||||
XbyakGenerator(XbyakAllocator* allocator);
|
||||
virtual ~XbyakGenerator();
|
||||
void* Emplace(X64CodeCache* code_cache);
|
||||
int Emit(LIRBuilder* builder);
|
||||
private:
|
||||
int EmitInstruction(LIRInstr* instr);
|
||||
};
|
||||
static const size_t MAX_CODE_SIZE = 1 * 1024 * 1024;
|
||||
|
||||
} // namespace x64
|
||||
} // namespace backend
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
X64Emitter::X64Emitter(X64Backend* backend) :
|
||||
X64Emitter::X64Emitter(X64Backend* backend, XbyakAllocator* allocator) :
|
||||
backend_(backend),
|
||||
code_cache_(backend->code_cache()) {
|
||||
allocator_ = new XbyakAllocator();
|
||||
generator_ = new XbyakGenerator(allocator_);
|
||||
code_cache_(backend->code_cache()),
|
||||
allocator_(allocator),
|
||||
CodeGenerator(MAX_CODE_SIZE, AutoGrow, allocator) {
|
||||
}
|
||||
|
||||
X64Emitter::~X64Emitter() {
|
||||
delete generator_;
|
||||
delete allocator_;
|
||||
}
|
||||
|
||||
|
@ -65,28 +50,21 @@ int X64Emitter::Initialize() {
|
|||
}
|
||||
|
||||
int X64Emitter::Emit(
|
||||
LIRBuilder* builder, void*& out_code_address, size_t& out_code_size) {
|
||||
HIRBuilder* builder, void*& out_code_address, size_t& out_code_size) {
|
||||
// Fill the generator with code.
|
||||
int result = generator_->Emit(builder);
|
||||
int result = Emit(builder);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Copy the final code to the cache and relocate it.
|
||||
out_code_size = generator_->getSize();
|
||||
out_code_address = generator_->Emplace(code_cache_);
|
||||
out_code_size = getSize();
|
||||
out_code_address = Emplace(code_cache_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XbyakGenerator::XbyakGenerator(XbyakAllocator* allocator) :
|
||||
CodeGenerator(1 * 1024 * 1024, AutoGrow, allocator) {
|
||||
}
|
||||
|
||||
XbyakGenerator::~XbyakGenerator() {
|
||||
}
|
||||
|
||||
void* XbyakGenerator::Emplace(X64CodeCache* code_cache) {
|
||||
void* X64Emitter::Emplace(X64CodeCache* code_cache) {
|
||||
// To avoid changing xbyak, we do a switcharoo here.
|
||||
// top_ points to the Xbyak buffer, and since we are in AutoGrow mode
|
||||
// it has pending relocations. We copy the top_ to our buffer, swap the
|
||||
|
@ -100,7 +78,7 @@ void* XbyakGenerator::Emplace(X64CodeCache* code_cache) {
|
|||
return new_address;
|
||||
}
|
||||
|
||||
int XbyakGenerator::Emit(LIRBuilder* builder) {
|
||||
int X64Emitter::Emit(HIRBuilder* builder) {
|
||||
// Function prolog.
|
||||
// Must be 16b aligned.
|
||||
// Windows is very strict about the form of this and the epilog:
|
||||
|
@ -119,6 +97,8 @@ int XbyakGenerator::Emit(LIRBuilder* builder) {
|
|||
// TODO(benvanik): save registers.
|
||||
}
|
||||
|
||||
auto lowering_table = backend_->lowering_table();
|
||||
|
||||
// Body.
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
|
@ -130,18 +110,10 @@ int XbyakGenerator::Emit(LIRBuilder* builder) {
|
|||
}
|
||||
|
||||
// Add instructions.
|
||||
auto instr = block->instr_head;
|
||||
while (instr) {
|
||||
// Stash offset in debug info.
|
||||
// TODO(benvanik): stash size_ value.
|
||||
|
||||
// Emit.
|
||||
int result = EmitInstruction(instr);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
instr = instr->next;
|
||||
// The table will process sequences of instructions to (try to)
|
||||
// generate optimal code.
|
||||
if (lowering_table->ProcessBlock(*this, block)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
block = block->next;
|
||||
|
@ -157,67 +129,3 @@ int XbyakGenerator::Emit(LIRBuilder* builder) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,9 @@
|
|||
|
||||
#include <alloy/core.h>
|
||||
|
||||
#include <third_party/xbyak/xbyak/xbyak.h>
|
||||
|
||||
XEDECLARECLASS2(alloy, hir, HIRBuilder);
|
||||
|
||||
namespace alloy {
|
||||
namespace backend {
|
||||
|
@ -19,26 +22,31 @@ namespace x64 {
|
|||
|
||||
class X64Backend;
|
||||
class X64CodeCache;
|
||||
namespace lir { class LIRBuilder; }
|
||||
|
||||
class XbyakAllocator;
|
||||
class XbyakGenerator;
|
||||
|
||||
class X64Emitter {
|
||||
// Unfortunately due to the design of xbyak we have to pass this to the ctor.
|
||||
class XbyakAllocator : public Xbyak::Allocator {
|
||||
public:
|
||||
X64Emitter(X64Backend* backend);
|
||||
~X64Emitter();
|
||||
virtual bool useProtect() const { return false; }
|
||||
};
|
||||
|
||||
class X64Emitter : public Xbyak::CodeGenerator {
|
||||
public:
|
||||
X64Emitter(X64Backend* backend, XbyakAllocator* allocator);
|
||||
virtual ~X64Emitter();
|
||||
|
||||
int Initialize();
|
||||
|
||||
int Emit(lir::LIRBuilder* builder,
|
||||
int Emit(hir::HIRBuilder* builder,
|
||||
void*& out_code_address, size_t& out_code_size);
|
||||
|
||||
private:
|
||||
void* Emplace(X64CodeCache* code_cache);
|
||||
int Emit(hir::HIRBuilder* builder);
|
||||
|
||||
private:
|
||||
X64Backend* backend_;
|
||||
X64CodeCache* code_cache_;
|
||||
XbyakAllocator* allocator_;
|
||||
XbyakGenerator* generator_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <alloy/compiler/passes/constant_propagation_pass.h>
|
||||
#include <alloy/compiler/passes/context_promotion_pass.h>
|
||||
#include <alloy/compiler/passes/dead_code_elimination_pass.h>
|
||||
#include <alloy/compiler/passes/finalization_pass.h>
|
||||
#include <alloy/compiler/passes/register_allocation_pass.h>
|
||||
//#include <alloy/compiler/passes/dead_store_elimination_pass.h>
|
||||
#include <alloy/compiler/passes/simplification_pass.h>
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <alloy/compiler/passes/finalization_pass.h>
|
||||
|
||||
#include <alloy/backend/backend.h>
|
||||
#include <alloy/compiler/compiler.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::compiler::passes;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
FinalizationPass::FinalizationPass() :
|
||||
CompilerPass() {
|
||||
}
|
||||
|
||||
FinalizationPass::~FinalizationPass() {
|
||||
}
|
||||
|
||||
int FinalizationPass::Run(HIRBuilder* builder) {
|
||||
// Process the HIR and prepare it for lowering.
|
||||
// After this is done the HIR should be ready for emitting.
|
||||
|
||||
auto arena = builder->arena();
|
||||
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
// Ensure all labels have names.
|
||||
auto label = block->label_head;
|
||||
while (label) {
|
||||
if (!label->name) {
|
||||
char* name = (char*)arena->Alloc(6 + 4 + 1);
|
||||
xestrcpya(name, 6 + 1, "_label");
|
||||
char* part = _itoa(label->id, name + 6, 10);
|
||||
label->name = name;
|
||||
}
|
||||
label = label->next;
|
||||
}
|
||||
|
||||
// ?
|
||||
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef ALLOY_COMPILER_PASSES_FINALIZATION_PASS_H_
|
||||
#define ALLOY_COMPILER_PASSES_FINALIZATION_PASS_H_
|
||||
|
||||
#include <alloy/compiler/compiler_pass.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
namespace passes {
|
||||
|
||||
|
||||
class FinalizationPass : public CompilerPass {
|
||||
public:
|
||||
FinalizationPass();
|
||||
virtual ~FinalizationPass();
|
||||
|
||||
virtual int Run(hir::HIRBuilder* builder);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
} // namespace passes
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_PASSES_FINALIZATION_PASS_H_
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <alloy/compiler/passes/register_allocation_pass.h>
|
||||
|
||||
#include <alloy/backend/backend.h>
|
||||
#include <alloy/compiler/compiler.h>
|
||||
#include <alloy/runtime/runtime.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::backend;
|
||||
using namespace alloy::compiler;
|
||||
using namespace alloy::compiler::passes;
|
||||
using namespace alloy::frontend;
|
||||
using namespace alloy::hir;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
RegisterAllocationPass::RegisterAllocationPass(Backend* backend) :
|
||||
CompilerPass() {
|
||||
// TODO(benvanik): query backend info (register layout, etc).
|
||||
}
|
||||
|
||||
RegisterAllocationPass::~RegisterAllocationPass() {
|
||||
}
|
||||
|
||||
int RegisterAllocationPass::Run(HIRBuilder* builder) {
|
||||
// Run through each block and give each dest value a register.
|
||||
// This pass is currently really dumb, and will over spill and other badness.
|
||||
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
if (ProcessBlock(block)) {
|
||||
return 1;
|
||||
}
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RegisterAllocationPass::ProcessBlock(Block* block) {
|
||||
//
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef ALLOY_COMPILER_PASSES_REGISTER_ALLOCATION_PASS_H_
|
||||
#define ALLOY_COMPILER_PASSES_REGISTER_ALLOCATION_PASS_H_
|
||||
|
||||
#include <alloy/compiler/compiler_pass.h>
|
||||
|
||||
XEDECLARECLASS2(alloy, backend, Backend);
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace compiler {
|
||||
namespace passes {
|
||||
|
||||
|
||||
class RegisterAllocationPass : public CompilerPass {
|
||||
public:
|
||||
RegisterAllocationPass(backend::Backend* backend);
|
||||
virtual ~RegisterAllocationPass();
|
||||
|
||||
virtual int Run(hir::HIRBuilder* builder);
|
||||
|
||||
private:
|
||||
int ProcessBlock(hir::Block* block);
|
||||
};
|
||||
|
||||
|
||||
} // namespace passes
|
||||
} // namespace compiler
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_COMPILER_PASSES_REGISTER_ALLOCATION_PASS_H_
|
|
@ -7,6 +7,10 @@
|
|||
'context_promotion_pass.h',
|
||||
'dead_code_elimination_pass.cc',
|
||||
'dead_code_elimination_pass.h',
|
||||
'finalization_pass.cc',
|
||||
'finalization_pass.h',
|
||||
'register_allocation_pass.cc',
|
||||
'register_allocation_pass.h',
|
||||
#'dead_store_elimination_pass.cc',
|
||||
#'dead_store_elimination_pass.h',
|
||||
'simplification_pass.cc',
|
||||
|
|
|
@ -30,11 +30,16 @@ using namespace alloy::runtime;
|
|||
|
||||
PPCTranslator::PPCTranslator(PPCFrontend* frontend) :
|
||||
frontend_(frontend) {
|
||||
Backend* backend = frontend->runtime()->backend();
|
||||
|
||||
scanner_ = new PPCScanner(frontend);
|
||||
builder_ = new PPCHIRBuilder(frontend);
|
||||
|
||||
compiler_ = new Compiler(frontend->runtime());
|
||||
assembler_ = backend->CreateAssembler();
|
||||
assembler_->Initialize();
|
||||
|
||||
// Passes are executed in the order they are added. Multiple of the same
|
||||
// pass type may be used.
|
||||
compiler_->AddPass(new passes::ContextPromotionPass());
|
||||
compiler_->AddPass(new passes::SimplificationPass());
|
||||
// TODO(benvanik): run repeatedly?
|
||||
|
@ -45,9 +50,11 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) :
|
|||
//compiler_->AddPass(new passes::DeadStoreEliminationPass());
|
||||
compiler_->AddPass(new passes::DeadCodeEliminationPass());
|
||||
|
||||
Backend* backend = frontend->runtime()->backend();
|
||||
assembler_ = backend->CreateAssembler();
|
||||
assembler_->Initialize();
|
||||
// After register allocation instructions should not be added/removed.
|
||||
compiler_->AddPass(new passes::RegisterAllocationPass(backend));
|
||||
|
||||
// Must come last. The HIR is not really HIR after this.
|
||||
compiler_->AddPass(new passes::FinalizationPass());
|
||||
}
|
||||
|
||||
PPCTranslator::~PPCTranslator() {
|
||||
|
|
|
@ -17,8 +17,6 @@ DebugInfo::DebugInfo() :
|
|||
source_disasm_(0),
|
||||
raw_hir_disasm_(0),
|
||||
hir_disasm_(0),
|
||||
raw_lir_disasm_(0),
|
||||
lir_disasm_(0),
|
||||
machine_code_disasm_(0) {
|
||||
}
|
||||
|
||||
|
@ -26,7 +24,5 @@ DebugInfo::~DebugInfo() {
|
|||
xe_free(source_disasm_);
|
||||
xe_free(raw_hir_disasm_);
|
||||
xe_free(hir_disasm_);
|
||||
xe_free(raw_lir_disasm_);
|
||||
xe_free(lir_disasm_);
|
||||
xe_free(machine_code_disasm_);
|
||||
}
|
||||
|
|
|
@ -23,9 +23,7 @@ enum DebugInfoFlags {
|
|||
DEBUG_INFO_SOURCE_DISASM = (1 << 1),
|
||||
DEBUG_INFO_RAW_HIR_DISASM = (1 << 2),
|
||||
DEBUG_INFO_HIR_DISASM = (1 << 3),
|
||||
DEBUG_INFO_RAW_LIR_DISASM = (1 << 4),
|
||||
DEBUG_INFO_LIR_DISASM = (1 << 5),
|
||||
DEBUG_INFO_MACHINE_CODE_DISASM = (1 << 6),
|
||||
DEBUG_INFO_MACHINE_CODE_DISASM = (1 << 4),
|
||||
|
||||
DEBUG_INFO_ALL_DISASM = 0xFFFF,
|
||||
};
|
||||
|
@ -42,10 +40,6 @@ public:
|
|||
void set_raw_hir_disasm(char* value) { raw_hir_disasm_ = value; }
|
||||
const char* hir_disasm() const { return hir_disasm_; }
|
||||
void set_hir_disasm(char* value) { hir_disasm_ = value; }
|
||||
const char* raw_lir_disasm() const { return raw_lir_disasm_; }
|
||||
void set_raw_lir_disasm(char* value) { raw_lir_disasm_ = value; }
|
||||
const char* lir_disasm() const { return lir_disasm_; }
|
||||
void set_lir_disasm(char* value) { lir_disasm_ = value; }
|
||||
const char* machine_code_disasm() const { return machine_code_disasm_; }
|
||||
void set_machine_code_disasm(char* value) { machine_code_disasm_ = value; }
|
||||
|
||||
|
@ -58,8 +52,6 @@ private:
|
|||
char* source_disasm_;
|
||||
char* raw_hir_disasm_;
|
||||
char* hir_disasm_;
|
||||
char* raw_lir_disasm_;
|
||||
char* lir_disasm_;
|
||||
char* machine_code_disasm_;
|
||||
};
|
||||
|
||||
|
|
|
@ -91,10 +91,10 @@ int Runtime::Initialize(Frontend* frontend, Backend* backend) {
|
|||
#endif // ALLOY_HAS_IVM_BACKEND
|
||||
if (FLAGS_runtime_backend == "any") {
|
||||
#if defined(ALLOY_HAS_X64_BACKEND) && ALLOY_HAS_X64_BACKEND
|
||||
/*if (!backend) {
|
||||
if (!backend) {
|
||||
backend = new alloy::backend::x64::X64Backend(
|
||||
this);
|
||||
}*/
|
||||
}
|
||||
#endif // ALLOY_HAS_X64_BACKEND
|
||||
#if defined(ALLOY_HAS_IVM_BACKEND) && ALLOY_HAS_IVM_BACKEND
|
||||
if (!backend) {
|
||||
|
|
|
@ -704,10 +704,6 @@ json_t* Processor::DumpFunction(uint64_t address, bool& succeeded) {
|
|||
json_object_set_new(disasm_json, "rawHir", disasm_str_json);
|
||||
disasm_str_json = json_string(debug_info->hir_disasm());
|
||||
json_object_set_new(disasm_json, "hir", disasm_str_json);
|
||||
disasm_str_json = json_string(debug_info->raw_lir_disasm());
|
||||
json_object_set_new(disasm_json, "rawLir", disasm_str_json);
|
||||
disasm_str_json = json_string(debug_info->lir_disasm());
|
||||
json_object_set_new(disasm_json, "lir", disasm_str_json);
|
||||
disasm_str_json = json_string(debug_info->machine_code_disasm());
|
||||
json_object_set_new(disasm_json, "machineCode", disasm_str_json);
|
||||
json_object_set_new(fn_json, "disasm", disasm_json);
|
||||
|
|
Loading…
Reference in New Issue