Adding instruction generation loop.
Not yet doing anything, but close.
This commit is contained in:
parent
25af5f410a
commit
b91d550ef1
|
@ -50,13 +50,11 @@ public:
|
|||
int GenerateModule();
|
||||
|
||||
private:
|
||||
CodegenFunction* GetCodegenFunction(uint32_t address);
|
||||
|
||||
void AddImports();
|
||||
void AddMissingImport(
|
||||
const xe_xex2_import_library_t *library,
|
||||
const xe_xex2_import_info_t* info, kernel::KernelExport* kernel_export);
|
||||
void AddPresentImport(
|
||||
const xe_xex2_import_library_t *library,
|
||||
const xe_xex2_import_info_t* info, kernel::KernelExport* kernel_export);
|
||||
void AddMissingImport(sdb::FunctionSymbol* fn);
|
||||
void AddPresentImport(sdb::FunctionSymbol* fn);
|
||||
void PrepareFunction(sdb::FunctionSymbol* fn);
|
||||
void BuildFunction(CodegenFunction* cgf);
|
||||
void OptimizeFunction(llvm::Module* m, llvm::Function* fn);
|
||||
|
@ -71,7 +69,7 @@ private:
|
|||
llvm::DIBuilder* di_builder_;
|
||||
llvm::MDNode* cu_;
|
||||
|
||||
std::map<sdb::FunctionSymbol*, CodegenFunction*> functions_;
|
||||
std::map<uint32_t, CodegenFunction*> functions_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ public:
|
|||
FunctionType type;
|
||||
uint32_t flags;
|
||||
|
||||
kernel::KernelExport* kernel_export;
|
||||
ExceptionEntrySymbol* ee;
|
||||
|
||||
vector<FunctionCall*> incoming_calls;
|
||||
|
|
|
@ -74,9 +74,6 @@ int CodegenContext::GenerateModule() {
|
|||
0);
|
||||
cu_ = (MDNode*)di_builder_->getCU();
|
||||
|
||||
// Add import thunks/etc.
|
||||
AddImports();
|
||||
|
||||
// Add export wrappers.
|
||||
//
|
||||
|
||||
|
@ -87,13 +84,24 @@ int CodegenContext::GenerateModule() {
|
|||
if (!sdb_->GetAllFunctions(functions)) {
|
||||
for (std::vector<FunctionSymbol*>::iterator it = functions.begin();
|
||||
it != functions.end(); ++it) {
|
||||
// kernel functions will be handled by the add imports handlers.
|
||||
if ((*it)->type == FunctionSymbol::User) {
|
||||
PrepareFunction(*it);
|
||||
FunctionSymbol* fn = *it;
|
||||
switch (fn->type) {
|
||||
case FunctionSymbol::User:
|
||||
PrepareFunction(fn);
|
||||
break;
|
||||
case FunctionSymbol::Kernel:
|
||||
if (fn->kernel_export && fn->kernel_export->IsImplemented()) {
|
||||
AddPresentImport(fn);
|
||||
} else {
|
||||
AddMissingImport(fn);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::map<FunctionSymbol*, CodegenFunction*>::iterator it =
|
||||
for (std::map<uint32_t, CodegenFunction*>::iterator it =
|
||||
functions_.begin(); it != functions_.end(); ++it) {
|
||||
BuildFunction(it->second);
|
||||
}
|
||||
|
@ -103,90 +111,54 @@ int CodegenContext::GenerateModule() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CodegenContext::AddImports() {
|
||||
xe_xex2_ref xex = module_->xex();
|
||||
const xe_xex2_header_t* header = xe_xex2_get_header(xex);
|
||||
|
||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||
const xe_xex2_import_library_t* library = &header->import_libraries[n];
|
||||
|
||||
xe_xex2_import_info_t* import_infos;
|
||||
size_t import_info_count;
|
||||
XEIGNORE(xe_xex2_get_import_infos(xex, library,
|
||||
&import_infos, &import_info_count));
|
||||
|
||||
for (size_t i = 0; i < import_info_count; i++) {
|
||||
const xe_xex2_import_info_t* info = &import_infos[i];
|
||||
KernelExport* kernel_export = export_resolver_->GetExportByOrdinal(
|
||||
library->name, info->ordinal);
|
||||
if (!kernel_export || !kernel_export->IsImplemented()) {
|
||||
// Not implemented or known.
|
||||
AddMissingImport(library, info, kernel_export);
|
||||
} else {
|
||||
// Implemented.
|
||||
AddPresentImport(library, info, kernel_export);
|
||||
}
|
||||
}
|
||||
|
||||
xe_free(import_infos);
|
||||
CodegenFunction* CodegenContext::GetCodegenFunction(uint32_t address) {
|
||||
std::map<uint32_t, CodegenFunction*>::iterator it = functions_.find(address);
|
||||
if (it != functions_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
xe_xex2_release(xex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CodegenContext::AddMissingImport(
|
||||
const xe_xex2_import_library_t* library,
|
||||
const xe_xex2_import_info_t* info, KernelExport* kernel_export) {
|
||||
void CodegenContext::AddMissingImport(FunctionSymbol* fn) {
|
||||
Module* m = gen_module_;
|
||||
LLVMContext& context = m->getContext();
|
||||
|
||||
char name[128];
|
||||
xesnprintfa(name, XECOUNT(name), "__thunk_%s_%.8X",
|
||||
library->name, kernel_export->ordinal);
|
||||
AttributeWithIndex awi[] = {
|
||||
//AttributeWithIndex::get(context, 2, Attributes::NoCapture),
|
||||
AttributeWithIndex::get(context,
|
||||
AttributeSet::FunctionIndex, Attribute::NoUnwind),
|
||||
};
|
||||
AttributeSet attrs = AttributeSet::get(context, awi);
|
||||
|
||||
// TODO(benvanik): add name as comment/alias?
|
||||
// name = kernel_export->name;
|
||||
std::vector<Type*> args;
|
||||
Type* return_type = Type::getInt32Ty(context);
|
||||
|
||||
if (info->thunk_address) {
|
||||
AttributeWithIndex awi[] = {
|
||||
//AttributeWithIndex::get(context, 2, Attributes::NoCapture),
|
||||
AttributeWithIndex::get(context,
|
||||
AttributeSet::FunctionIndex, Attribute::NoUnwind),
|
||||
};
|
||||
AttributeSet attrs = AttributeSet::get(context, awi);
|
||||
FunctionType* ft = FunctionType::get(return_type,
|
||||
ArrayRef<Type*>(args), false);
|
||||
Function* f = cast<Function>(m->getOrInsertFunction(
|
||||
StringRef(fn->name), ft, attrs));
|
||||
f->setCallingConv(CallingConv::C);
|
||||
f->setVisibility(GlobalValue::DefaultVisibility);
|
||||
|
||||
std::vector<Type*> args;
|
||||
Type* return_type = Type::getInt32Ty(context);
|
||||
// TODO(benvanik): log errors.
|
||||
BasicBlock* block = BasicBlock::Create(context, "entry", f);
|
||||
IRBuilder<> builder(block);
|
||||
Value* tmp = builder.getInt32(0);
|
||||
builder.CreateRet(tmp);
|
||||
|
||||
FunctionType* ft = FunctionType::get(return_type,
|
||||
ArrayRef<Type*>(args), false);
|
||||
Function* f = cast<Function>(m->getOrInsertFunction(
|
||||
StringRef(name), ft, attrs));
|
||||
f->setCallingConv(CallingConv::C);
|
||||
f->setVisibility(GlobalValue::DefaultVisibility);
|
||||
OptimizeFunction(m, f);
|
||||
|
||||
// TODO(benvanik): log errors.
|
||||
BasicBlock* block = BasicBlock::Create(context, "entry", f);
|
||||
IRBuilder<> builder(block);
|
||||
Value* tmp = builder.getInt32(0);
|
||||
builder.CreateRet(tmp);
|
||||
|
||||
OptimizeFunction(m, f);
|
||||
|
||||
//GlobalAlias *alias = new GlobalAlias(f->getType(), GlobalValue::InternalLinkage, name, f, m);
|
||||
// printf(" F %.8X %.8X %.3X (%3d) %s %s\n",
|
||||
// info->value_address, info->thunk_address, info->ordinal,
|
||||
// info->ordinal, implemented ? " " : "!!", name);
|
||||
} else {
|
||||
// printf(" V %.8X %.3X (%3d) %s %s\n",
|
||||
// info->value_address, info->ordinal, info->ordinal,
|
||||
// implemented ? " " : "!!", name);
|
||||
}
|
||||
//GlobalAlias *alias = new GlobalAlias(f->getType(), GlobalValue::InternalLinkage, name, f, m);
|
||||
// printf(" F %.8X %.8X %.3X (%3d) %s %s\n",
|
||||
// info->value_address, info->thunk_address, info->ordinal,
|
||||
// info->ordinal, implemented ? " " : "!!", name);
|
||||
// For values:
|
||||
// printf(" V %.8X %.3X (%3d) %s %s\n",
|
||||
// info->value_address, info->ordinal, info->ordinal,
|
||||
// implemented ? " " : "!!", name);
|
||||
}
|
||||
|
||||
void CodegenContext::AddPresentImport(
|
||||
const xe_xex2_import_library_t* library,
|
||||
const xe_xex2_import_info_t* info, KernelExport* kernel_export) {
|
||||
void CodegenContext::AddPresentImport(FunctionSymbol* fn) {
|
||||
// Module *m = gen_module_;
|
||||
// LLVMContext& context = m->getContext();
|
||||
|
||||
|
@ -212,7 +184,7 @@ void CodegenContext::PrepareFunction(FunctionSymbol* fn) {
|
|||
if (fn->name) {
|
||||
pname = fn->name;
|
||||
} else {
|
||||
xesnprintfa(name, XECOUNT(name), "fn_%.8X", fn->start_address);
|
||||
xesnprintfa(name, XECOUNT(name), "sub_%.8X", fn->start_address);
|
||||
}
|
||||
|
||||
FunctionType* ft = FunctionType::get(return_type,
|
||||
|
@ -226,43 +198,21 @@ void CodegenContext::PrepareFunction(FunctionSymbol* fn) {
|
|||
cgf->symbol = fn;
|
||||
cgf->function_type = ft;
|
||||
cgf->function = f;
|
||||
functions_.insert(std::pair<FunctionSymbol*, CodegenFunction*>(fn, cgf));
|
||||
functions_.insert(std::pair<uint32_t, CodegenFunction*>(
|
||||
fn->start_address, cgf));
|
||||
}
|
||||
|
||||
void CodegenContext::BuildFunction(CodegenFunction* cgf) {
|
||||
FunctionSymbol* fn = cgf->symbol;
|
||||
|
||||
printf("%s:\n", fn->name);
|
||||
|
||||
// Setup the generation context.
|
||||
InstrContext ic(fn, context_, gen_module_, cgf->function);
|
||||
// for each basic block:
|
||||
// - ic.AddBasicBlock(bb);
|
||||
InstrContext ic(memory_, fn, context_, gen_module_, cgf->function);
|
||||
|
||||
// Run through and generate each basic block.
|
||||
ic.GenerateBasicBlocks();
|
||||
|
||||
// // TODO(benvanik): generate code!
|
||||
// BasicBlock* block = BasicBlock::Create(*context_, "entry", cgf->function);
|
||||
// IRBuilder<> builder(block);
|
||||
// //builder.SetCurrentDebugLocation(DebugLoc::get(fn->start_address >> 8, fn->start_address & 0xFF, ctx->cu));
|
||||
// Value* tmp = builder.getInt32(0);
|
||||
// builder.CreateRet(tmp);
|
||||
|
||||
// // i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
|
||||
|
||||
uint8_t* mem = xe_memory_addr(memory_, 0);
|
||||
uint32_t* pc = (uint32_t*)(mem + fn->start_address);
|
||||
uint32_t pcdata = XEGETUINT32BE(pc);
|
||||
printf("data %.8X %.8X\n", fn->start_address, pcdata);
|
||||
InstrType* instr_type = ppc::GetInstrType(pcdata);
|
||||
if (instr_type) {
|
||||
printf("instr %.8X %s\n", fn->start_address, instr_type->name);
|
||||
// xe_ppc_instr_t instr;
|
||||
// instr.data.code = pcdata;
|
||||
// printf("%d %d\n", instr.data.XFX.D, instr.data.XFX.spr);
|
||||
} else {
|
||||
printf("instr not found\n");
|
||||
}
|
||||
|
||||
// Run the optimizer on the function.
|
||||
// Doing this here keeps the size of the IR small and speeds up the later
|
||||
// passes.
|
||||
|
|
|
@ -9,14 +9,23 @@
|
|||
|
||||
#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(FunctionSymbol* fn, LLVMContext* context,
|
||||
Module* gen_module, Function* gen_fn) {
|
||||
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;
|
||||
|
@ -42,15 +51,61 @@ llvm::Function* InstrContext::gen_fn() {
|
|||
return gen_fn_;
|
||||
}
|
||||
|
||||
void InstrContext::AddBasicBlock() {
|
||||
//
|
||||
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::GenerateBasicBlocks() {
|
||||
//
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,9 @@ namespace ppc {
|
|||
|
||||
class InstrContext {
|
||||
public:
|
||||
InstrContext(sdb::FunctionSymbol* fn, llvm::LLVMContext* context,
|
||||
llvm::Module* gen_module, llvm::Function* gen_fn);
|
||||
InstrContext(xe_memory_ref memory, sdb::FunctionSymbol* fn,
|
||||
llvm::LLVMContext* context, llvm::Module* gen_module,
|
||||
llvm::Function* gen_fn);
|
||||
~InstrContext();
|
||||
|
||||
sdb::FunctionSymbol* fn();
|
||||
|
@ -40,7 +41,6 @@ public:
|
|||
llvm::Module* gen_module();
|
||||
llvm::Function* gen_fn();
|
||||
|
||||
void AddBasicBlock();
|
||||
void GenerateBasicBlocks();
|
||||
llvm::BasicBlock* GetBasicBlock(uint32_t address);
|
||||
|
||||
|
@ -63,12 +63,17 @@ public:
|
|||
void write_memory(llvm::Value* addr, uint32_t size, llvm::Value* value);
|
||||
|
||||
private:
|
||||
void GenerateBasicBlock(sdb::FunctionBlock* block, llvm::BasicBlock* bb);
|
||||
|
||||
xe_memory_ref memory_;
|
||||
sdb::FunctionSymbol* fn_;
|
||||
llvm::LLVMContext* context_;
|
||||
llvm::Module* gen_module_;
|
||||
llvm::Function* gen_fn_;
|
||||
// TODO(benvanik): IRBuilder/etc
|
||||
|
||||
std::map<uint32_t, llvm::BasicBlock*> bbs_;
|
||||
|
||||
// Address of the instruction being generated.
|
||||
uint32_t cia_;
|
||||
};
|
||||
|
|
|
@ -408,6 +408,7 @@ int SymbolDatabase::AddImports(const xe_xex2_import_library_t* library) {
|
|||
FunctionSymbol* fn = GetOrInsertFunction(info->thunk_address);
|
||||
fn->end_address = fn->start_address + 16 - 4;
|
||||
fn->type = FunctionSymbol::Kernel;
|
||||
fn->kernel_export = kernel_export;
|
||||
if (kernel_export) {
|
||||
xesnprintfa(name, XECOUNT(name), "%s", kernel_export->name);
|
||||
} else {
|
||||
|
@ -526,6 +527,7 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
|||
}
|
||||
|
||||
bool ends_block = false;
|
||||
bool ends_fn = false;
|
||||
if (i.code == 0x4E800020) {
|
||||
// blr -- unconditional branch to LR.
|
||||
// This is generally a return.
|
||||
|
@ -536,7 +538,7 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
|||
} else {
|
||||
// Function end point.
|
||||
XELOGSDB("function end %.8X\n", addr);
|
||||
break;
|
||||
ends_fn = true;
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x48000000) {
|
||||
|
@ -556,19 +558,22 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
|||
if (target >= fn->start_address &&
|
||||
target < addr && furthest_target <= addr) {
|
||||
XELOGSDB("function end %.8X (back b)\n", addr);
|
||||
break;
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
// If the target is a __restgprlr_* method it's the end of a function.
|
||||
// Note that sometimes functions stick this in a basic block *inside*
|
||||
// of the function somewhere, so ensure we don't have any branches over
|
||||
// it.
|
||||
if (furthest_target <= addr && IsRestGprLr(target)) {
|
||||
if (!ends_fn &&
|
||||
furthest_target <= addr && IsRestGprLr(target)) {
|
||||
XELOGSDB("function end %.8X (__restgprlr_*)\n", addr);
|
||||
break;
|
||||
ends_fn = true;
|
||||
}
|
||||
|
||||
furthest_target = MAX(furthest_target, target);
|
||||
if (!ends_fn) {
|
||||
furthest_target = MAX(furthest_target, target);
|
||||
}
|
||||
}
|
||||
ends_block = true;
|
||||
} else if (i.type->opcode == 0x40000000) {
|
||||
|
@ -609,6 +614,10 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
|||
block = NULL;
|
||||
}
|
||||
|
||||
if (ends_fn) {
|
||||
break;
|
||||
}
|
||||
|
||||
addr += 4;
|
||||
if (fn->end_address && addr > fn->end_address) {
|
||||
// Hmm....
|
||||
|
|
Loading…
Reference in New Issue