From 099e37490a1b504f584983b9aa002e9709b7e43d Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sun, 13 Jan 2013 15:48:18 -0800 Subject: [PATCH] Work on CPU, codegen skeleton, and thunk. --- include/xenia/cpu.h | 4 +- src/cpu/codegen.cc | 194 ++++++++++++++++++++++++++++ src/cpu/codegen.h | 31 +++++ src/cpu/cpu.cc | 251 ++++++++++++++++++++++++++++++------- src/cpu/sources.gypi | 1 + src/cpu/xethunk/xethunk.bc | Bin 0 -> 736 bytes src/cpu/xethunk/xethunk.c | 39 ++++++ src/cpu/xethunk/xethunk.h | 27 ++++ src/cpu/xethunk/xethunk.ll | 21 ++++ src/kernel/kernel.cc | 3 +- xenia-build.py | 28 +++++ xenia.gyp | 4 +- 12 files changed, 557 insertions(+), 46 deletions(-) create mode 100644 src/cpu/codegen.cc create mode 100644 src/cpu/codegen.h create mode 100644 src/cpu/xethunk/xethunk.bc create mode 100644 src/cpu/xethunk/xethunk.c create mode 100644 src/cpu/xethunk/xethunk.h create mode 100644 src/cpu/xethunk/xethunk.ll diff --git a/include/xenia/cpu.h b/include/xenia/cpu.h index 6cbef37a8..72f598dcc 100644 --- a/include/xenia/cpu.h +++ b/include/xenia/cpu.h @@ -13,6 +13,7 @@ #include #include +#include #include @@ -33,7 +34,8 @@ void xe_cpu_release(xe_cpu_ref cpu); xe_pal_ref xe_cpu_get_pal(xe_cpu_ref cpu); xe_memory_ref xe_cpu_get_memory(xe_cpu_ref cpu); -int xe_cpu_prepare_module(xe_cpu_ref cpu, xe_module_ref module); +int xe_cpu_prepare_module(xe_cpu_ref cpu, xe_module_ref module, + xe_kernel_export_resolver_ref export_resolver); int xe_cpu_execute(xe_cpu_ref cpu, uint32_t address); diff --git a/src/cpu/codegen.cc b/src/cpu/codegen.cc new file mode 100644 index 000000000..b7f69b69a --- /dev/null +++ b/src/cpu/codegen.cc @@ -0,0 +1,194 @@ +/** + ****************************************************************************** + * 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/codegen.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + + +void xe_cpu_codegen_add_imports(xe_memory_ref memory, + xe_kernel_export_resolver_ref export_resolver, + xe_module_ref module, Module *m); +void xe_cpu_codegen_add_missing_import( + Module *m, const xe_xex2_import_library_t *library, + const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export); +void xe_cpu_codegen_add_import( + Module *m, const xe_xex2_import_library_t *library, + const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export); +void xe_cpu_codegen_optimize(Module *m, Function *fn); + + +llvm::Module *xe_cpu_codegen(llvm::LLVMContext& context, xe_memory_ref memory, + xe_kernel_export_resolver_ref export_resolver, + xe_module_ref module, Module *shared_module, + xe_codegen_options_t options) { + std::string error_message; + + // Initialize the module. + Module *m = new Module("generated.xex", context); + // TODO(benavnik): addModuleFlag? + + // Link shared module into generated module. + // This gives us a single module that we can optimize and prevents the need + // for foreward declarations. + Linker::LinkModules(m, shared_module, 0, &error_message); + + // Add import thunks/etc. + xe_cpu_codegen_add_imports(memory, export_resolver, module, m); + + // Add export wrappers. + // + + Constant* c = m->getOrInsertFunction("mul_add", + /*ret type*/ IntegerType::get(context, 32), + /*args*/ IntegerType::get(context, 32), + IntegerType::get(context, 32), + IntegerType::get(context, 32), + /*varargs terminated with null*/ NULL); + + Function* mul_add = cast(c); + mul_add->setCallingConv(CallingConv::C); + + Function::arg_iterator args = mul_add->arg_begin(); + Value* x = args++; + x->setName("x"); + Value* y = args++; + y->setName("y"); + Value* z = args++; + z->setName("z"); + + BasicBlock* block = BasicBlock::Create(getGlobalContext(), "entry", mul_add); + IRBuilder<> builder(block); + + Value* tmp = builder.CreateBinOp(Instruction::Mul, + x, y, "tmp"); + Value* tmp2 = builder.CreateBinOp(Instruction::Add, + tmp, z, "tmp2"); + + builder.CreateRet(tmp2); + + // Run the optimizer on the function. + // Doing this here keeps the size of the IR small and speeds up the later + // passes. + xe_cpu_codegen_optimize(m, mul_add); + + return m; +} + +void xe_cpu_codegen_add_imports(xe_memory_ref memory, + xe_kernel_export_resolver_ref export_resolver, + xe_module_ref module, Module *m) { + xe_xex2_ref xex = xe_module_get_xex(module); + 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]; + xe_kernel_export_t *kernel_export = + xe_kernel_export_resolver_get_by_ordinal( + export_resolver, library->name, info->ordinal); + if (!kernel_export || !xe_kernel_export_is_implemented(kernel_export)) { + // Not implemented or known. + xe_cpu_codegen_add_missing_import(m, library, info, kernel_export); + } else { + // Implemented. + xe_cpu_codegen_add_import(m, library, info, kernel_export); + } + } + + xe_free(import_infos); + } + + xe_xex2_release(xex); +} + +void xe_cpu_codegen_add_missing_import( + Module *m, const xe_xex2_import_library_t *library, + const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export) { + LLVMContext& context = m->getContext(); + + char name[128]; + xesnprintfa(name, XECOUNT(name), "__%s_%.8X", + library->name, kernel_export->ordinal); + + // TODO(benvanik): add name as comment/alias? + // name = kernel_export->name; + + 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); + + std::vector args; + Type *return_type = Type::getInt32Ty(context); + + FunctionType *ft = FunctionType::get(return_type, + ArrayRef(args), false); + Function *f = cast(m->getOrInsertFunction( + StringRef(name), ft, attrs)); + f->setCallingConv(CallingConv::C); + f->setVisibility(GlobalValue::DefaultVisibility); + + BasicBlock* block = BasicBlock::Create(context, "entry", f); + IRBuilder<> builder(block); + Value *tmp = builder.getInt32(0); + builder.getInt32(123); + builder.CreateRet(tmp); + + xe_cpu_codegen_optimize(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); + } +} + +void xe_cpu_codegen_add_import( + Module *m, const xe_xex2_import_library_t *library, + const xe_xex2_import_info_t* info, xe_kernel_export_t *kernel_export) { + // +} + +void xe_cpu_codegen_optimize(Module *m, Function *fn) { + FunctionPassManager pm(m); + 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); +} diff --git a/src/cpu/codegen.h b/src/cpu/codegen.h new file mode 100644 index 000000000..38860bd4e --- /dev/null +++ b/src/cpu/codegen.h @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * 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 XENIA_CPU_CODEGEN_H_ +#define XENIA_CPU_CODEGEN_H_ + +#include +#include + +#include +#include + + +typedef struct { + int reserved; +} xe_codegen_options_t; + + +llvm::Module *xe_cpu_codegen(llvm::LLVMContext& context, xe_memory_ref memory, + xe_kernel_export_resolver_ref export_resolver, + xe_module_ref module, llvm::Module *shared_module, + xe_codegen_options_t options); + + +#endif // XENIA_CPU_CODEGEN_H_ diff --git a/src/cpu/cpu.cc b/src/cpu/cpu.cc index ae081b7e9..881898be7 100644 --- a/src/cpu/cpu.cc +++ b/src/cpu/cpu.cc @@ -9,14 +9,39 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpu/codegen.h" +#include "cpu/xethunk/xethunk.h" using namespace llvm; +typedef struct { + xe_module_ref module; + LLVMContext *context; + Module *m; +} xe_cpu_module_entry_t; + typedef struct xe_cpu { xe_ref_t ref; @@ -24,9 +49,18 @@ typedef struct xe_cpu { xe_pal_ref pal; xe_memory_ref memory; + + std::vector entries; + + ExecutionEngine *engine; } xe_cpu_t; +int xe_cpu_setup_engine(xe_cpu_ref cpu, Module *gen_module); +int xe_cpu_init_module(xe_cpu_ref, Module *gen_module); +void xe_cpu_uninit_module(xe_cpu_ref cpu, xe_cpu_module_entry_t *module_entry); + + xe_cpu_ref xe_cpu_create(xe_pal_ref pal, xe_memory_ref memory, xe_cpu_options_t options) { xe_cpu_ref cpu = (xe_cpu_ref)xe_calloc(sizeof(xe_cpu)); @@ -37,10 +71,32 @@ xe_cpu_ref xe_cpu_create(xe_pal_ref pal, xe_memory_ref memory, cpu->pal = xe_pal_retain(pal); cpu->memory = xe_memory_retain(memory); + LLVMLinkInInterpreter(); + LLVMLinkInJIT(); + InitializeNativeTarget(); + XEEXPECTTRUE(llvm_start_multithreaded()); + return cpu; + +XECLEANUP: + xe_cpu_release(cpu); + return NULL; } void xe_cpu_dealloc(xe_cpu_ref cpu) { + // Cleanup all modules. + for (std::vector::iterator it = cpu->entries.begin(); + it != cpu->entries.end(); ++it) { + xe_cpu_uninit_module(cpu, &*it); + cpu->engine->removeModule(it->m); + delete it->m; + delete it->context; + xe_module_release(it->module); + } + + delete cpu->engine; + llvm_shutdown(); + xe_memory_release(cpu->memory); xe_pal_release(cpu->pal); } @@ -62,52 +118,163 @@ xe_memory_ref xe_cpu_get_memory(xe_cpu_ref cpu) { return xe_memory_retain(cpu->memory); } -int xe_cpu_prepare_module(xe_cpu_ref cpu, xe_module_ref module) { - // TODO(benvanik): lookup the module in the cache. +int xe_cpu_setup_engine(xe_cpu_ref cpu, Module *gen_module) { + if (cpu->engine) { + // Engine already initialized - just add the module. + cpu->engine->addModule(gen_module); + return 0; + } - // TODO(benvanik): implement prepare module. + std::string error_message; + cpu->engine = ExecutionEngine::create(gen_module, false, &error_message, + CodeGenOpt::Aggressive); - XELOGCPU(XT("cpu")); - - LLVMContext &context = getGlobalContext(); - //IRBuilder<> builder(context); - Module *m = new Module("my cool jit", context); - - Constant* c = m->getOrInsertFunction("mul_add", - /*ret type*/ IntegerType::get(context, 32), - /*args*/ IntegerType::get(context, 32), - IntegerType::get(context, 32), - IntegerType::get(context, 32), - /*varargs terminated with null*/ NULL); - - Function* mul_add = cast(c); - mul_add->setCallingConv(CallingConv::C); - - Function::arg_iterator args = mul_add->arg_begin(); - Value* x = args++; - x->setName("x"); - Value* y = args++; - y->setName("y"); - Value* z = args++; - z->setName("z"); - - BasicBlock* block = BasicBlock::Create(getGlobalContext(), "entry", mul_add); - IRBuilder<> builder(block); - - Value* tmp = builder.CreateBinOp(Instruction::Mul, - x, y, "tmp"); - Value* tmp2 = builder.CreateBinOp(Instruction::Add, - tmp, z, "tmp2"); - - builder.CreateRet(tmp2); - - XELOGD(XT("woo %d"), 123); - - m->dump(); - delete m; return 0; } +int xe_cpu_prepare_module(xe_cpu_ref cpu, xe_module_ref module, + xe_kernel_export_resolver_ref export_resolver) { + int result_code = 1; + std::string error_message; + + LLVMContext *context = NULL; + OwningPtr shared_module_buffer; + Module *gen_module = NULL; + Module *shared_module = NULL; + raw_ostream *outs = NULL; + + PassManager pm; + PassManagerBuilder pmb; + + // TODO(benvanik): embed the bc file into the emulator. + const char *thunk_path = "src/cpu/xethunk/xethunk.bc"; + + // Create a LLVM context for this prepare. + // This is required to ensure thread safety/etc. + context = new LLVMContext(); + + // Calculate a cache path based on the module, the CPU version, and other + // bits. + // TODO(benvanik): cache path calculation. + const char *cache_path = "build/generated.bc"; + + // Check the cache to see if the bitcode exists. + // If it does, load that module directly. In the future we could also cache + // on linked binaries but that requires more safety around versioning. + // TODO(benvanik): check cache for module bitcode and load. + // if (path_exists(cache_key)) { + // gen_module = load_bitcode(cache_key); + // } + + // If not found in cache, generate a new module. + if (!gen_module) { + // Load shared bitcode files. + // These contain globals and common thunk code that are used by the + // generated code. + XEEXPECTZERO(MemoryBuffer::getFile(thunk_path, shared_module_buffer)); + shared_module = ParseBitcodeFile(&*shared_module_buffer, *context, + &error_message); + XEEXPECTNOTNULL(shared_module); + + // Build the module from the source code. + xe_codegen_options_t codegen_options; + xe_zero_struct(&codegen_options, sizeof(codegen_options)); + gen_module = xe_cpu_codegen(*context, cpu->memory, export_resolver, + module, shared_module, + codegen_options); + + // Write to cache. + outs = new raw_fd_ostream(cache_path, error_message, + raw_fd_ostream::F_Binary); + XEEXPECTTRUE(error_message.empty()); + WriteBitcodeToFile(gen_module, *outs); + } + + // Link optimizations. + XEEXPECTZERO(gen_module->MaterializeAllPermanently(&error_message)); + + // Reset target triple (ignore what's in xethunk). + gen_module->setTargetTriple(llvm::sys::getDefaultTargetTriple()); + + // Run full module optimizations. + pm.add(new DataLayout(gen_module)); + pm.add(createVerifierPass()); + pmb.OptLevel = 3; + pmb.SizeLevel = 0; + pmb.Inliner = createFunctionInliningPass(); + pmb.Vectorize = true; + pmb.LoopVectorize = true; + pmb.populateModulePassManager(pm); + pmb.populateLTOPassManager(pm, false, true); + pm.add(createVerifierPass()); + pm.run(*gen_module); + + // TODO(benvanik): experiment with LLD to see if we can write out a dll. + + // Setup the execution engine (if needed). + // The engine is required to get the data layout and other values. + XEEXPECTZERO(xe_cpu_setup_engine(cpu, gen_module)); + + // Initialize the module. + XEEXPECTZERO(xe_cpu_init_module(cpu, gen_module)); + + // Force JIT of all functions. + for (Module::iterator I = gen_module->begin(), E = gen_module->end(); + I != E; I++) { + Function* fn = &*I; + if (!fn->isDeclaration()) { + cpu->engine->getPointerToFunction(fn); + } + } + + gen_module->dump(); + + // Stash the module entry to allow cleanup later. + xe_cpu_module_entry_t module_entry; + module_entry.module = xe_module_retain(module); + module_entry.context = context; + module_entry.m = gen_module; + cpu->entries.push_back(module_entry); + + result_code = 0; +XECLEANUP: + delete outs; + delete shared_module; + if (result_code) { + delete gen_module; + delete context; + } + return result_code; +} + +int xe_cpu_init_module(xe_cpu_ref cpu, Module *gen_module) { + // Run static initializers. I'm not sure we'll have any, but who knows. + cpu->engine->runStaticConstructorsDestructors(gen_module, false); + + // Prepare init options. + xe_module_init_options_t init_options; + xe_zero_struct(&init_options, sizeof(init_options)); + init_options.memory_base = xe_memory_addr(cpu->memory, 0); + + // Grab the init function and call it. + Function *xe_module_init = gen_module->getFunction("xe_module_init"); + std::vector args; + args.push_back(GenericValue(&init_options)); + GenericValue ret = cpu->engine->runFunction(xe_module_init, args); + + return ret.IntVal.getSExtValue(); +} + +void xe_cpu_uninit_module(xe_cpu_ref cpu, xe_cpu_module_entry_t *module_entry) { + // Grab function and call it. + Function *xe_module_uninit = module_entry->m->getFunction("xe_module_uninit"); + std::vector args; + cpu->engine->runFunction(xe_module_uninit, args); + + // Run static destructors. + cpu->engine->runStaticConstructorsDestructors(module_entry->m, true); +} + int xe_cpu_execute(xe_cpu_ref cpu, uint32_t address) { // TODO(benvanik): implement execute. return 0; diff --git a/src/cpu/sources.gypi b/src/cpu/sources.gypi index 98d0dc414..d7ad99ec2 100644 --- a/src/cpu/sources.gypi +++ b/src/cpu/sources.gypi @@ -1,6 +1,7 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ + 'codegen.cc', 'cpu.cc', ], } diff --git a/src/cpu/xethunk/xethunk.bc b/src/cpu/xethunk/xethunk.bc new file mode 100644 index 0000000000000000000000000000000000000000..c456885d1f27e60e789b2821ed9311316b4563a7 GIT binary patch literal 736 zcmZ8fO=uHQ5S~po`?g6;-gbjcq12>lHHbpkXj!RZeyk=EwdhIkuq{En6!KGI8Vasv zwNWFi^^)TXJ>(>K@E$Ohg3yMZJV6}+|f;=!u3X{p3vc7ES{Z}!b>HU=Dk*y+*@ zE?pT-*mZxPd0TZ3`g5aXl^15}Mm@5!!yr!53&5gwXn&ASG$UvHuAc@`T4-1&e%dCC@;Fb5Dk%gP#~&7#T{eRXDN#}|2pZ_-eWVm3IfI~qZV!Uen^peHx_b}1 zvp(~>f3n53fs~N3r53k$U>x+OxQggfl2Z@m?3T-{RSug$qRdo!`LS4!Js0?jO|E(cJ)9-$Bjst$WRN+4_NA-tfKYiwx|B*CJ<|x6UWZ zDb7sMsyO`!66PAfG}hpXfyhSBm>O3Q&f)w}L0I^#(6T_HFsJWw%fX<(ET}QKt67=u WxvLp@U6WrO;h4W9vWy9FM1KKnD8CE< literal 0 HcmV?d00001 diff --git a/src/cpu/xethunk/xethunk.c b/src/cpu/xethunk/xethunk.c new file mode 100644 index 000000000..2ac6d662a --- /dev/null +++ b/src/cpu/xethunk/xethunk.c @@ -0,0 +1,39 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +/** + * This file is compiled with clang to produce LLVM bitcode. + * When the emulator goes to build a full module it then imports this code into + * the generated module to provide globals/other shared values. + * + * Changes to this file require building a new version and checking it into the + * repo on a machine that has clang. + * + * # rebuild the xethunk.bc/.ll files: + * xb xethunk + */ + +// NOTE: only headers in this directory should be included. +#include "xethunk.h" + + +// The base pointer that all guest addresses should be relative to. +static void* xe_memory_base; + + +int xe_module_init(xe_module_init_options_t *options) { + xe_memory_base = options->memory_base; + + // TODO(benvanik): setup call table, etc? + + return 0; +} + +void xe_module_uninit() { +} diff --git a/src/cpu/xethunk/xethunk.h b/src/cpu/xethunk/xethunk.h new file mode 100644 index 000000000..ad71a7270 --- /dev/null +++ b/src/cpu/xethunk/xethunk.h @@ -0,0 +1,27 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +/** + * This file is shared between xethunk and the loader to pass structures + * between the two. Since this file is compiled with the LLVM clang it cannot + * include any other files. + */ + +#ifndef XENIA_CPU_XELIB_H_ +#define XENIA_CPU_XELIB_H_ + + +typedef struct { + void* memory_base; + + // TODO(benvanik): execute call thunk +} xe_module_init_options_t; + + +#endif // XENIA_CPU_XELIB_H_ diff --git a/src/cpu/xethunk/xethunk.ll b/src/cpu/xethunk/xethunk.ll new file mode 100644 index 000000000..aacede493 --- /dev/null +++ b/src/cpu/xethunk/xethunk.ll @@ -0,0 +1,21 @@ +; ModuleID = 'src/cpu/xethunk/xethunk.bc' +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.8.0" + +%struct.xe_module_init_options_t = type { i8* } + +@xe_memory_base = internal global i8* null, align 8 + +define i32 @xe_module_init(%struct.xe_module_init_options_t* %options) nounwind uwtable ssp { + %1 = alloca %struct.xe_module_init_options_t*, align 8 + store %struct.xe_module_init_options_t* %options, %struct.xe_module_init_options_t** %1, align 8 + %2 = load %struct.xe_module_init_options_t** %1, align 8 + %3 = getelementptr inbounds %struct.xe_module_init_options_t* %2, i32 0, i32 0 + %4 = load i8** %3, align 8 + store i8* %4, i8** @xe_memory_base, align 8 + ret i32 0 +} + +define void @xe_module_uninit() nounwind uwtable ssp { + ret void +} diff --git a/src/kernel/kernel.cc b/src/kernel/kernel.cc index fd3784d61..c7d94355a 100644 --- a/src/kernel/kernel.cc +++ b/src/kernel/kernel.cc @@ -122,7 +122,8 @@ xe_module_ref xe_kernel_load_module(xe_kernel_ref kernel, } // Prepare the module. - XEEXPECTZERO(xe_cpu_prepare_module(kernel->cpu, module)); + XEEXPECTZERO(xe_cpu_prepare_module(kernel->cpu, module, + kernel->export_resolver)); // Stash in modules list (takes reference). // TODO(benvanik): stash in list. diff --git a/xenia-build.py b/xenia-build.py index 1bb733e40..f68a95a0a 100755 --- a/xenia-build.py +++ b/xenia-build.py @@ -61,6 +61,7 @@ def discover_commands(): 'pull': PullCommand(), 'gyp': GypCommand(), 'build': BuildCommand(), + 'xethunk': XethunkCommand(), 'clean': CleanCommand(), 'nuke': NukeCommand(), } @@ -379,6 +380,33 @@ class BuildCommand(Command): return 0 +class XethunkCommand(Command): + """'xethunk' command.""" + + def __init__(self, *args, **kwargs): + super(XethunkCommand, self).__init__( + name='xethunk', + help_short='Updates the xethunk.bc file.', + *args, **kwargs) + + def execute(self, args, cwd): + print 'Building xethunk...' + print '' + + path = 'src/cpu/xethunk/xethunk' + result = shell_call('clang -emit-llvm -O0 -c %s.c -o %s.bc' % (path, path), + throw_on_error=False) + if result != 0: + return result + + shell_call('build/llvm/release/bin/llvm-dis %s.bc -o %s.ll' % (path, path)) + + shell_call('cat %s.ll' % (path)) + + print 'Success!' + return 0 + + class CleanCommand(Command): """'clean' command.""" diff --git a/xenia.gyp b/xenia.gyp index 6afda4a5d..c66e8d514 100644 --- a/xenia.gyp +++ b/xenia.gyp @@ -74,7 +74,7 @@ ['_type=="executable"', { 'libraries': [ '