xenia/src/cpu/codegen/module_generator.cc

266 lines
7.8 KiB
C++
Raw Normal View History

/**
******************************************************************************
* 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/module_generator.h>
#include <llvm/DIBuilder.h>
#include <llvm/Linker.h>
#include <llvm/PassManager.h>
2013-01-19 14:26:01 +01:00
#include <llvm/DebugInfo.h>
#include <llvm/Analysis/Verifier.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 <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
#include <xenia/cpu/ppc.h>
#include <xenia/cpu/codegen/function_generator.h>
#include "cpu/cpu-private.h"
using namespace llvm;
using namespace xe;
using namespace xe::cpu;
using namespace xe::cpu::codegen;
using namespace xe::cpu::sdb;
using namespace xe::kernel;
ModuleGenerator::ModuleGenerator(
xe_memory_ref memory, ExportResolver* export_resolver,
UserModule* module, SymbolDatabase* sdb,
LLVMContext* context, Module* gen_module) {
memory_ = xe_memory_retain(memory);
export_resolver_ = export_resolver;
module_ = module;
sdb_ = sdb;
context_ = context;
gen_module_ = gen_module;
di_builder_ = NULL;
}
ModuleGenerator::~ModuleGenerator() {
for (std::map<uint32_t, CodegenFunction*>::iterator it =
functions_.begin(); it != functions_.end(); ++it) {
delete it->second;
}
delete di_builder_;
xe_memory_release(memory_);
}
int ModuleGenerator::Generate() {
std::string error_message;
2013-01-19 14:26:01 +01:00
// Setup a debug info builder.
// This is used when creating any debug info. We may want to go more
// fine grained than this, but for now it's something.
xechar_t dir[2048];
XEIGNORE(xestrcpy(dir, XECOUNT(dir), module_->path()));
xechar_t* slash = xestrrchr(dir, '/');
2013-01-19 14:26:01 +01:00
if (slash) {
*(slash + 1) = 0;
}
di_builder_ = new DIBuilder(*gen_module_);
di_builder_->createCompileUnit(
2013-01-19 14:26:01 +01:00
0,
StringRef(module_->name()),
2013-01-19 14:26:01 +01:00
StringRef(dir),
StringRef("xenia"),
true,
StringRef(""),
0);
cu_ = (MDNode*)di_builder_->getCU();
2013-01-19 14:26:01 +01:00
// Add export wrappers.
//
2013-01-19 14:26:01 +01:00
// Add all functions.
// We do two passes - the first creates the function signature and global
// value (so that we can call it), the second actually builds the function.
std::vector<FunctionSymbol*> functions;
if (!sdb_->GetAllFunctions(functions)) {
for (std::vector<FunctionSymbol*>::iterator it = functions.begin();
it != functions.end(); ++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:
XEASSERTALWAYS();
break;
}
}
}
// Build out all the user functions.
for (std::map<uint32_t, CodegenFunction*>::iterator it =
functions_.begin(); it != functions_.end(); ++it) {
BuildFunction(it->second);
}
di_builder_->finalize();
2013-01-19 14:26:01 +01:00
return 0;
}
ModuleGenerator::CodegenFunction* ModuleGenerator::GetCodegenFunction(
uint32_t address) {
std::map<uint32_t, CodegenFunction*>::iterator it = functions_.find(address);
if (it != functions_.end()) {
return it->second;
}
return NULL;
}
2013-01-24 07:38:59 +01:00
Function* ModuleGenerator::CreateFunctionDefinition(const char* name) {
Module* m = gen_module_;
LLVMContext& context = m->getContext();
std::vector<Type*> args;
args.push_back(PointerType::getUnqual(Type::getInt8Ty(context)));
args.push_back(Type::getInt64Ty(context));
2013-01-24 07:38:59 +01:00
Type* return_type = Type::getVoidTy(context);
FunctionType* ft = FunctionType::get(return_type,
ArrayRef<Type*>(args), false);
Function* f = cast<Function>(m->getOrInsertFunction(
2013-01-24 07:38:59 +01:00
StringRef(name), ft));
f->setVisibility(GlobalValue::DefaultVisibility);
2013-01-24 07:38:59 +01:00
// Indicate that the function will never be unwound with an exception.
// If we ever support native exception handling we may need to remove this.
f->doesNotThrow();
// May be worth trying the X86_FastCall, as we only need state in a register.
//f->setCallingConv(CallingConv::Fast);
f->setCallingConv(CallingConv::C);
Function::arg_iterator fn_args = f->arg_begin();
2013-01-24 07:38:59 +01:00
// 'state'
Value* fn_arg = fn_args++;
fn_arg->setName("state");
2013-01-24 07:38:59 +01:00
f->setDoesNotAlias(1);
f->setDoesNotCapture(1);
2013-01-24 07:38:59 +01:00
// 'state' should try to be in a register, if possible.
// TODO(benvanik): verify that's a good idea.
// f->getArgumentList().begin()->addAttr(
// Attribute::get(context, AttrBuilder().addAttribute(Attribute::InReg)));
// 'lr'
fn_arg = fn_args++;
fn_arg->setName("lr");
2013-01-24 07:38:59 +01:00
return f;
};
void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) {
Module *m = gen_module_;
LLVMContext& context = m->getContext();
// Create the function (and setup args/attributes/etc).
Function* f = CreateFunctionDefinition(fn->name);
// TODO(benvanik): log errors.
BasicBlock* block = BasicBlock::Create(context, "entry", f);
IRBuilder<> builder(block);
2013-01-24 09:10:24 +01:00
if (FLAGS_trace_kernel_calls) {
Value* traceKernelCall = m->getGlobalVariable("XeTraceKernelCall");
builder.CreateCall3(
traceKernelCall,
f->arg_begin(),
builder.getInt64(fn->start_address),
++f->arg_begin());
2013-01-24 09:10:24 +01:00
}
2013-01-24 07:38:59 +01:00
builder.CreateRetVoid();
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);
// For values:
// printf(" V %.8X %.3X (%3d) %s %s\n",
// info->value_address, info->ordinal, info->ordinal,
// implemented ? " " : "!!", name);
}
void ModuleGenerator::AddPresentImport(FunctionSymbol* fn) {
// Module *m = gen_module_;
// LLVMContext& context = m->getContext();
// TODO(benvanik): add import thunk code.
}
void ModuleGenerator::PrepareFunction(FunctionSymbol* fn) {
2013-01-24 07:38:59 +01:00
// Module* m = gen_module_;
// LLVMContext& context = m->getContext();
2013-01-24 07:38:59 +01:00
// Create the function (and setup args/attributes/etc).
Function* f = CreateFunctionDefinition(fn->name);
2013-01-24 07:38:59 +01:00
// Setup our codegen wrapper to keep all the pointers together.
CodegenFunction* cgf = new CodegenFunction();
cgf->symbol = fn;
2013-01-24 07:38:59 +01:00
cgf->function_type = f->getFunctionType();
cgf->function = f;
functions_.insert(std::pair<uint32_t, CodegenFunction*>(
fn->start_address, cgf));
}
void ModuleGenerator::BuildFunction(CodegenFunction* cgf) {
FunctionSymbol* fn = cgf->symbol;
printf("%s:\n", fn->name);
// Setup the generation context.
FunctionGenerator fgen(
memory_, sdb_, fn, context_, gen_module_, cgf->function);
// Run through and generate each basic block.
fgen.GenerateBasicBlocks();
// Run the optimizer on the function.
// Doing this here keeps the size of the IR small and speeds up the later
// passes.
OptimizeFunction(gen_module_, cgf->function);
}
void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) {
FunctionPassManager pm(m);
2013-01-27 06:51:31 +01:00
//fn->dump();
if (FLAGS_optimize_ir_functions) {
PassManagerBuilder pmb;
pmb.OptLevel = 3;
pmb.SizeLevel = 0;
pmb.Inliner = createFunctionInliningPass();
pmb.Vectorize = true;
pmb.LoopVectorize = true;
pmb.populateFunctionPassManager(pm);
}
pm.add(createVerifierPass());
pm.run(*fn);
}