Rearranging code a bit to keep things cleaner.
This commit is contained in:
parent
b91d550ef1
commit
95a8be078b
|
@ -7,34 +7,31 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_CPU_PPC_INSTR_CONTEXT_H_
|
#ifndef XENIA_CPU_CODEGEN_FUNCTION_GENERATOR_H_
|
||||||
#define XENIA_CPU_PPC_INSTR_CONTEXT_H_
|
#define XENIA_CPU_CODEGEN_FUNCTION_GENERATOR_H_
|
||||||
|
|
||||||
#include <xenia/cpu/ppc/instr.h>
|
#include <llvm/IR/Attributes.h>
|
||||||
|
#include <llvm/IR/DataLayout.h>
|
||||||
|
#include <llvm/IR/DerivedTypes.h>
|
||||||
|
#include <llvm/IR/IRBuilder.h>
|
||||||
|
#include <llvm/IR/LLVMContext.h>
|
||||||
|
#include <llvm/IR/Module.h>
|
||||||
|
|
||||||
#include <xenia/cpu/sdb.h>
|
#include <xenia/cpu/sdb.h>
|
||||||
|
#include <xenia/cpu/ppc/instr.h>
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class LLVMContext;
|
|
||||||
class Module;
|
|
||||||
class Function;
|
|
||||||
class BasicBlock;
|
|
||||||
class Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
namespace ppc {
|
namespace codegen {
|
||||||
|
|
||||||
|
|
||||||
class InstrContext {
|
class FunctionGenerator {
|
||||||
public:
|
public:
|
||||||
InstrContext(xe_memory_ref memory, sdb::FunctionSymbol* fn,
|
FunctionGenerator(xe_memory_ref memory, sdb::FunctionSymbol* fn,
|
||||||
llvm::LLVMContext* context, llvm::Module* gen_module,
|
llvm::LLVMContext* context, llvm::Module* gen_module,
|
||||||
llvm::Function* gen_fn);
|
llvm::Function* gen_fn);
|
||||||
~InstrContext();
|
~FunctionGenerator();
|
||||||
|
|
||||||
sdb::FunctionSymbol* fn();
|
sdb::FunctionSymbol* fn();
|
||||||
llvm::LLVMContext* context();
|
llvm::LLVMContext* context();
|
||||||
|
@ -47,13 +44,18 @@ public:
|
||||||
llvm::Function* GetFunction(uint32_t addr);
|
llvm::Function* GetFunction(uint32_t addr);
|
||||||
|
|
||||||
llvm::Value* cia_value();
|
llvm::Value* cia_value();
|
||||||
llvm::Value* nia_value();
|
|
||||||
void update_nia_value(llvm::Value* value);
|
|
||||||
llvm::Value* spr_value(uint32_t n);
|
|
||||||
void update_spr_value(uint32_t n, llvm::Value* value);
|
|
||||||
|
|
||||||
llvm::Value* cr_value();
|
void FlushRegisters();
|
||||||
void update_cr_value(llvm::Value* value);
|
|
||||||
|
llvm::Value* xer_value();
|
||||||
|
void update_xer_value(llvm::Value* value);
|
||||||
|
llvm::Value* lr_value();
|
||||||
|
void update_lr_value(llvm::Value* value);
|
||||||
|
llvm::Value* ctr_value();
|
||||||
|
void update_ctr_value(llvm::Value* value);
|
||||||
|
|
||||||
|
llvm::Value* cr_value(uint32_t n);
|
||||||
|
void update_cr_value(uint32_t n, llvm::Value* value);
|
||||||
|
|
||||||
llvm::Value* gpr_value(uint32_t n);
|
llvm::Value* gpr_value(uint32_t n);
|
||||||
void update_gpr_value(uint32_t n, llvm::Value* value);
|
void update_gpr_value(uint32_t n, llvm::Value* value);
|
||||||
|
@ -70,18 +72,28 @@ private:
|
||||||
llvm::LLVMContext* context_;
|
llvm::LLVMContext* context_;
|
||||||
llvm::Module* gen_module_;
|
llvm::Module* gen_module_;
|
||||||
llvm::Function* gen_fn_;
|
llvm::Function* gen_fn_;
|
||||||
// TODO(benvanik): IRBuilder/etc
|
llvm::IRBuilder<>* builder_;
|
||||||
|
|
||||||
std::map<uint32_t, llvm::BasicBlock*> bbs_;
|
std::map<uint32_t, llvm::BasicBlock*> bbs_;
|
||||||
|
|
||||||
// Address of the instruction being generated.
|
// Address of the instruction being generated.
|
||||||
uint32_t cia_;
|
uint32_t cia_;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
llvm::Value* xer;
|
||||||
|
llvm::Value* lr;
|
||||||
|
llvm::Value* ctr;
|
||||||
|
|
||||||
|
llvm::Value* cr[4];
|
||||||
|
|
||||||
|
llvm::Value* gpr[32];
|
||||||
|
} values_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace ppc
|
} // namespace codegen
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
#endif // XENIA_CPU_PPC_INSTR_CONTEXT_H_
|
#endif // XENIA_CPU_CODEGEN_FUNCTION_GENERATOR_H_
|
|
@ -7,8 +7,8 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_CPU_CODEGEN_H_
|
#ifndef XENIA_CPU_CODEGEN_MODULE_GENERATOR_H_
|
||||||
#define XENIA_CPU_CODEGEN_H_
|
#define XENIA_CPU_CODEGEN_MODULE_GENERATOR_H_
|
||||||
|
|
||||||
#include <xenia/cpu/sdb.h>
|
#include <xenia/cpu/sdb.h>
|
||||||
#include <xenia/core/memory.h>
|
#include <xenia/core/memory.h>
|
||||||
|
@ -31,25 +31,24 @@ namespace cpu {
|
||||||
namespace codegen {
|
namespace codegen {
|
||||||
|
|
||||||
|
|
||||||
class CodegenFunction {
|
class ModuleGenerator {
|
||||||
public:
|
public:
|
||||||
sdb::FunctionSymbol* symbol;
|
ModuleGenerator(
|
||||||
llvm::FunctionType* function_type;
|
|
||||||
llvm::Function* function;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class CodegenContext {
|
|
||||||
public:
|
|
||||||
CodegenContext(
|
|
||||||
xe_memory_ref memory, kernel::ExportResolver* export_resolver,
|
xe_memory_ref memory, kernel::ExportResolver* export_resolver,
|
||||||
kernel::UserModule* module, sdb::SymbolDatabase* sdb,
|
kernel::UserModule* module, sdb::SymbolDatabase* sdb,
|
||||||
llvm::LLVMContext* context, llvm::Module* gen_module);
|
llvm::LLVMContext* context, llvm::Module* gen_module);
|
||||||
~CodegenContext();
|
~ModuleGenerator();
|
||||||
|
|
||||||
int GenerateModule();
|
int Generate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class CodegenFunction {
|
||||||
|
public:
|
||||||
|
sdb::FunctionSymbol* symbol;
|
||||||
|
llvm::FunctionType* function_type;
|
||||||
|
llvm::Function* function;
|
||||||
|
};
|
||||||
|
|
||||||
CodegenFunction* GetCodegenFunction(uint32_t address);
|
CodegenFunction* GetCodegenFunction(uint32_t address);
|
||||||
|
|
||||||
void AddImports();
|
void AddImports();
|
||||||
|
@ -78,4 +77,4 @@ private:
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
#endif // XENIA_CPU_CODEGEN_H_
|
#endif // XENIA_CPU_CODEGEN_MODULE_GENERATOR_H_
|
|
@ -27,7 +27,7 @@ namespace llvm {
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
namespace codegen {
|
namespace codegen {
|
||||||
class CodegenContext;
|
class ModuleGenerator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,14 +53,14 @@ private:
|
||||||
int Init();
|
int Init();
|
||||||
int Uninit();
|
int Uninit();
|
||||||
|
|
||||||
xe_memory_ref memory_;
|
xe_memory_ref memory_;
|
||||||
shared_ptr<kernel::ExportResolver> export_resolver_;
|
shared_ptr<kernel::ExportResolver> export_resolver_;
|
||||||
kernel::UserModule* module_;
|
kernel::UserModule* module_;
|
||||||
shared_ptr<llvm::ExecutionEngine> engine_;
|
shared_ptr<llvm::ExecutionEngine> engine_;
|
||||||
shared_ptr<sdb::SymbolDatabase> sdb_;
|
shared_ptr<sdb::SymbolDatabase> sdb_;
|
||||||
shared_ptr<llvm::LLVMContext> context_;
|
shared_ptr<llvm::LLVMContext> context_;
|
||||||
shared_ptr<llvm::Module> gen_module_;
|
shared_ptr<llvm::Module> gen_module_;
|
||||||
auto_ptr<codegen::CodegenContext> codegen_;
|
auto_ptr<codegen::ModuleGenerator> codegen_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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 <xenia/cpu/codegen/function_generator.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
using namespace xe::cpu::codegen;
|
||||||
|
using namespace xe::cpu::ppc;
|
||||||
|
using namespace xe::cpu::sdb;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This generates function code.
|
||||||
|
* One context is created for each function to generate. Each basic block in
|
||||||
|
* the function is created and stashed in one pass, then filled in the next.
|
||||||
|
*
|
||||||
|
* This context object is a stateful representation of the current machine state
|
||||||
|
* and all accessors to registers should occur through it. By doing so it's
|
||||||
|
* possible to exploit the SSA nature of LLVM to reuse register values within
|
||||||
|
* a function without needing to flush to memory.
|
||||||
|
*
|
||||||
|
* Function calls (any branch outside of the function) will result in an
|
||||||
|
* expensive flush of registers.
|
||||||
|
*
|
||||||
|
* TODO(benvanik): track arguments by looking for register reads without writes
|
||||||
|
* TODO(benvanik): avoid flushing registers for leaf nodes
|
||||||
|
* TODO(benvnaik): pass return value in LLVM return, not by memory
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
FunctionGenerator::FunctionGenerator(xe_memory_ref memory, FunctionSymbol* fn,
|
||||||
|
LLVMContext* context, Module* gen_module,
|
||||||
|
Function* gen_fn) {
|
||||||
|
memory_ = memory;
|
||||||
|
fn_ = fn;
|
||||||
|
context_ = context;
|
||||||
|
gen_module_ = gen_module;
|
||||||
|
gen_fn_ = gen_fn;
|
||||||
|
builder_ = new IRBuilder<>(*context_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionGenerator::~FunctionGenerator() {
|
||||||
|
delete builder_;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionSymbol* FunctionGenerator::fn() {
|
||||||
|
return fn_;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::LLVMContext* FunctionGenerator::context() {
|
||||||
|
return context_;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Module* FunctionGenerator::gen_module() {
|
||||||
|
return gen_module_;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Function* FunctionGenerator::gen_fn() {
|
||||||
|
return gen_fn_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::GenerateBasicBlocks() {
|
||||||
|
// Pass 1 creates all of the blocks - this way we can branch to them.
|
||||||
|
for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin();
|
||||||
|
it != fn_->blocks.end(); ++it) {
|
||||||
|
FunctionBlock* block = it->second;
|
||||||
|
|
||||||
|
char name[32];
|
||||||
|
xesnprintfa(name, XECOUNT(name), "loc_%.8X", block->start_address);
|
||||||
|
BasicBlock* bb = BasicBlock::Create(*context_, name, gen_fn_);
|
||||||
|
bbs_.insert(std::pair<uint32_t, BasicBlock*>(block->start_address, bb));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin();
|
||||||
|
it != fn_->blocks.end(); ++it) {
|
||||||
|
FunctionBlock* block = it->second;
|
||||||
|
GenerateBasicBlock(block, GetBasicBlock(block->start_address));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block,
|
||||||
|
BasicBlock* bb) {
|
||||||
|
printf(" bb %.8X-%.8X:\n", block->start_address, block->end_address);
|
||||||
|
|
||||||
|
// Move the builder to this block and setup.
|
||||||
|
builder_->SetInsertPoint(bb);
|
||||||
|
//i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
|
||||||
|
|
||||||
|
// Walk instructions in block.
|
||||||
|
uint8_t* p = xe_memory_addr(memory_, 0);
|
||||||
|
for (uint32_t ia = block->start_address; ia <= block->end_address; ia += 4) {
|
||||||
|
InstrData i;
|
||||||
|
i.address = ia;
|
||||||
|
i.code = XEGETUINT32BE(p + ia);
|
||||||
|
i.type = ppc::GetInstrType(i.code);
|
||||||
|
if (!i.type) {
|
||||||
|
XELOGCPU("Invalid instruction at %.8X: %.8X\n", ia, i.code);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf(" %.8X: %.8X %s\n", ia, i.code, i.type->name);
|
||||||
|
|
||||||
|
// TODO(benvanik): debugging information? source/etc?
|
||||||
|
// builder_>SetCurrentDebugLocation(DebugLoc::get(
|
||||||
|
// ia >> 8, ia & 0xFF, ctx->cu));
|
||||||
|
|
||||||
|
//emit(this, i, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Value* tmp = builder_->getInt32(0);
|
||||||
|
builder_->CreateRetVoid();
|
||||||
|
|
||||||
|
// TODO(benvanik): finish up BB
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicBlock* FunctionGenerator::GetBasicBlock(uint32_t address) {
|
||||||
|
std::map<uint32_t, BasicBlock*>::iterator it = bbs_.find(address);
|
||||||
|
if (it != bbs_.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Function* FunctionGenerator::GetFunction(uint32_t addr) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* FunctionGenerator::cia_value() {
|
||||||
|
return builder_->getInt32(cia_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::FlushRegisters() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* FunctionGenerator::xer_value() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::update_xer_value(Value* value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* FunctionGenerator::lr_value() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::update_lr_value(Value* value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* FunctionGenerator::ctr_value() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::update_ctr_value(Value* value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* FunctionGenerator::cr_value(uint32_t n) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::update_cr_value(uint32_t n, Value* value) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* FunctionGenerator::gpr_value(uint32_t n) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::update_gpr_value(uint32_t n, Value* value) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* FunctionGenerator::memory_addr(uint32_t addr) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* FunctionGenerator::read_memory(Value* addr, uint32_t size, bool extend) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionGenerator::write_memory(Value* addr, uint32_t size, Value* value) {
|
||||||
|
//
|
||||||
|
}
|
|
@ -7,7 +7,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <xenia/cpu/codegen.h>
|
#include <xenia/cpu/codegen/module_generator.h>
|
||||||
|
|
||||||
#include <llvm/DIBuilder.h>
|
#include <llvm/DIBuilder.h>
|
||||||
#include <llvm/Linker.h>
|
#include <llvm/Linker.h>
|
||||||
|
@ -24,18 +24,18 @@
|
||||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||||
|
|
||||||
#include <xenia/cpu/ppc.h>
|
#include <xenia/cpu/ppc.h>
|
||||||
#include "cpu/ppc/instr_context.h"
|
#include <xenia/cpu/codegen/function_generator.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace xe;
|
using namespace xe;
|
||||||
using namespace xe::cpu;
|
using namespace xe::cpu;
|
||||||
using namespace xe::cpu::codegen;
|
using namespace xe::cpu::codegen;
|
||||||
using namespace xe::cpu::ppc;
|
|
||||||
using namespace xe::cpu::sdb;
|
using namespace xe::cpu::sdb;
|
||||||
using namespace xe::kernel;
|
using namespace xe::kernel;
|
||||||
|
|
||||||
|
|
||||||
CodegenContext::CodegenContext(
|
ModuleGenerator::ModuleGenerator(
|
||||||
xe_memory_ref memory, ExportResolver* export_resolver,
|
xe_memory_ref memory, ExportResolver* export_resolver,
|
||||||
UserModule* module, SymbolDatabase* sdb,
|
UserModule* module, SymbolDatabase* sdb,
|
||||||
LLVMContext* context, Module* gen_module) {
|
LLVMContext* context, Module* gen_module) {
|
||||||
|
@ -47,11 +47,11 @@ CodegenContext::CodegenContext(
|
||||||
gen_module_ = gen_module;
|
gen_module_ = gen_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
CodegenContext::~CodegenContext() {
|
ModuleGenerator::~ModuleGenerator() {
|
||||||
xe_memory_release(memory_);
|
xe_memory_release(memory_);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CodegenContext::GenerateModule() {
|
int ModuleGenerator::Generate() {
|
||||||
std::string error_message;
|
std::string error_message;
|
||||||
|
|
||||||
// Setup a debug info builder.
|
// Setup a debug info builder.
|
||||||
|
@ -111,7 +111,8 @@ int CodegenContext::GenerateModule() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CodegenFunction* CodegenContext::GetCodegenFunction(uint32_t address) {
|
ModuleGenerator::CodegenFunction* ModuleGenerator::GetCodegenFunction(
|
||||||
|
uint32_t address) {
|
||||||
std::map<uint32_t, CodegenFunction*>::iterator it = functions_.find(address);
|
std::map<uint32_t, CodegenFunction*>::iterator it = functions_.find(address);
|
||||||
if (it != functions_.end()) {
|
if (it != functions_.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
|
@ -119,7 +120,7 @@ CodegenFunction* CodegenContext::GetCodegenFunction(uint32_t address) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodegenContext::AddMissingImport(FunctionSymbol* fn) {
|
void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) {
|
||||||
Module* m = gen_module_;
|
Module* m = gen_module_;
|
||||||
LLVMContext& context = m->getContext();
|
LLVMContext& context = m->getContext();
|
||||||
|
|
||||||
|
@ -158,14 +159,14 @@ void CodegenContext::AddMissingImport(FunctionSymbol* fn) {
|
||||||
// implemented ? " " : "!!", name);
|
// implemented ? " " : "!!", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodegenContext::AddPresentImport(FunctionSymbol* fn) {
|
void ModuleGenerator::AddPresentImport(FunctionSymbol* fn) {
|
||||||
// Module *m = gen_module_;
|
// Module *m = gen_module_;
|
||||||
// LLVMContext& context = m->getContext();
|
// LLVMContext& context = m->getContext();
|
||||||
|
|
||||||
// TODO(benvanik): add import thunk code.
|
// TODO(benvanik): add import thunk code.
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodegenContext::PrepareFunction(FunctionSymbol* fn) {
|
void ModuleGenerator::PrepareFunction(FunctionSymbol* fn) {
|
||||||
Module* m = gen_module_;
|
Module* m = gen_module_;
|
||||||
LLVMContext& context = m->getContext();
|
LLVMContext& context = m->getContext();
|
||||||
|
|
||||||
|
@ -177,7 +178,7 @@ void CodegenContext::PrepareFunction(FunctionSymbol* fn) {
|
||||||
AttributeSet attrs = AttributeSet::get(context, awi);
|
AttributeSet attrs = AttributeSet::get(context, awi);
|
||||||
|
|
||||||
std::vector<Type*> args;
|
std::vector<Type*> args;
|
||||||
Type* return_type = Type::getInt32Ty(context);
|
Type* return_type = Type::getVoidTy(context);
|
||||||
|
|
||||||
char name[64];
|
char name[64];
|
||||||
char* pname = name;
|
char* pname = name;
|
||||||
|
@ -202,16 +203,16 @@ void CodegenContext::PrepareFunction(FunctionSymbol* fn) {
|
||||||
fn->start_address, cgf));
|
fn->start_address, cgf));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodegenContext::BuildFunction(CodegenFunction* cgf) {
|
void ModuleGenerator::BuildFunction(CodegenFunction* cgf) {
|
||||||
FunctionSymbol* fn = cgf->symbol;
|
FunctionSymbol* fn = cgf->symbol;
|
||||||
|
|
||||||
printf("%s:\n", fn->name);
|
printf("%s:\n", fn->name);
|
||||||
|
|
||||||
// Setup the generation context.
|
// Setup the generation context.
|
||||||
InstrContext ic(memory_, fn, context_, gen_module_, cgf->function);
|
FunctionGenerator fgen(memory_, fn, context_, gen_module_, cgf->function);
|
||||||
|
|
||||||
// Run through and generate each basic block.
|
// Run through and generate each basic block.
|
||||||
ic.GenerateBasicBlocks();
|
fgen.GenerateBasicBlocks();
|
||||||
|
|
||||||
// Run the optimizer on the function.
|
// Run the optimizer on the function.
|
||||||
// Doing this here keeps the size of the IR small and speeds up the later
|
// Doing this here keeps the size of the IR small and speeds up the later
|
||||||
|
@ -219,7 +220,7 @@ void CodegenContext::BuildFunction(CodegenFunction* cgf) {
|
||||||
OptimizeFunction(gen_module_, cgf->function);
|
OptimizeFunction(gen_module_, cgf->function);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodegenContext::OptimizeFunction(Module* m, Function* fn) {
|
void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) {
|
||||||
FunctionPassManager pm(m);
|
FunctionPassManager pm(m);
|
||||||
PassManagerBuilder pmb;
|
PassManagerBuilder pmb;
|
||||||
pmb.OptLevel = 3;
|
pmb.OptLevel = 3;
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||||
|
{
|
||||||
|
'sources': [
|
||||||
|
'function_generator.cc',
|
||||||
|
'module_generator.cc',
|
||||||
|
],
|
||||||
|
}
|
|
@ -27,7 +27,7 @@
|
||||||
#include <llvm/Transforms/IPO.h>
|
#include <llvm/Transforms/IPO.h>
|
||||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||||
|
|
||||||
#include <xenia/cpu/codegen.h>
|
#include <xenia/cpu/codegen/module_generator.h>
|
||||||
#include <xenia/cpu/sdb.h>
|
#include <xenia/cpu/sdb.h>
|
||||||
|
|
||||||
#include "cpu/xethunk/xethunk.h"
|
#include "cpu/xethunk/xethunk.h"
|
||||||
|
@ -115,10 +115,10 @@ int ExecModule::Prepare() {
|
||||||
&error_message);
|
&error_message);
|
||||||
|
|
||||||
// Build the module from the source code.
|
// Build the module from the source code.
|
||||||
codegen_ = auto_ptr<CodegenContext>(new CodegenContext(
|
codegen_ = auto_ptr<ModuleGenerator>(new ModuleGenerator(
|
||||||
memory_, export_resolver_.get(), module_, sdb_.get(),
|
memory_, export_resolver_.get(), module_, sdb_.get(),
|
||||||
context_.get(), gen_module_.get()));
|
context_.get(), gen_module_.get()));
|
||||||
XEEXPECTZERO(codegen_->GenerateModule());
|
XEEXPECTZERO(codegen_->Generate());
|
||||||
|
|
||||||
// Write to cache.
|
// Write to cache.
|
||||||
outs = auto_ptr<raw_ostream>(new raw_fd_ostream(
|
outs = auto_ptr<raw_ostream>(new raw_fd_ostream(
|
||||||
|
|
|
@ -1,162 +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 "cpu/ppc/instr_context.h"
|
|
||||||
|
|
||||||
#include <llvm/IR/Attributes.h>
|
|
||||||
#include <llvm/IR/DataLayout.h>
|
|
||||||
#include <llvm/IR/DerivedTypes.h>
|
|
||||||
#include <llvm/IR/IRBuilder.h>
|
|
||||||
#include <llvm/IR/LLVMContext.h>
|
|
||||||
#include <llvm/IR/Module.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace llvm;
|
|
||||||
using namespace xe::cpu::ppc;
|
|
||||||
using namespace xe::cpu::sdb;
|
|
||||||
|
|
||||||
|
|
||||||
InstrContext::InstrContext(xe_memory_ref memory, FunctionSymbol* fn,
|
|
||||||
LLVMContext* context, Module* gen_module,
|
|
||||||
Function* gen_fn) {
|
|
||||||
memory_ = memory;
|
|
||||||
fn_ = fn;
|
|
||||||
context_ = context;
|
|
||||||
gen_module_ = gen_module;
|
|
||||||
gen_fn_ = gen_fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstrContext::~InstrContext() {
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionSymbol* InstrContext::fn() {
|
|
||||||
return fn_;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::LLVMContext* InstrContext::context() {
|
|
||||||
return context_;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Module* InstrContext::gen_module() {
|
|
||||||
return gen_module_;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Function* InstrContext::gen_fn() {
|
|
||||||
return gen_fn_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstrContext::GenerateBasicBlocks() {
|
|
||||||
// Pass 1 creates all of the blocks - this way we can branch to them.
|
|
||||||
for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin();
|
|
||||||
it != fn_->blocks.end(); ++it) {
|
|
||||||
FunctionBlock* block = it->second;
|
|
||||||
|
|
||||||
char name[32];
|
|
||||||
xesnprintfa(name, XECOUNT(name), "loc_%.8X", block->start_address);
|
|
||||||
BasicBlock* bb = BasicBlock::Create(*context_, name, gen_fn_);
|
|
||||||
bbs_.insert(std::pair<uint32_t, BasicBlock*>(block->start_address, bb));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin();
|
|
||||||
it != fn_->blocks.end(); ++it) {
|
|
||||||
FunctionBlock* block = it->second;
|
|
||||||
GenerateBasicBlock(block, GetBasicBlock(block->start_address));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstrContext::GenerateBasicBlock(FunctionBlock* block, BasicBlock* bb) {
|
|
||||||
printf(" bb %.8X-%.8X:\n", block->start_address, block->end_address);
|
|
||||||
|
|
||||||
//builder.SetCurrentDebugLocation(DebugLoc::get(fn->start_address >> 8, fn->start_address & 0xFF, ctx->cu));
|
|
||||||
//i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
|
|
||||||
|
|
||||||
IRBuilder<> builder(bb);
|
|
||||||
|
|
||||||
// Walk instructions in block.
|
|
||||||
uint8_t* p = xe_memory_addr(memory_, 0);
|
|
||||||
for (uint32_t ia = block->start_address; ia <= block->end_address; ia += 4) {
|
|
||||||
InstrData i;
|
|
||||||
i.address = ia;
|
|
||||||
i.code = XEGETUINT32BE(p + ia);
|
|
||||||
i.type = ppc::GetInstrType(i.code);
|
|
||||||
if (!i.type) {
|
|
||||||
XELOGCPU("Invalid instruction at %.8X: %.8X\n", ia, i.code);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
printf(" %.8X: %.8X %s\n", ia, i.code, i.type->name);
|
|
||||||
// stash current bb?
|
|
||||||
// stash builder
|
|
||||||
//emit(this, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* tmp = builder.getInt32(0);
|
|
||||||
builder.CreateRet(tmp);
|
|
||||||
|
|
||||||
// TODO(benvanik): finish up BB
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicBlock* InstrContext::GetBasicBlock(uint32_t address) {
|
|
||||||
std::map<uint32_t, BasicBlock*>::iterator it = bbs_.find(address);
|
|
||||||
if (it != bbs_.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Function* InstrContext::GetFunction(uint32_t addr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* InstrContext::cia_value() {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* InstrContext::nia_value() {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstrContext::update_nia_value(Value* value) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* InstrContext::spr_value(uint32_t n) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstrContext::update_spr_value(uint32_t n, Value* value) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* InstrContext::cr_value() {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstrContext::update_cr_value(Value* value) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* InstrContext::gpr_value(uint32_t n) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstrContext::update_gpr_value(uint32_t n, Value* value) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* InstrContext::memory_addr(uint32_t addr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value* InstrContext::read_memory(Value* addr, uint32_t size, bool extend) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstrContext::write_memory(Value* addr, uint32_t size, Value* value) {
|
|
||||||
//
|
|
||||||
}
|
|
|
@ -2,6 +2,5 @@
|
||||||
{
|
{
|
||||||
'sources': [
|
'sources': [
|
||||||
'instr.cc',
|
'instr.cc',
|
||||||
'instr_context.cc',
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||||
{
|
{
|
||||||
'sources': [
|
'sources': [
|
||||||
'codegen.cc',
|
|
||||||
'exec_module.cc',
|
'exec_module.cc',
|
||||||
'processor.cc',
|
'processor.cc',
|
||||||
'sdb.cc',
|
'sdb.cc',
|
||||||
],
|
],
|
||||||
|
|
||||||
'includes': [
|
'includes': [
|
||||||
|
'codegen/sources.gypi',
|
||||||
'ppc/sources.gypi',
|
'ppc/sources.gypi',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue