diff --git a/docs/building.md b/docs/building.md index 95c1d40ee..208a57366 100644 --- a/docs/building.md +++ b/docs/building.md @@ -31,25 +31,19 @@ Install both and add Python to your PATH (`C:\Python27\`). Depending on your Visual Studio version you'll need to use one of the provided command prompts (until I write my own) to perform all `xenia-build` tasks. -#### Visual Studio 2010 - -The build has been most tested with 2010. -Use the `Visual Studio 2010 x64 Command Prompt` as your shell. - -* Visual Studio 2010 (not sure Express will work) - * [Visual Studio 2010 SP1](http://msdn.microsoft.com/en-us/vstudio/aa718359) -* [Windows SDK](http://www.microsoft.com/download/en/details.aspx?id=8279) -* [DirectX SDK](http://msdn.microsoft.com/en-us/directx/) - #### Visual Studio 2012 (Express) -Basic testing has been done with 2012 Express (all I have access to). Since it's -newer and shinier, I may end up deprecating the 2010 support. +Basic testing has been done with 2012 Express (all I have access to). Use the `VS2012 x64 Cross Tools Command Prompt` as your shell. * [Windows 8 SDK](http://msdn.microsoft.com/en-us/windows/desktop/aa904949.aspx) * [Visual Studio 2012 Express for Desktop](http://go.microsoft.com/?linkid=9816758) +VS2012 behaves oddly with the debug paths. Open the xenia-run project properties +and set the 'Command' to `$(ProjectDir)$(OutputPath)$(TargetFileName)` and the +'Working Directory' to `$(SolutionDir)..\..`. You can specify flags and +the file to run in the 'Command Arguments' field. + ## xenia-build A simple build script is included to manage basic tasks such as building diff --git a/src/xenia/cpu/backend.h b/src/xenia/cpu/backend.h index 0e1f28c47..51a533fe9 100644 --- a/src/xenia/cpu/backend.h +++ b/src/xenia/cpu/backend.h @@ -19,22 +19,21 @@ namespace xe { namespace cpu { -class CodeUnitBuilder; -class FunctionTable; class JIT; -class LibraryLinker; class LibraryLoader; +namespace sdb { +class SymbolTable; +} // namespace sdb + class Backend { public: virtual ~Backend() {} - virtual CodeUnitBuilder* CreateCodeUnitBuilder() = 0; - virtual LibraryLinker* CreateLibraryLinker() = 0; virtual LibraryLoader* CreateLibraryLoader() = 0; - virtual JIT* CreateJIT(xe_memory_ref memory, FunctionTable* fn_table) = 0; + virtual JIT* CreateJIT(xe_memory_ref memory, sdb::SymbolTable* sym_table) = 0; protected: Backend() {} diff --git a/src/xenia/cpu/code_unit_builder.h b/src/xenia/cpu/code_unit_builder.h deleted file mode 100644 index 61603f03c..000000000 --- a/src/xenia/cpu/code_unit_builder.h +++ /dev/null @@ -1,51 +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 XENIA_CPU_CODE_UNIT_BUILDER_H_ -#define XENIA_CPU_CODE_UNIT_BUILDER_H_ - -#include -#include - -#include -#include -#include - - -namespace xe { -namespace cpu { - - -class CodeUnitBuilder { -public: - virtual ~CodeUnitBuilder() { - xe_memory_release(memory_); - } - - virtual int Init(const char* module_name, const char* module_path) = 0; - virtual int MakeFunction(sdb::FunctionSymbol* symbol) = 0; - virtual int Finalize() = 0; - virtual void Reset() = 0; - - // TODO(benvanik): write to file/etc - -protected: - CodeUnitBuilder(xe_memory_ref memory) { - memory_ = xe_memory_retain(memory); - } - - xe_memory_ref memory_; -}; - - -} // namespace cpu -} // namespace xe - - -#endif // XENIA_CPU_CODE_UNIT_BUILDER_H_ diff --git a/src/xenia/cpu/cpu.h b/src/xenia/cpu/cpu.h index c0c3724d4..7f32bcbfa 100644 --- a/src/xenia/cpu/cpu.h +++ b/src/xenia/cpu/cpu.h @@ -13,6 +13,6 @@ #include // TODO(benvanik): conditionally include? -#include +#include #endif // XENIA_CPU_CPU_H_ diff --git a/src/xenia/cpu/exec_module.cc b/src/xenia/cpu/exec_module.cc index 5f49d6ff3..742f4b61a 100644 --- a/src/xenia/cpu/exec_module.cc +++ b/src/xenia/cpu/exec_module.cc @@ -21,11 +21,11 @@ using namespace xe::kernel; ExecModule::ExecModule( xe_memory_ref memory, shared_ptr export_resolver, - FunctionTable* fn_table, + SymbolTable* sym_table, const char* module_name, const char* module_path) { memory_ = xe_memory_retain(memory); export_resolver_ = export_resolver; - fn_table_ = fn_table; + sym_table_ = sym_table; module_name_ = xestrdupa(module_name); module_path_ = xestrdupa(module_path); } @@ -43,7 +43,7 @@ SymbolDatabase* ExecModule::sdb() { int ExecModule::PrepareRawBinary(uint32_t start_address, uint32_t end_address) { sdb_ = shared_ptr( new sdb::RawSymbolDatabase(memory_, export_resolver_.get(), - start_address, end_address)); + sym_table_, start_address, end_address)); code_addr_low_ = start_address; code_addr_high_ = end_address; @@ -53,7 +53,8 @@ int ExecModule::PrepareRawBinary(uint32_t start_address, uint32_t end_address) { int ExecModule::PrepareXexModule(xe_xex2_ref xex) { sdb_ = shared_ptr( - new sdb::XexSymbolDatabase(memory_, export_resolver_.get(), xex)); + new sdb::XexSymbolDatabase(memory_, export_resolver_.get(), + sym_table_, xex)); code_addr_low_ = 0; code_addr_high_ = 0; @@ -65,8 +66,8 @@ int ExecModule::PrepareXexModule(xe_xex2_ref xex) { const size_t end_address = start_address + (section->info.page_count * xe_xex2_section_length); if (section->info.type == XEX_SECTION_CODE) { - code_addr_low_ = MIN(code_addr_low_, start_address); - code_addr_high_ = MAX(code_addr_high_, end_address); + code_addr_low_ = (uint32_t)MIN(code_addr_low_, start_address); + code_addr_high_ = (uint32_t)MAX(code_addr_high_, end_address); } i += section->info.page_count; } diff --git a/src/xenia/cpu/exec_module.h b/src/xenia/cpu/exec_module.h index 509da2374..18f01a122 100644 --- a/src/xenia/cpu/exec_module.h +++ b/src/xenia/cpu/exec_module.h @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -27,7 +26,7 @@ class ExecModule { public: ExecModule( xe_memory_ref memory, shared_ptr export_resolver, - FunctionTable* fn_table, + sdb::SymbolTable* sym_table, const char* module_name, const char* module_path); ~ExecModule(); @@ -46,7 +45,7 @@ private: xe_memory_ref memory_; shared_ptr export_resolver_; - FunctionTable* fn_table_; + sdb::SymbolTable* sym_table_; char* module_name_; char* module_path_; diff --git a/src/xenia/cpu/global_exports.cc b/src/xenia/cpu/global_exports.cc index cb49b088c..dc9e64d77 100644 --- a/src/xenia/cpu/global_exports.cc +++ b/src/xenia/cpu/global_exports.cc @@ -24,18 +24,24 @@ using namespace xe::kernel; namespace { -void XeTrap(xe_ppc_state_t* state, uint32_t cia) { +void _cdecl XeTrap( + xe_ppc_state_t* state, uint64_t cia, uint64_t unused1, + void* unused2) { XELOGE("TRAP"); XEASSERTALWAYS(); } -void XeIndirectBranch(xe_ppc_state_t* state, uint64_t target, uint64_t br_ia) { +void _cdecl XeIndirectBranch( + xe_ppc_state_t* state, uint64_t target, uint64_t br_ia, + void* unused) { XELOGCPU("INDIRECT BRANCH %.8X -> %.8X", (uint32_t)br_ia, (uint32_t)target); XEASSERTALWAYS(); } -void XeInvalidInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { +void _cdecl XeInvalidInstruction( + xe_ppc_state_t* state, uint64_t cia, uint64_t data, + void* unused) { ppc::InstrData i; i.address = cia; i.code = data; @@ -57,26 +63,32 @@ void XeInvalidInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { } } -void XeAccessViolation(xe_ppc_state_t* state, uint32_t cia, uint64_t ea) { +void _cdecl XeAccessViolation( + xe_ppc_state_t* state, uint64_t cia, uint64_t ea, + void* unused) { XELOGE("INVALID ACCESS %.8X: tried to touch %.8X", cia, (uint32_t)ea); XEASSERTALWAYS(); } -void XeTraceKernelCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, - KernelExport* kernel_export) { +void _cdecl XeTraceKernelCall( + xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, + KernelExport* kernel_export) { XELOGCPU("TRACE: %.8X -> k.%.8X (%s)", (uint32_t)call_ia - 4, (uint32_t)cia, kernel_export ? kernel_export->name : "unknown"); } -void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, - FunctionSymbol* fn) { +void _cdecl XeTraceUserCall( + xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, + FunctionSymbol* fn) { XELOGCPU("TRACE: %.8X -> u.%.8X (%s)", (uint32_t)call_ia - 4, (uint32_t)cia, fn->name()); } -void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { +void _cdecl XeTraceInstruction( + xe_ppc_state_t* state, uint64_t cia, uint64_t data, + void* unused) { ppc::InstrType* type = ppc::GetInstrType(data); XELOGCPU("TRACE: %.8X %.8X %s %s", cia, data, diff --git a/src/xenia/cpu/global_exports.h b/src/xenia/cpu/global_exports.h index a8f19c05e..0c8df49df 100644 --- a/src/xenia/cpu/global_exports.h +++ b/src/xenia/cpu/global_exports.h @@ -23,22 +23,22 @@ namespace cpu { typedef struct { - void (*XeTrap)( - xe_ppc_state_t* state, uint32_t cia); - void (*XeIndirectBranch)( - xe_ppc_state_t* state, uint64_t target, uint64_t br_ia); - void (*XeInvalidInstruction)( - xe_ppc_state_t* state, uint32_t cia, uint32_t data); - void (*XeAccessViolation)( - xe_ppc_state_t* state, uint32_t cia, uint64_t ea); - void (*XeTraceKernelCall)( + void (_cdecl *XeTrap)( + xe_ppc_state_t* state, uint64_t cia, uint64_t unused1, void* unused2); + void (_cdecl *XeIndirectBranch)( + xe_ppc_state_t* state, uint64_t target, uint64_t br_ia, void* unused); + void (_cdecl *XeInvalidInstruction)( + xe_ppc_state_t* state, uint64_t cia, uint64_t data, void* unused); + void (_cdecl *XeAccessViolation)( + xe_ppc_state_t* state, uint64_t cia, uint64_t ea, void* unused); + void (_cdecl *XeTraceKernelCall)( xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, kernel::KernelExport* kernel_export); - void (*XeTraceUserCall)( + void (_cdecl *XeTraceUserCall)( xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, sdb::FunctionSymbol* fn); - void (*XeTraceInstruction)( - xe_ppc_state_t* state, uint32_t cia, uint32_t data); + void (_cdecl *XeTraceInstruction)( + xe_ppc_state_t* state, uint64_t cia, uint64_t data, void* unused); } GlobalExports; diff --git a/src/xenia/cpu/jit.h b/src/xenia/cpu/jit.h index 2102210d9..b9dfbde5c 100644 --- a/src/xenia/cpu/jit.h +++ b/src/xenia/cpu/jit.h @@ -12,7 +12,6 @@ #include -#include #include #include @@ -35,16 +34,17 @@ public: virtual int InitModule(ExecModule* module) = 0; virtual int UninitModule(ExecModule* module) = 0; - virtual FunctionPointer GenerateFunction(sdb::FunctionSymbol* symbol) = 0; + virtual int Execute(xe_ppc_state_t* ppc_state, + sdb::FunctionSymbol* fn_symbol) = 0; protected: - JIT(xe_memory_ref memory, FunctionTable* fn_table) { + JIT(xe_memory_ref memory, sdb::SymbolTable* sym_table) { memory_ = xe_memory_retain(memory); - fn_table_ = fn_table; + sym_table_ = sym_table; } - xe_memory_ref memory_; - FunctionTable* fn_table_; + xe_memory_ref memory_; + sdb::SymbolTable* sym_table_; }; diff --git a/src/xenia/cpu/libjit/libjit_backend.cc b/src/xenia/cpu/libjit/libjit_backend.cc new file mode 100644 index 000000000..b1fe7415f --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_backend.cc @@ -0,0 +1,61 @@ +/** + ****************************************************************************** + * 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 + +#include +#include +#include + + +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::libjit; +using namespace xe::cpu::sdb; + + +namespace { + void InitializeIfNeeded(); + void CleanupOnShutdown(); + + void InitializeIfNeeded() { + static bool has_initialized = false; + if (has_initialized) { + return; + } + has_initialized = true; + + libjit::LibjitRegisterEmitCategoryALU(); + libjit::LibjitRegisterEmitCategoryControl(); + libjit::LibjitRegisterEmitCategoryFPU(); + libjit::LibjitRegisterEmitCategoryMemory(); + + atexit(CleanupOnShutdown); + } + + void CleanupOnShutdown() { + } +} + + +LibjitBackend::LibjitBackend() : + Backend() { + InitializeIfNeeded(); +} + +LibjitBackend::~LibjitBackend() { +} + +LibraryLoader* LibjitBackend::CreateLibraryLoader() { + return NULL; +} + +JIT* LibjitBackend::CreateJIT(xe_memory_ref memory, SymbolTable* sym_table) { + return new LibjitJIT(memory, sym_table); +} diff --git a/src/xenia/cpu/libjit/libjit_backend.h b/src/xenia/cpu/libjit/libjit_backend.h new file mode 100644 index 000000000..bd8f0f6fc --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_backend.h @@ -0,0 +1,41 @@ +/** + ****************************************************************************** + * 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_LIBJIT_LIBJIT_BACKEND_H_ +#define XENIA_CPU_LIBJIT_LIBJIT_BACKEND_H_ + +#include + +#include + + +namespace xe { +namespace cpu { +namespace libjit { + + +class LibjitBackend : public Backend { +public: + LibjitBackend(); + virtual ~LibjitBackend(); + + virtual LibraryLoader* CreateLibraryLoader(); + + virtual JIT* CreateJIT(xe_memory_ref memory, sdb::SymbolTable* sym_table); + +protected: +}; + + +} // namespace libjit +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LIBJIT_LIBJIT_BACKEND_H_ diff --git a/src/xenia/cpu/libjit/libjit_emit.h b/src/xenia/cpu/libjit/libjit_emit.h new file mode 100644 index 000000000..db4275e63 --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_emit.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * 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_LIBJIT_LIBJIT_EMIT_H_ +#define XENIA_CPU_LIBJIT_LIBJIT_EMIT_H_ + +#include +#include +#include + + +namespace xe { +namespace cpu { +namespace libjit { + + +void LibjitRegisterEmitCategoryALU(); +void LibjitRegisterEmitCategoryControl(); +void LibjitRegisterEmitCategoryFPU(); +void LibjitRegisterEmitCategoryMemory(); + + +#define XEEMITTER(name, opcode, format) int InstrEmit_##name + +#define XEREGISTERINSTR(name, opcode) \ + RegisterInstrEmit(opcode, (InstrEmitFn)InstrEmit_##name); + +#define XEINSTRNOTIMPLEMENTED() +//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS + + +} // namespace libjit +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LIBJIT_LIBJIT_EMIT_H_ diff --git a/src/xenia/cpu/libjit/libjit_emit_alu.cc b/src/xenia/cpu/libjit/libjit_emit_alu.cc new file mode 100644 index 000000000..0fa244ca0 --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_emit_alu.cc @@ -0,0 +1,1081 @@ +/* + ****************************************************************************** + * 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 + + +using namespace xe::cpu; +using namespace xe::cpu::ppc; + + +namespace xe { +namespace cpu { +namespace libjit { + + +// Integer arithmetic (A-3) + +XEEMITTER(addx, 0x7C000214, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + // RD <- (RA) + (RB) + +// if (i.XO.OE) { +// // With XER update. +// // This is a different codepath as we need to use llvm.sadd.with.overflow. +// +// Function* sadd_with_overflow = Intrinsic::getDeclaration( +// e.gen_module(), Intrinsic::sadd_with_overflow, b.getInt64Ty()); +// Value* v = b.CreateCall2(sadd_with_overflow, +// e.gpr_value(i.XO.RA), e.gpr_value(i.XO.RB)); +// Value* v0 = b.CreateExtractValue(v, 0); +// e.update_gpr_value(i.XO.RT, v0); +// e.update_xer_with_overflow(b.CreateExtractValue(v, 1)); +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v0, b.getInt64(0), true); +// } +// +// return 0; +// } else { +// // No OE bit setting. +// Value* v = b.CreateAdd(e.gpr_value(i.XO.RA), e.gpr_value(i.XO.RB)); +// e.update_gpr_value(i.XO.RT, v); +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +// } + return 0; +} + +//XEEMITTER(addcx, 0x7C000014, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(addex, 0x7C000114, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(addi, 0x38000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // RT <- EXTS(SI) +// // else +// // RT <- (RA) + EXTS(SI) +// +// Value* v = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// v = b.CreateAdd(e.gpr_value(i.D.RA), v); +// } +// e.update_gpr_value(i.D.RT, v); +// +// return 0; +//} +// +//XEEMITTER(addic, 0x30000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RT <- (RA) + EXTS(SI) +// +// Function* sadd_with_overflow = Intrinsic::getDeclaration( +// e.gen_module(), Intrinsic::sadd_with_overflow, b.getInt64Ty()); +// Value* v = b.CreateCall2(sadd_with_overflow, +// e.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); +// e.update_gpr_value(i.D.RT, b.CreateExtractValue(v, 0)); +// e.update_xer_with_carry(b.CreateExtractValue(v, 1)); +// +// return 0; +//} +// +//XEEMITTER(addicx, 0x34000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(addis, 0x3C000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // RT <- EXTS(SI) || i16.0 +// // else +// // RT <- (RA) + EXTS(SI) || i16.0 +// +// Value* v = b.getInt64(XEEXTS16(i.D.DS) << 16); +// if (i.D.RA) { +// v = b.CreateAdd(e.gpr_value(i.D.RA), v); +// } +// e.update_gpr_value(i.D.RT, v); +// +// return 0; +//} +// +//XEEMITTER(addmex, 0x7C0001D4, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(addzex, 0x7C000194, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RT <- (RA) + CA +// +// Function* sadd_with_overflow = Intrinsic::getDeclaration( +// e.gen_module(), Intrinsic::sadd_with_overflow, b.getInt64Ty()); +// Value* ca = b.CreateAnd(b.CreateLShr(e.xer_value(), 29), 0x1); +// Value* v = b.CreateCall2(sadd_with_overflow, +// e.gpr_value(i.XO.RA), ca); +// Value* add_value = b.CreateExtractValue(v, 0); +// e.update_gpr_value(i.XO.RT, add_value); +// if (i.XO.OE) { +// // With XER[SO] update too. +// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); +// } else { +// // Just CA update. +// e.update_xer_with_carry(b.CreateExtractValue(v, 1)); +// } +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, add_value, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(divdx, 0x7C0003D2, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(divdux, 0x7C000392, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(divwx, 0x7C0003D6, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // dividend[0:31] <- (RA)[32:63] +// // divisor[0:31] <- (RB)[32:63] +// // if divisor = 0 then +// // if OE = 1 then +// // XER[OV] <- 1 +// // return +// // RT[32:63] <- dividend ÷ divisor +// // RT[0:31] <- undefined +// +// Value* dividend = b.CreateTrunc(e.gpr_value(i.XO.RA), b.getInt32Ty()); +// Value* divisor = b.CreateTrunc(e.gpr_value(i.XO.RB), b.getInt32Ty()); +// +// // Note that we skip the zero handling block and just avoid the divide if +// // we are OE=0. +// BasicBlock* zero_bb = i.XO.OE ? +// BasicBlock::Create(*e.context(), "", e.gen_fn()) : NULL; +// BasicBlock* nonzero_bb = BasicBlock::Create(*e.context(), "", e.gen_fn()); +// BasicBlock* after_bb = BasicBlock::Create(*e.context(), "", e.gen_fn()); +// b.CreateCondBr(b.CreateICmpEQ(divisor, b.getInt32(0)), +// i.XO.OE ? zero_bb : after_bb, nonzero_bb); +// +// if (zero_bb) { +// // Divisor was zero - do XER update. +// b.SetInsertPoint(zero_bb); +// e.update_xer_with_overflow(b.getInt1(1)); +// b.CreateBr(after_bb); +// } +// +// // Divide. +// b.SetInsertPoint(nonzero_bb); +// Value* v = b.CreateSDiv(dividend, divisor); +// v = b.CreateSExt(v, b.getInt64Ty()); +// e.update_gpr_value(i.XO.RT, v); +// +// // If we are OE=1 we need to clear the overflow bit. +// if (i.XO.OE) { +// e.update_xer_with_overflow(b.getInt1(0)); +// } +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// b.CreateBr(after_bb); +// +// // Resume. +// b.SetInsertPoint(after_bb); +// +// return 0; +//} +// +//XEEMITTER(divwux, 0x7C000396, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // dividend[0:31] <- (RA)[32:63] +// // divisor[0:31] <- (RB)[32:63] +// // if divisor = 0 then +// // if OE = 1 then +// // XER[OV] <- 1 +// // return +// // RT[32:63] <- dividend ÷ divisor +// // RT[0:31] <- undefined +// +// Value* dividend = b.CreateTrunc(e.gpr_value(i.XO.RA), b.getInt32Ty()); +// Value* divisor = b.CreateTrunc(e.gpr_value(i.XO.RB), b.getInt32Ty()); +// +// // Note that we skip the zero handling block and just avoid the divide if +// // we are OE=0. +// BasicBlock* zero_bb = i.XO.OE ? +// BasicBlock::Create(*e.context(), "", e.gen_fn()) : NULL; +// BasicBlock* nonzero_bb = BasicBlock::Create(*e.context(), "", e.gen_fn()); +// BasicBlock* after_bb = BasicBlock::Create(*e.context(), "", e.gen_fn()); +// b.CreateCondBr(b.CreateICmpEQ(divisor, b.getInt32(0)), +// i.XO.OE ? zero_bb : after_bb, nonzero_bb); +// +// if (zero_bb) { +// // Divisor was zero - do XER update. +// b.SetInsertPoint(zero_bb); +// e.update_xer_with_overflow(b.getInt1(1)); +// b.CreateBr(after_bb); +// } +// +// // Divide. +// b.SetInsertPoint(nonzero_bb); +// Value* v = b.CreateUDiv(dividend, divisor); +// v = b.CreateZExt(v, b.getInt64Ty()); +// e.update_gpr_value(i.XO.RT, v); +// +// // If we are OE=1 we need to clear the overflow bit. +// if (i.XO.OE) { +// e.update_xer_with_overflow(b.getInt1(0)); +// } +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// b.CreateBr(after_bb); +// +// // Resume. +// b.SetInsertPoint(after_bb); +// +// return 0; +//} +// +//XEEMITTER(mulhdx, 0x7C000092, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(mulhdux, 0x7C000012, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(mulhwx, 0x7C000096, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(mulhwux, 0x7C000016, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(mulldx, 0x7C0001D2, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(mulli, 0x1C000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // prod[0:127] <- (RA) × EXTS(SI) +// // RT <- prod[64:127] +// +// // TODO(benvanik): ensure this has the right behavior when the value +// // overflows. It should be truncating the result, but I'm not sure what LLVM +// // does. +// +// Value* v = b.CreateMul(e.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); +// e.update_gpr_value(i.D.RT, b.CreateTrunc(v, b.getInt64Ty())); +// +// return 0; +//} +// +//XEEMITTER(mullwx, 0x7C0001D6, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RT <- (RA)[32:63] × (RB)[32:63] +// +// if (i.XO.OE) { +// // With XER update. +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } +// +// Value* v = b.CreateMul(b.CreateSExt(e.gpr_value(i.XO.RA), b.getInt64Ty()), +// b.CreateSExt(e.gpr_value(i.XO.RB), b.getInt64Ty())); +// e.update_gpr_value(i.XO.RT, v); +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(negx, 0x7C0000D0, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RT <- ¬(RA) + 1 +// +// if (i.XO.OE) { +// // With XER update. +// // This is a different codepath as we need to use llvm.ssub.with.overflow. +// +// // if RA == 0x8000000000000000 then no-op and set OV=1 +// // This may just magically do that... +// +// Function* ssub_with_overflow = Intrinsic::getDeclaration( +// e.gen_module(), Intrinsic::ssub_with_overflow, b.getInt64Ty()); +// Value* v = b.CreateCall2(ssub_with_overflow, +// b.getInt64(0), e.gpr_value(i.XO.RA)); +// Value* v0 = b.CreateExtractValue(v, 0); +// e.update_gpr_value(i.XO.RT, v0); +// e.update_xer_with_overflow(b.CreateExtractValue(v, 1)); +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v0, b.getInt64(0), true); +// } +// +// return 0; +// } else { +// // No OE bit setting. +// Value* v = b.CreateSub(b.getInt64(0), e.gpr_value(i.XO.RA)); +// e.update_gpr_value(i.XO.RT, v); +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +// } +//} +// +//XEEMITTER(subfx, 0x7C000050, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RT <- ¬(RA) + (RB) + 1 +// +// if (i.XO.OE) { +// // With XER update. +// // This is a different codepath as we need to use llvm.ssub.with.overflow. +// +// Function* ssub_with_overflow = Intrinsic::getDeclaration( +// e.gen_module(), Intrinsic::ssub_with_overflow, b.getInt64Ty()); +// Value* v = b.CreateCall2(ssub_with_overflow, +// e.gpr_value(i.XO.RB), e.gpr_value(i.XO.RA)); +// Value* v0 = b.CreateExtractValue(v, 0); +// e.update_gpr_value(i.XO.RT, v0); +// e.update_xer_with_overflow(b.CreateExtractValue(v, 1)); +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v0, b.getInt64(0), true); +// } +// +// return 0; +// } else { +// // No OE bit setting. +// Value* v = b.CreateSub(e.gpr_value(i.XO.RB), e.gpr_value(i.XO.RA)); +// e.update_gpr_value(i.XO.RT, v); +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +// } +//} +// +//XEEMITTER(subfcx, 0x7C000010, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(subficx, 0x20000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RT <- ¬(RA) + EXTS(SI) + 1 +// +// Function* ssub_with_overflow = Intrinsic::getDeclaration( +// e.gen_module(), Intrinsic::ssub_with_overflow, b.getInt64Ty()); +// Value* v = b.CreateCall2(ssub_with_overflow, +// b.getInt64(XEEXTS16(i.D.DS)), e.gpr_value(i.D.RA)); +// e.update_gpr_value(i.D.RT, b.CreateExtractValue(v, 0)); +// e.update_xer_with_carry(b.CreateExtractValue(v, 1)); +// +// return 0; +//} +// +//XEEMITTER(subfex, 0x7C000110, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RT <- ¬(RA) + (RB) + CA +// +// // TODO(benvanik): possible that the add of rb+ca needs to also check for +// // overflow! +// +// Value* ca = b.CreateAnd(b.CreateLShr(e.xer_value(), 29), 0x1); +// Function* uadd_with_overflow = Intrinsic::getDeclaration( +// e.gen_module(), Intrinsic::uadd_with_overflow, b.getInt64Ty()); +// Value* v = b.CreateCall2(uadd_with_overflow, +// b.CreateNeg(e.gpr_value(i.XO.RA)), +// b.CreateAdd(e.gpr_value(i.XO.RB), ca)); +// Value* v0 = b.CreateExtractValue(v, 0); +// e.update_gpr_value(i.XO.RT, v0); +// +// if (i.XO.OE) { +// // With XER update. +// e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); +// } else { +// e.update_xer_with_carry(b.CreateExtractValue(v, 1)); +// } +// +// if (i.XO.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v0, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(subfmex, 0x7C0001D0, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(subfzex, 0x7C000190, XO )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +// +//// Integer compare (A-4) +// +//XEEMITTER(cmp, 0x7C000000, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if L = 0 then +// // a <- EXTS((RA)[32:63]) +// // b <- EXTS((RB)[32:63]) +// // else +// // a <- (RA) +// // b <- (RB) +// // if a < b then +// // c <- 0b100 +// // else if a > b then +// // c <- 0b010 +// // else +// // c <- 0b001 +// // CR[4×BF+32:4×BF+35] <- c || XER[SO] +// +// uint32_t BF = i.X.RT >> 2; +// uint32_t L = i.X.RT & 1; +// +// Value* lhs = e.gpr_value(i.X.RA); +// Value* rhs = e.gpr_value(i.X.RB); +// if (!L) { +// // 32-bit - truncate and sign extend. +// lhs = b.CreateTrunc(lhs, b.getInt32Ty()); +// lhs = b.CreateSExt(lhs, b.getInt64Ty()); +// rhs = b.CreateTrunc(rhs, b.getInt32Ty()); +// rhs = b.CreateSExt(rhs, b.getInt64Ty()); +// } +// +// e.update_cr_with_cond(BF, lhs, rhs, true); +// +// return 0; +//} +// +//XEEMITTER(cmpi, 0x2C000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if L = 0 then +// // a <- EXTS((RA)[32:63]) +// // else +// // a <- (RA) +// // if a < EXTS(SI) then +// // c <- 0b100 +// // else if a > EXTS(SI) then +// // c <- 0b010 +// // else +// // c <- 0b001 +// // CR[4×BF+32:4×BF+35] <- c || XER[SO] +// +// uint32_t BF = i.D.RT >> 2; +// uint32_t L = i.D.RT & 1; +// +// Value* lhs = e.gpr_value(i.D.RA); +// if (!L) { +// // 32-bit - truncate and sign extend. +// lhs = b.CreateTrunc(lhs, b.getInt32Ty()); +// lhs = b.CreateSExt(lhs, b.getInt64Ty()); +// } +// +// Value* rhs = b.getInt64(XEEXTS16(i.D.DS)); +// e.update_cr_with_cond(BF, lhs, rhs, true); +// +// return 0; +//} +// +//XEEMITTER(cmpl, 0x7C000040, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if L = 0 then +// // a <- i32.0 || (RA)[32:63] +// // b <- i32.0 || (RB)[32:63] +// // else +// // a <- (RA) +// // b <- (RB) +// // if a u b then +// // c <- 0b010 +// // else +// // c <- 0b001 +// // CR[4×BF+32:4×BF+35] <- c || XER[SO] +// +// uint32_t BF = i.X.RT >> 2; +// uint32_t L = i.X.RT & 1; +// +// Value* lhs = e.gpr_value(i.X.RA); +// Value* rhs = e.gpr_value(i.X.RB); +// if (!L) { +// // 32-bit - truncate and zero extend. +// lhs = b.CreateTrunc(lhs, b.getInt32Ty()); +// lhs = b.CreateZExt(lhs, b.getInt64Ty()); +// rhs = b.CreateTrunc(rhs, b.getInt32Ty()); +// rhs = b.CreateZExt(rhs, b.getInt64Ty()); +// } +// +// e.update_cr_with_cond(BF, lhs, rhs, false); +// +// return 0; +//} +// +//XEEMITTER(cmpli, 0x28000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if L = 0 then +// // a <- i32.0 || (RA)[32:63] +// // else +// // a <- (RA) +// // if a u i48.0 || SI then +// // c <- 0b010 +// // else +// // c <- 0b001 +// // CR[4×BF+32:4×BF+35] <- c || XER[SO] +// +// uint32_t BF = i.D.RT >> 2; +// uint32_t L = i.D.RT & 1; +// +// Value* lhs = e.gpr_value(i.D.RA); +// if (!L) { +// // 32-bit - truncate and zero extend. +// lhs = b.CreateTrunc(lhs, b.getInt32Ty()); +// lhs = b.CreateZExt(lhs, b.getInt64Ty()); +// } +// +// Value* rhs = b.getInt64(i.D.DS); +// e.update_cr_with_cond(BF, lhs, rhs, false); +// +// return 0; +//} +// +// +//// Integer logical (A-5) +// +//XEEMITTER(andx, 0x7C000038, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) & (RB) +// +// Value* v = b.CreateAnd(e.gpr_value(i.X.RT), e.gpr_value(i.X.RB)); +// e.update_gpr_value(i.X.RA, v); +// +// if (i.X.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(andcx, 0x7C000078, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) & ¬(RB) +// +// Value* v = b.CreateXor(e.gpr_value(i.X.RB), -1); +// v = b.CreateAnd(e.gpr_value(i.X.RT), v); +// e.update_gpr_value(i.X.RA, v); +// +// if (i.X.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(andix, 0x70000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) & (i48.0 || UI) +// +// Value* v = b.CreateAnd(e.gpr_value(i.D.RT), (uint64_t)i.D.DS); +// e.update_gpr_value(i.D.RA, v); +// +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// +// return 0; +//} +// +//XEEMITTER(andisx, 0x74000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) & (i32.0 || UI || i16.0) +// +// Value* v = b.CreateAnd(e.gpr_value(i.D.RT), ((uint64_t)i.D.DS) << 16); +// e.update_gpr_value(i.D.RA, v); +// +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// +// return 1; +//} +// +//XEEMITTER(cntlzdx, 0x7C000074, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(cntlzwx, 0x7C000034, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // n <- 32 +// // do while n < 64 +// // if (RS) = 1 then leave n +// // n <- n + 1 +// // RA <- n - 32 +// +// Value* v = e.gpr_value(i.X.RT); +// v = b.CreateTrunc(v, b.getInt32Ty()); +// +// std::vector arg_types; +// arg_types.push_back(b.getInt32Ty()); +// Function* ctlz = Intrinsic::getDeclaration( +// e.gen_fn()->getParent(), Intrinsic::ctlz, arg_types); +// Value* count = b.CreateCall2(ctlz, v, b.getInt1(1)); +// +// count = b.CreateZExt(count, b.getInt64Ty()); +// e.update_gpr_value(i.X.RA, count); +// +// if (i.X.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, count, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(eqvx, 0x7C000238, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(extsbx, 0x7C000774, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // s <- (RS)[56] +// // RA[56:63] <- (RS)[56:63] +// // RA[0:55] <- i56.s +// +// Value* v = e.gpr_value(i.X.RT); +// v = b.CreateTrunc(v, b.getInt8Ty()); +// v = b.CreateSExt(v, b.getInt64Ty()); +// e.update_gpr_value(i.X.RA, v); +// +// if (i.X.Rc) { +// // Update cr0. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(extshx, 0x7C000734, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(extswx, 0x7C0007B4, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(nandx, 0x7C0003B8, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(norx, 0x7C0000F8, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- ¬((RS) | (RB)) +// +// Value* v = b.CreateOr(e.gpr_value(i.X.RT), e.gpr_value(i.X.RB)); +// v = b.CreateXor(v, -1); +// e.update_gpr_value(i.X.RA, v); +// +// if (i.X.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(orx, 0x7C000378, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) | (RB) +// +// Value* v = b.CreateOr(e.gpr_value(i.X.RT), e.gpr_value(i.X.RB)); +// e.update_gpr_value(i.X.RA, v); +// +// if (i.X.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(orcx, 0x7C000338, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(ori, 0x60000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) | (i48.0 || UI) +// +// Value* v = b.CreateOr(e.gpr_value(i.D.RT), (uint64_t)i.D.DS); +// e.update_gpr_value(i.D.RA, v); +// +// return 0; +//} +// +//XEEMITTER(oris, 0x64000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) | (i32.0 || UI || i16.0) +// +// Value* v = b.CreateOr(e.gpr_value(i.D.RT), ((uint64_t)i.D.DS) << 16); +// e.update_gpr_value(i.D.RA, v); +// +// return 0; +//} +// +//XEEMITTER(xorx, 0x7C000278, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) XOR (RB) +// +// Value* v = b.CreateXor(e.gpr_value(i.X.RT), e.gpr_value(i.X.RB)); +// e.update_gpr_value(i.X.RA, v); +// +// if (i.X.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(xori, 0x68000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) XOR (i48.0 || UI) +// +// Value* v = b.CreateXor(e.gpr_value(i.D.RT), (uint64_t)i.D.DS); +// e.update_gpr_value(i.D.RA, v); +// +// return 0; +//} +// +//XEEMITTER(xoris, 0x6C000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // RA <- (RS) XOR (i32.0 || UI || i16.0) +// +// Value* v = b.CreateXor(e.gpr_value(i.D.RT), ((uint64_t)i.D.DS) << 16); +// e.update_gpr_value(i.D.RA, v); +// +// return 0; +//} +// +// +//// Integer rotate (A-6) +// +//XEEMITTER(rldclx, 0x78000010, MDS)(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(rldcrx, 0x78000012, MDS)(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(rldicx, 0x78000008, MD )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(rldiclx, 0x78000000, MD )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // n <- sh[5] || sh[0:4] +// // r <- ROTL64((RS), n) +// // b <- mb[5] || mb[0:4] +// // m <- MASK(b, 63) +// // RA <- r & m +// +// // uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; +// // uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; +// +// // Value* v = e.gpr_value(i.MD.RS); +// // if (sh) { +// // v = // rotate by sh +// // } +// // if (mb) { +// // v = // mask b mb->63 +// // } +// // e.update_gpr_value(i.MD.RA, v); +// +// // if (i.MD.Rc) { +// // // With cr0 update. +// // e.update_cr_with_cond(0, v, b.getInt64(0), true); +// // } +// +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(rldicrx, 0x78000004, MD )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(rldimix, 0x7800000C, MD )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(rlwimix, 0x50000000, M )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // n <- SH +// // r <- ROTL32((RS)[32:63], n) +// // m <- MASK(MB+32, ME+32) +// // RA <- r&m | (RA)&¬m +// +// // ROTL32(x, y) = rotl(i64.(x||x), y) +// Value* v = b.CreateAnd(e.gpr_value(i.M.RT), UINT32_MAX); +// v = b.CreateOr(b.CreateShl(v, 32), v); +// // (v << shift) | (v >> (32 - shift)); +// v = b.CreateOr(b.CreateShl(v, i.M.SH), b.CreateLShr(v, 32 - i.M.SH)); +// uint64_t m = XEMASK(i.M.MB + 32, i.M.ME + 32); +// v = b.CreateAnd(v, m); +// v = b.CreateOr(v, b.CreateAnd(e.gpr_value(i.M.RA), ~m)); +// e.update_gpr_value(i.M.RA, v); +// +// if (i.M.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(rlwinmx, 0x54000000, M )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // n <- SH +// // r <- ROTL32((RS)[32:63], n) +// // m <- MASK(MB+32, ME+32) +// // RA <- r & m +// +// // The compiler will generate a bunch of these for the special case of SH=0. +// // Which seems to just select some bits and set cr0 for use with a branch. +// // We can detect this and do less work. +// if (!i.M.SH) { +// Value* v = b.CreateAnd( +// b.CreateTrunc(e.gpr_value(i.M.RT), b.getInt32Ty()), +// b.getInt32((uint32_t)XEMASK(i.M.MB + 32, i.M.ME + 32))); +// v = b.CreateZExt(v, b.getInt64Ty()); +// e.update_gpr_value(i.M.RA, v); +// if (i.M.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// return 0; +// } +// +// // ROTL32(x, y) = rotl(i64.(x||x), y) +// Value* v = b.CreateAnd(e.gpr_value(i.M.RT), UINT32_MAX); +// v = b.CreateOr(b.CreateShl(v, 32), v); +// // (v << shift) | (v >> (32 - shift)); +// v = b.CreateOr(b.CreateShl(v, i.M.SH), b.CreateLShr(v, 32 - i.M.SH)); +// v = b.CreateAnd(v, XEMASK(i.M.MB + 32, i.M.ME + 32)); +// e.update_gpr_value(i.M.RA, v); +// +// if (i.M.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(rlwnmx, 0x5C000000, M )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +// +//// Integer shift (A-7) +// +//XEEMITTER(sldx, 0x7C000036, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(slwx, 0x7C000030, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // n <- (RB)[59:63] +// // r <- ROTL32((RS)[32:63], n) +// // if (RB)[58] = 0 then +// // m <- MASK(32, 63-n) +// // else +// // m <- i64.0 +// // RA <- r & m +// +// Value* v = b.CreateShl(e.gpr_value(i.X.RT), e.gpr_value(i.X.RB)); +// v = b.CreateAnd(v, UINT32_MAX); +// e.update_gpr_value(i.X.RA, v); +// +// if (i.X.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(sradx, 0x7C000634, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(sradix, 0x7C000674, XS )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(srawx, 0x7C000630, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(srawix, 0x7C000670, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // n <- SH +// // r <- ROTL32((RS)[32:63], 64-n) +// // m <- MASK(n+32, 63) +// // s <- (RS)[32] +// // RA <- r&m | (i64.s)&¬m +// // CA <- s & ((r&¬m)[32:63]≠0) +// +// Value* rs64 = e.gpr_value(i.X.RT); +// Value* rs32 = b.CreateTrunc(rs64, b.getInt32Ty()); +// +// Value* v; +// Value* ca; +// if (!i.X.RB) { +// // No shift, just a fancy sign extend and CA clearer. +// v = rs32; +// ca = b.getInt64(0); +// } else { +// v = b.CreateAShr(rs32, i.X.RB); +// +// // CA is set to 1 if the low-order 32 bits of (RS) contain a negative number +// // and any 1-bits are shifted out of position 63; otherwise CA is set to 0. +// ca = b.CreateAnd(b.CreateICmpSLT(v, b.getInt32(0)), +// b.CreateICmpSLT(rs64, b.getInt64(0))); +// } +// v = b.CreateSExt(v, b.getInt64Ty()); +// e.update_gpr_value(i.X.RA, v); +// e.update_xer_with_carry(ca); +// +// if (i.X.Rc) { +// // With cr0 update. +// e.update_cr_with_cond(0, v, b.getInt64(0), true); +// } +// +// return 0; +//} +// +//XEEMITTER(srdx, 0x7C000436, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} +// +//XEEMITTER(srwx, 0x7C000430, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +//} + + +void LibjitRegisterEmitCategoryALU() { + XEREGISTERINSTR(addx, 0x7C000214); +// XEREGISTERINSTR(addcx, 0X7C000014); +// XEREGISTERINSTR(addex, 0x7C000114); +// XEREGISTERINSTR(addi, 0x38000000); +// XEREGISTERINSTR(addic, 0x30000000); +// XEREGISTERINSTR(addicx, 0x34000000); +// XEREGISTERINSTR(addis, 0x3C000000); +// XEREGISTERINSTR(addmex, 0x7C0001D4); +// XEREGISTERINSTR(addzex, 0x7C000194); +// XEREGISTERINSTR(divdx, 0x7C0003D2); +// XEREGISTERINSTR(divdux, 0x7C000392); +// XEREGISTERINSTR(divwx, 0x7C0003D6); +// XEREGISTERINSTR(divwux, 0x7C000396); +// XEREGISTERINSTR(mulhdx, 0x7C000092); +// XEREGISTERINSTR(mulhdux, 0x7C000012); +// XEREGISTERINSTR(mulhwx, 0x7C000096); +// XEREGISTERINSTR(mulhwux, 0x7C000016); +// XEREGISTERINSTR(mulldx, 0x7C0001D2); +// XEREGISTERINSTR(mulli, 0x1C000000); +// XEREGISTERINSTR(mullwx, 0x7C0001D6); +// XEREGISTERINSTR(negx, 0x7C0000D0); +// XEREGISTERINSTR(subfx, 0x7C000050); +// XEREGISTERINSTR(subfcx, 0x7C000010); +// XEREGISTERINSTR(subficx, 0x20000000); +// XEREGISTERINSTR(subfex, 0x7C000110); +// XEREGISTERINSTR(subfmex, 0x7C0001D0); +// XEREGISTERINSTR(subfzex, 0x7C000190); +// XEREGISTERINSTR(cmp, 0x7C000000); +// XEREGISTERINSTR(cmpi, 0x2C000000); +// XEREGISTERINSTR(cmpl, 0x7C000040); +// XEREGISTERINSTR(cmpli, 0x28000000); +// XEREGISTERINSTR(andx, 0x7C000038); +// XEREGISTERINSTR(andcx, 0x7C000078); +// XEREGISTERINSTR(andix, 0x70000000); +// XEREGISTERINSTR(andisx, 0x74000000); +// XEREGISTERINSTR(cntlzdx, 0x7C000074); +// XEREGISTERINSTR(cntlzwx, 0x7C000034); +// XEREGISTERINSTR(eqvx, 0x7C000238); +// XEREGISTERINSTR(extsbx, 0x7C000774); +// XEREGISTERINSTR(extshx, 0x7C000734); +// XEREGISTERINSTR(extswx, 0x7C0007B4); +// XEREGISTERINSTR(nandx, 0x7C0003B8); +// XEREGISTERINSTR(norx, 0x7C0000F8); +// XEREGISTERINSTR(orx, 0x7C000378); +// XEREGISTERINSTR(orcx, 0x7C000338); +// XEREGISTERINSTR(ori, 0x60000000); +// XEREGISTERINSTR(oris, 0x64000000); +// XEREGISTERINSTR(xorx, 0x7C000278); +// XEREGISTERINSTR(xori, 0x68000000); +// XEREGISTERINSTR(xoris, 0x6C000000); +// XEREGISTERINSTR(rldclx, 0x78000010); +// XEREGISTERINSTR(rldcrx, 0x78000012); +// XEREGISTERINSTR(rldicx, 0x78000008); +// XEREGISTERINSTR(rldiclx, 0x78000000); +// XEREGISTERINSTR(rldicrx, 0x78000004); +// XEREGISTERINSTR(rldimix, 0x7800000C); +// XEREGISTERINSTR(rlwimix, 0x50000000); +// XEREGISTERINSTR(rlwinmx, 0x54000000); +// XEREGISTERINSTR(rlwnmx, 0x5C000000); +// XEREGISTERINSTR(sldx, 0x7C000036); +// XEREGISTERINSTR(slwx, 0x7C000030); +// XEREGISTERINSTR(sradx, 0x7C000634); +// XEREGISTERINSTR(sradix, 0x7C000674); +// XEREGISTERINSTR(srawx, 0x7C000630); +// XEREGISTERINSTR(srawix, 0x7C000670); +// XEREGISTERINSTR(srdx, 0x7C000436); +// XEREGISTERINSTR(srwx, 0x7C000430); +} + + +} // namespace libjit +} // namespace cpu +} // namespace xe diff --git a/src/xenia/cpu/libjit/libjit_emit_control.cc b/src/xenia/cpu/libjit/libjit_emit_control.cc new file mode 100644 index 000000000..33ee39579 --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_emit_control.cc @@ -0,0 +1,709 @@ +/* + ****************************************************************************** + * 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 + + +using namespace xe::cpu; +using namespace xe::cpu::ppc; +using namespace xe::cpu::sdb; + + +namespace xe { +namespace cpu { +namespace libjit { + + +// int XeEmitIndirectBranchTo( +// LibjitEmitter& e, jit_function_t f, const char* src, uint32_t cia, +// bool lk, uint32_t reg) { +// // TODO(benvanik): run a DFA pass to see if we can detect whether this is +// // a normal function return that is pulling the LR from the stack that +// // it set in the prolog. If so, we can omit the dynamic check! + +// // NOTE: we avoid spilling registers until we know that the target is not +// // a basic block within this function. + +// Value* target; +// switch (reg) { +// case kXEPPCRegLR: +// target = e.lr_value(); +// break; +// case kXEPPCRegCTR: +// target = e.ctr_value(); +// break; +// default: +// XEASSERTALWAYS(); +// return 1; +// } + +// // Dynamic test when branching to LR, which is usually used for the return. +// // We only do this if LK=0 as returns wouldn't set LR. +// // Ideally it's a return and we can just do a simple ret and be done. +// // If it's not, we fall through to the full indirection logic. +// if (!lk && reg == kXEPPCRegLR) { +// BasicBlock* next_block = e.GetNextBasicBlock(); +// BasicBlock* mismatch_bb = BasicBlock::Create(*e.context(), "lr_mismatch", +// e.gen_fn(), next_block); +// Value* lr_cmp = b.CreateICmpEQ(target, ++(e.gen_fn()->arg_begin())); +// // The return block will spill registers for us. +// b.CreateCondBr(lr_cmp, e.GetReturnBasicBlock(), mismatch_bb); +// b.SetInsertPoint(mismatch_bb); +// } + +// // Defer to the generator, which will do fancy things. +// bool likely_local = !lk && reg == kXEPPCRegCTR; +// return e.GenerateIndirectionBranch(cia, target, lk, likely_local); +// } + +// int XeEmitBranchTo( +// LibjitEmitter& e, jit_function_t f, const char* src, uint32_t cia, +// bool lk) { +// // Get the basic block and switch behavior based on outgoing type. +// FunctionBlock* fn_block = e.fn_block(); +// switch (fn_block->outgoing_type) { +// case FunctionBlock::kTargetBlock: +// { +// BasicBlock* target_bb = e.GetBasicBlock(fn_block->outgoing_address); +// XEASSERTNOTNULL(target_bb); +// b.CreateBr(target_bb); +// break; +// } +// case FunctionBlock::kTargetFunction: +// { +// // Spill all registers to memory. +// // TODO(benvanik): only spill ones used by the target function? Use +// // calling convention flags on the function to not spill temp +// // registers? +// e.SpillRegisters(); + +// XEASSERTNOTNULL(fn_block->outgoing_function); +// Function* target_fn = e.GetFunction(fn_block->outgoing_function); +// Function::arg_iterator args = e.gen_fn()->arg_begin(); +// Value* state_ptr = args; +// BasicBlock* next_bb = e.GetNextBasicBlock(); +// if (!lk || !next_bb) { +// // Tail. No need to refill the local register values, just return. +// // We optimize this by passing in the LR from our parent instead of the +// // next instruction. This allows the return from our callee to pop +// // all the way up. +// b.CreateCall2(target_fn, state_ptr, ++args); +// b.CreateRetVoid(); +// } else { +// // Will return here eventually. +// // Refill registers from state. +// b.CreateCall2(target_fn, state_ptr, b.getInt64(cia + 4)); +// e.FillRegisters(); +// b.CreateBr(next_bb); +// } +// break; +// } +// case FunctionBlock::kTargetLR: +// { +// // An indirect jump. +// printf("INDIRECT JUMP VIA LR: %.8X\n", cia); +// return XeEmitIndirectBranchTo(e, b, src, cia, lk, kXEPPCRegLR); +// } +// case FunctionBlock::kTargetCTR: +// { +// // An indirect jump. +// printf("INDIRECT JUMP VIA CTR: %.8X\n", cia); +// return XeEmitIndirectBranchTo(e, b, src, cia, lk, kXEPPCRegCTR); +// } +// default: +// case FunctionBlock::kTargetNone: +// XEASSERTALWAYS(); +// return 1; +// } +// return 0; +// } + + +// XEEMITTER(bx, 0x48000000, I )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if AA then +// // NIA <- EXTS(LI || 0b00) +// // else +// // NIA <- CIA + EXTS(LI || 0b00) +// // if LK then +// // LR <- CIA + 4 + +// uint32_t nia; +// if (i.I.AA) { +// nia = XEEXTS26(i.I.LI << 2); +// } else { +// nia = i.address + XEEXTS26(i.I.LI << 2); +// } +// if (i.I.LK) { +// e.update_lr_value(b.getInt32(i.address + 4)); +// } + +// return XeEmitBranchTo(e, b, "bx", i.address, i.I.LK); +// } + +// XEEMITTER(bcx, 0x40000000, B )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if ¬BO[2] then +// // CTR <- CTR - 1 +// // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3]) +// // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) +// // if ctr_ok & cond_ok then +// // if AA then +// // NIA <- EXTS(BD || 0b00) +// // else +// // NIA <- CIA + EXTS(BD || 0b00) +// // if LK then +// // LR <- CIA + 4 + +// // NOTE: the condition bits are reversed! +// // 01234 (docs) +// // 43210 (real) + +// // TODO(benvanik): this may be wrong and overwrite LRs when not desired! +// // The docs say always, though... +// if (i.B.LK) { +// e.update_lr_value(b.getInt32(i.address + 4)); +// } + +// Value* ctr_ok = NULL; +// if (XESELECTBITS(i.B.BO, 2, 2)) { +// // Ignore ctr. +// } else { +// // Decrement counter. +// Value* ctr = e.ctr_value(); +// ctr = b.CreateSub(ctr, b.getInt64(1)); +// e.update_ctr_value(ctr); + +// // Ctr check. +// if (XESELECTBITS(i.B.BO, 1, 1)) { +// ctr_ok = b.CreateICmpEQ(ctr, b.getInt64(0)); +// } else { +// ctr_ok = b.CreateICmpNE(ctr, b.getInt64(0)); +// } +// } + +// Value* cond_ok = NULL; +// if (XESELECTBITS(i.B.BO, 4, 4)) { +// // Ignore cond. +// } else { +// Value* cr = e.cr_value(i.B.BI >> 2); +// cr = b.CreateAnd(cr, 1 << (i.B.BI & 3)); +// if (XESELECTBITS(i.B.BO, 3, 3)) { +// cond_ok = b.CreateICmpNE(cr, b.getInt64(0)); +// } else { +// cond_ok = b.CreateICmpEQ(cr, b.getInt64(0)); +// } +// } + +// // We do a bit of optimization here to make the llvm assembly easier to read. +// Value* ok = NULL; +// if (ctr_ok && cond_ok) { +// ok = b.CreateAnd(ctr_ok, cond_ok); +// } else if (ctr_ok) { +// ok = ctr_ok; +// } else if (cond_ok) { +// ok = cond_ok; +// } + +// // Handle unconditional branches without extra fluff. +// BasicBlock* original_bb = b.GetInsertBlock(); +// if (ok) { +// char name[32]; +// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address); +// BasicBlock* next_block = e.GetNextBasicBlock(); +// BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(), +// next_block); + +// b.CreateCondBr(ok, branch_bb, next_block); +// b.SetInsertPoint(branch_bb); +// } + +// // Note that this occurs entirely within the branch true block. +// uint32_t nia; +// if (i.B.AA) { +// nia = XEEXTS26(i.B.BD << 2); +// } else { +// nia = i.address + XEEXTS26(i.B.BD << 2); +// } +// if (XeEmitBranchTo(e, b, "bcx", i.address, i.B.LK)) { +// return 1; +// } + +// b.SetInsertPoint(original_bb); + +// return 0; +// } + +// XEEMITTER(bcctrx, 0x4C000420, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) +// // if cond_ok then +// // NIA <- CTR[0:61] || 0b00 +// // if LK then +// // LR <- CIA + 4 + +// // NOTE: the condition bits are reversed! +// // 01234 (docs) +// // 43210 (real) + +// // TODO(benvanik): this may be wrong and overwrite LRs when not desired! +// // The docs say always, though... +// if (i.XL.LK) { +// e.update_lr_value(b.getInt32(i.address + 4)); +// } + +// Value* cond_ok = NULL; +// if (XESELECTBITS(i.XL.BO, 4, 4)) { +// // Ignore cond. +// } else { +// Value* cr = e.cr_value(i.XL.BI >> 2); +// cr = b.CreateAnd(cr, 1 << (i.XL.BI & 3)); +// if (XESELECTBITS(i.XL.BO, 3, 3)) { +// cond_ok = b.CreateICmpNE(cr, b.getInt64(0)); +// } else { +// cond_ok = b.CreateICmpEQ(cr, b.getInt64(0)); +// } +// } + +// // We do a bit of optimization here to make the llvm assembly easier to read. +// Value* ok = NULL; +// if (cond_ok) { +// ok = cond_ok; +// } + +// // Handle unconditional branches without extra fluff. +// BasicBlock* original_bb = b.GetInsertBlock(); +// if (ok) { +// char name[32]; +// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcctrx", i.address); +// BasicBlock* next_block = e.GetNextBasicBlock(); +// XEASSERTNOTNULL(next_block); +// BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(), +// next_block); + +// b.CreateCondBr(ok, branch_bb, next_block); +// b.SetInsertPoint(branch_bb); +// } + +// // Note that this occurs entirely within the branch true block. +// if (XeEmitBranchTo(e, b, "bcctrx", i.address, i.XL.LK)) { +// return 1; +// } + +// b.SetInsertPoint(original_bb); + +// return 0; +// } + +// XEEMITTER(bclrx, 0x4C000020, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if ¬BO[2] then +// // CTR <- CTR - 1 +// // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3] +// // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) +// // if ctr_ok & cond_ok then +// // NIA <- LR[0:61] || 0b00 +// // if LK then +// // LR <- CIA + 4 + +// // NOTE: the condition bits are reversed! +// // 01234 (docs) +// // 43210 (real) + +// // TODO(benvanik): this may be wrong and overwrite LRs when not desired! +// // The docs say always, though... +// if (i.XL.LK) { +// e.update_lr_value(b.getInt32(i.address + 4)); +// } + +// Value* ctr_ok = NULL; +// if (XESELECTBITS(i.XL.BO, 2, 2)) { +// // Ignore ctr. +// } else { +// // Decrement counter. +// Value* ctr = e.ctr_value(); +// ctr = b.CreateSub(ctr, b.getInt64(1)); + +// // Ctr check. +// if (XESELECTBITS(i.XL.BO, 1, 1)) { +// ctr_ok = b.CreateICmpEQ(ctr, b.getInt64(0)); +// } else { +// ctr_ok = b.CreateICmpNE(ctr, b.getInt64(0)); +// } +// } + +// Value* cond_ok = NULL; +// if (XESELECTBITS(i.XL.BO, 4, 4)) { +// // Ignore cond. +// } else { +// Value* cr = e.cr_value(i.XL.BI >> 2); +// cr = b.CreateAnd(cr, 1 << (i.XL.BI & 3)); +// if (XESELECTBITS(i.XL.BO, 3, 3)) { +// cond_ok = b.CreateICmpNE(cr, b.getInt64(0)); +// } else { +// cond_ok = b.CreateICmpEQ(cr, b.getInt64(0)); +// } +// } + +// // We do a bit of optimization here to make the llvm assembly easier to read. +// Value* ok = NULL; +// if (ctr_ok && cond_ok) { +// ok = b.CreateAnd(ctr_ok, cond_ok); +// } else if (ctr_ok) { +// ok = ctr_ok; +// } else if (cond_ok) { +// ok = cond_ok; +// } + +// // Handle unconditional branches without extra fluff. +// BasicBlock* original_bb = b.GetInsertBlock(); +// if (ok) { +// char name[32]; +// xesnprintfa(name, XECOUNT(name), "loc_%.8X_bclrx", i.address); +// BasicBlock* next_block = e.GetNextBasicBlock(); +// XEASSERTNOTNULL(next_block); +// BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(), +// next_block); + +// b.CreateCondBr(ok, branch_bb, next_block); +// b.SetInsertPoint(branch_bb); +// } + +// // Note that this occurs entirely within the branch true block. +// if (XeEmitBranchTo(e, b, "bclrx", i.address, i.XL.LK)) { +// return 1; +// } + +// b.SetInsertPoint(original_bb); + +// return 0; +// } + + +// // Condition register logical (A-23) + +// XEEMITTER(crand, 0x4C000202, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(crandc, 0x4C000102, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(creqv, 0x4C000242, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(crnand, 0x4C0001C2, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(crnor, 0x4C000042, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(cror, 0x4C000382, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(crorc, 0x4C000342, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(crxor, 0x4C000182, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(mcrf, 0x4C000000, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + + +// // System linkage (A-24) + +// XEEMITTER(sc, 0x44000002, SC )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + + +// // Trap (A-25) + +// int XeEmitTrap(LibjitEmitter& e, jit_function_t f, InstrData& i, +// Value* va, Value* vb, uint32_t TO) { +// // if (a < b) & TO[0] then TRAP +// // if (a > b) & TO[1] then TRAP +// // if (a = b) & TO[2] then TRAP +// // if (a u b) & TO[4] then TRAP +// // Bits swapped: +// // 01234 +// // 43210 + +// if (!TO) { +// return 0; +// } + +// BasicBlock* after_bb = BasicBlock::Create(*e.context(), "", e.gen_fn(), +// e.GetNextBasicBlock()); +// BasicBlock* trap_bb = BasicBlock::Create(*e.context(), "", e.gen_fn(), +// after_bb); + +// // Create the basic blocks (so we can chain). +// std::vector bbs; +// if (TO & (1 << 4)) { +// bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); +// } +// if (TO & (1 << 3)) { +// bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); +// } +// if (TO & (1 << 2)) { +// bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); +// } +// if (TO & (1 << 1)) { +// bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); +// } +// if (TO & (1 << 0)) { +// bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); +// } +// bbs.push_back(after_bb); + +// // Jump to the first bb. +// b.CreateBr(bbs.front()); + +// // Setup each basic block. +// std::vector::iterator it = bbs.begin(); +// if (TO & (1 << 4)) { +// // a < b +// BasicBlock* bb = *(it++); +// b.SetInsertPoint(bb); +// Value* cmp = b.CreateICmpSLT(va, vb); +// b.CreateCondBr(cmp, trap_bb, *it); +// } +// if (TO & (1 << 3)) { +// // a > b +// BasicBlock* bb = *(it++); +// b.SetInsertPoint(bb); +// Value* cmp = b.CreateICmpSGT(va, vb); +// b.CreateCondBr(cmp, trap_bb, *it); +// } +// if (TO & (1 << 2)) { +// // a = b +// BasicBlock* bb = *(it++); +// b.SetInsertPoint(bb); +// Value* cmp = b.CreateICmpEQ(va, vb); +// b.CreateCondBr(cmp, trap_bb, *it); +// } +// if (TO & (1 << 1)) { +// // a u b +// BasicBlock* bb = *(it++); +// b.SetInsertPoint(bb); +// Value* cmp = b.CreateICmpUGT(va, vb); +// b.CreateCondBr(cmp, trap_bb, *it); +// } + +// // Create trap BB. +// b.SetInsertPoint(trap_bb); +// e.SpillRegisters(); +// // TODO(benvanik): use @llvm.debugtrap? could make debugging better +// b.CreateCall2(e.gen_module()->getFunction("XeTrap"), +// e.gen_fn()->arg_begin(), +// b.getInt32(i.address)); +// b.CreateBr(after_bb); + +// // Resume. +// b.SetInsertPoint(after_bb); + +// return 0; +// } + +// XEEMITTER(td, 0x7C000088, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // a <- (RA) +// // b <- (RB) +// // if (a < b) & TO[0] then TRAP +// // if (a > b) & TO[1] then TRAP +// // if (a = b) & TO[2] then TRAP +// // if (a u b) & TO[4] then TRAP +// return XeEmitTrap(e, b, i, +// e.gpr_value(i.X.RA), +// e.gpr_value(i.X.RB), +// i.X.RT); +// } + +// XEEMITTER(tdi, 0x08000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // a <- (RA) +// // if (a < EXTS(SI)) & TO[0] then TRAP +// // if (a > EXTS(SI)) & TO[1] then TRAP +// // if (a = EXTS(SI)) & TO[2] then TRAP +// // if (a u EXTS(SI)) & TO[4] then TRAP +// return XeEmitTrap(e, b, i, +// e.gpr_value(i.D.RA), +// b.getInt64(XEEXTS16(i.D.DS)), +// i.D.RT); +// } + +// XEEMITTER(tw, 0x7C000008, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // a <- EXTS((RA)[32:63]) +// // b <- EXTS((RB)[32:63]) +// // if (a < b) & TO[0] then TRAP +// // if (a > b) & TO[1] then TRAP +// // if (a = b) & TO[2] then TRAP +// // if (a u b) & TO[4] then TRAP +// return XeEmitTrap(e, b, i, +// b.CreateSExt(b.CreateTrunc(e.gpr_value(i.X.RA), +// b.getInt32Ty()), +// b.getInt64Ty()), +// b.CreateSExt(b.CreateTrunc(e.gpr_value(i.X.RB), +// b.getInt32Ty()), +// b.getInt64Ty()), +// i.X.RT); +// } + +// XEEMITTER(twi, 0x0C000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // a <- EXTS((RA)[32:63]) +// // if (a < EXTS(SI)) & TO[0] then TRAP +// // if (a > EXTS(SI)) & TO[1] then TRAP +// // if (a = EXTS(SI)) & TO[2] then TRAP +// // if (a u EXTS(SI)) & TO[4] then TRAP +// return XeEmitTrap(e, b, i, +// b.CreateSExt(b.CreateTrunc(e.gpr_value(i.D.RA), +// b.getInt32Ty()), +// b.getInt64Ty()), +// b.getInt64(XEEXTS16(i.D.DS)), +// i.D.RT); +// } + + +// // Processor control (A-26) + +// XEEMITTER(mfcr, 0x7C000026, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(mfspr, 0x7C0002A6, XFX)(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // n <- spr[5:9] || spr[0:4] +// // if length(SPR(n)) = 64 then +// // RT <- SPR(n) +// // else +// // RT <- i32.0 || SPR(n) + +// const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F); +// Value* v = NULL; +// switch (n) { +// case 1: +// // XER +// v = e.xer_value(); +// break; +// case 8: +// // LR +// v = e.lr_value(); +// break; +// case 9: +// // CTR +// v = e.ctr_value(); +// break; +// default: +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// e.update_gpr_value(i.XFX.RT, v); + +// return 0; +// } + +// XEEMITTER(mftb, 0x7C0002E6, XFX)(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(mtcrf, 0x7C000120, XFX)(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(mtspr, 0x7C0003A6, XFX)(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // n <- spr[5:9] || spr[0:4] +// // if length(SPR(n)) = 64 then +// // SPR(n) <- (RS) +// // else +// // SPR(n) <- (RS)[32:63] + +// Value* v = e.gpr_value(i.XFX.RT); + +// const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F); +// switch (n) { +// case 1: +// // XER +// e.update_xer_value(v); +// break; +// case 8: +// // LR +// e.update_lr_value(v); +// break; +// case 9: +// // CTR +// e.update_ctr_value(v); +// break; +// default: +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// return 0; +// } + + +void LibjitRegisterEmitCategoryControl() { + // XEREGISTERINSTR(bx, 0x48000000); + // XEREGISTERINSTR(bcx, 0x40000000); + // XEREGISTERINSTR(bcctrx, 0x4C000420); + // XEREGISTERINSTR(bclrx, 0x4C000020); + // XEREGISTERINSTR(crand, 0x4C000202); + // XEREGISTERINSTR(crandc, 0x4C000102); + // XEREGISTERINSTR(creqv, 0x4C000242); + // XEREGISTERINSTR(crnand, 0x4C0001C2); + // XEREGISTERINSTR(crnor, 0x4C000042); + // XEREGISTERINSTR(cror, 0x4C000382); + // XEREGISTERINSTR(crorc, 0x4C000342); + // XEREGISTERINSTR(crxor, 0x4C000182); + // XEREGISTERINSTR(mcrf, 0x4C000000); + // XEREGISTERINSTR(sc, 0x44000002); + // XEREGISTERINSTR(td, 0x7C000088); + // XEREGISTERINSTR(tdi, 0x08000000); + // XEREGISTERINSTR(tw, 0x7C000008); + // XEREGISTERINSTR(twi, 0x0C000000); + // XEREGISTERINSTR(mfcr, 0x7C000026); + // XEREGISTERINSTR(mfspr, 0x7C0002A6); + // XEREGISTERINSTR(mftb, 0x7C0002E6); + // XEREGISTERINSTR(mtcrf, 0x7C000120); + // XEREGISTERINSTR(mtspr, 0x7C0003A6); +} + + +} // namespace libjit +} // namespace cpu +} // namespace xe diff --git a/src/xenia/cpu/libjit/libjit_emit_fpu.cc b/src/xenia/cpu/libjit/libjit_emit_fpu.cc new file mode 100644 index 000000000..630d0359c --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_emit_fpu.cc @@ -0,0 +1,293 @@ +/* + ****************************************************************************** + * 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 + + +using namespace xe::cpu; +using namespace xe::cpu::ppc; + + +namespace xe { +namespace cpu { +namespace libjit { + + +// Floating-point arithmetic (A-8) + +XEEMITTER(faddx, 0xFC00002A, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(faddsx, 0xEC00002A, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fdivx, 0xFC000024, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fdivsx, 0xEC000024, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fmulx, 0xFC000032, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fmulsx, 0xEC000032, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fresx, 0xEC000030, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(frsqrtex, 0xFC000034, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fsubx, 0xFC000028, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fsubsx, 0xEC000028, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fselx, 0xFC00002E, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fsqrtx, 0xFC00002C, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fsqrtsx, 0xEC00002C, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Floating-point multiply-add (A-9) + +XEEMITTER(fmaddx, 0xFC00003A, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fmaddsx, 0xEC00003A, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fmsubx, 0xFC000038, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fmsubsx, 0xEC000038, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fnmaddx, 0xFC00003E, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fnmaddsx, 0xEC00003E, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fnmsubx, 0xFC00003C, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fnmsubsx, 0xEC00003C, A )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Floating-point rounding and conversion (A-10) + +XEEMITTER(fcfidx, 0xFC00069C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fctidx, 0xFC00065C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fctidzx, 0xFC00065E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fctiwx, 0xFC00001C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fctiwzx, 0xFC00001E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(frspx, 0xFC000018, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Floating-point compare (A-11) + +XEEMITTER(fcmpo, 0xFC000040, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fcmpu, 0xFC000000, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + // if (FRA) is a NaN or (FRB) is a NaN then + // c <- 0b0001 + // else if (FRA) < (FRB) then + // c <- 0b1000 + // else if (FRA) > (FRB) then + // c <- 0b0100 + // else { + // c <- 0b0010 + // } + // FPCC <- c + // CR[4*BF:4*BF+3] <- c + // if (FRA) is an SNaN or (FRB) is an SNaN then + // VXSNAN <- 1 + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Floating-point status and control register (A + +XEEMITTER(mcrfs, 0xFC000080, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mffsx, 0xFC00048E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtfsb0x, 0xFC00008C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtfsb1x, 0xFC00004C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtfsfx, 0xFC00058E, XFL)(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtfsfix, 0xFC00010C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Floating-point move (A-21) + +XEEMITTER(fabsx, 0xFC000210, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fmrx, 0xFC000090, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fnabsx, 0xFC000110, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fnegx, 0xFC000050, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +void LibjitRegisterEmitCategoryFPU() { + XEREGISTERINSTR(faddx, 0xFC00002A); + XEREGISTERINSTR(faddsx, 0xEC00002A); + XEREGISTERINSTR(fdivx, 0xFC000024); + XEREGISTERINSTR(fdivsx, 0xEC000024); + XEREGISTERINSTR(fmulx, 0xFC000032); + XEREGISTERINSTR(fmulsx, 0xEC000032); + XEREGISTERINSTR(fresx, 0xEC000030); + XEREGISTERINSTR(frsqrtex, 0xFC000034); + XEREGISTERINSTR(fsubx, 0xFC000028); + XEREGISTERINSTR(fsubsx, 0xEC000028); + XEREGISTERINSTR(fselx, 0xFC00002E); + XEREGISTERINSTR(fsqrtx, 0xFC00002C); + XEREGISTERINSTR(fsqrtsx, 0xEC00002C); + XEREGISTERINSTR(fmaddx, 0xFC00003A); + XEREGISTERINSTR(fmaddsx, 0xEC00003A); + XEREGISTERINSTR(fmsubx, 0xFC000038); + XEREGISTERINSTR(fmsubsx, 0xEC000038); + XEREGISTERINSTR(fnmaddx, 0xFC00003E); + XEREGISTERINSTR(fnmaddsx, 0xEC00003E); + XEREGISTERINSTR(fnmsubx, 0xFC00003C); + XEREGISTERINSTR(fnmsubsx, 0xEC00003C); + XEREGISTERINSTR(fcfidx, 0xFC00069C); + XEREGISTERINSTR(fctidx, 0xFC00065C); + XEREGISTERINSTR(fctidzx, 0xFC00065E); + XEREGISTERINSTR(fctiwx, 0xFC00001C); + XEREGISTERINSTR(fctiwzx, 0xFC00001E); + XEREGISTERINSTR(frspx, 0xFC000018); + XEREGISTERINSTR(fcmpo, 0xFC000040); + XEREGISTERINSTR(fcmpu, 0xFC000000); + XEREGISTERINSTR(mcrfs, 0xFC000080); + XEREGISTERINSTR(mffsx, 0xFC00048E); + XEREGISTERINSTR(mtfsb0x, 0xFC00008C); + XEREGISTERINSTR(mtfsb1x, 0xFC00004C); + XEREGISTERINSTR(mtfsfx, 0xFC00058E); + XEREGISTERINSTR(mtfsfix, 0xFC00010C); + XEREGISTERINSTR(fabsx, 0xFC000210); + XEREGISTERINSTR(fmrx, 0xFC000090); + XEREGISTERINSTR(fnabsx, 0xFC000110); + XEREGISTERINSTR(fnegx, 0xFC000050); +} + + +} // namespace libjit +} // namespace cpu +} // namespace xe diff --git a/src/xenia/cpu/libjit/libjit_emit_memory.cc b/src/xenia/cpu/libjit/libjit_emit_memory.cc new file mode 100644 index 000000000..b9f61a093 --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_emit_memory.cc @@ -0,0 +1,1167 @@ +/* + ****************************************************************************** + * 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 + + +using namespace xe::cpu; +using namespace xe::cpu::ppc; + + +namespace xe { +namespace cpu { +namespace libjit { + + +// Integer load (A-13) + +// XEEMITTER(lbz, 0x88000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // RT <- i56.0 || MEM(EA, 1) + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 1, false); +// e.update_gpr_value(i.D.RT, v); + +// return 0; +// } + +// XEEMITTER(lbzu, 0x8C000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // RT <- i56.0 || MEM(EA, 1) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.ReadMemory(i.address, ea, 1, false); +// e.update_gpr_value(i.D.RT, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(lbzux, 0x7C0000EE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // RT <- i56.0 || MEM(EA, 1) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.ReadMemory(i.address, ea, 1, false); +// e.update_gpr_value(i.X.RT, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(lbzx, 0x7C0000AE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // RT <- i56.0 || MEM(EA, 1) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 1, false); +// e.update_gpr_value(i.X.RT, v); + +// return 0; +// } + +// XEEMITTER(ld, 0xE8000000, DS )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(DS || 0b00) +// // RT <- MEM(EA, 8) + +// Value* ea = b.getInt64(XEEXTS16(i.DS.DS << 2)); +// if (i.DS.RA) { +// ea = b.CreateAdd(e.gpr_value(i.DS.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 8, false); +// e.update_gpr_value(i.DS.RT, v); + +// return 0; +// } + +// XEEMITTER(ldu, 0xE8000001, DS )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(DS || 0b00) +// // RT <- MEM(EA, 8) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.DS.RA), +// b.getInt64(XEEXTS16(i.DS.DS << 2))); +// Value* v = e.ReadMemory(i.address, ea, 8, false); +// e.update_gpr_value(i.DS.RT, v); +// e.update_gpr_value(i.DS.RA, ea); + +// return 0; +// } + +// XEEMITTER(ldux, 0x7C00006A, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(ldx, 0x7C00002A, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(lha, 0xA8000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // RT <- EXTS(MEM(EA, 2)) + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = b.CreateSExt(e.ReadMemory(i.address, ea, 2, false), +// b.getInt64Ty()); +// e.update_gpr_value(i.D.RT, v); + +// return 0; +// } + +// XEEMITTER(lhau, 0xAC000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(lhaux, 0x7C0002EE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(lhax, 0x7C0002AE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // RT <- EXTS(MEM(EA, 2)) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = b.CreateSExt(e.ReadMemory(i.address, ea, 2, false), +// b.getInt64Ty()); +// e.update_gpr_value(i.X.RT, v); + +// return 0; +// } + +// XEEMITTER(lhz, 0xA0000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // RT <- i48.0 || MEM(EA, 2) + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 2, false); +// e.update_gpr_value(i.D.RT, v); + +// return 0; +// } + +// XEEMITTER(lhzu, 0xA4000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // RT <- i48.0 || MEM(EA, 2) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.ReadMemory(i.address, ea, 2, false); +// e.update_gpr_value(i.D.RT, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(lhzux, 0x7C00026E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // RT <- i48.0 || MEM(EA, 2) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.ReadMemory(i.address, ea, 2, false); +// e.update_gpr_value(i.X.RT, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(lhzx, 0x7C00022E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // RT <- i48.0 || MEM(EA, 2) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 2, false); +// e.update_gpr_value(i.X.RT, v); + +// return 0; +// } + +// XEEMITTER(lwa, 0xE8000002, DS )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D || 00) +// // RT <- EXTS(MEM(EA, 4)) + +// Value* ea = b.getInt64(XEEXTS16(i.DS.DS << 2)); +// if (i.DS.RA) { +// ea = b.CreateAdd(e.gpr_value(i.DS.RA), ea); +// } +// Value* v = b.CreateSExt(e.ReadMemory(i.address, ea, 4, false), +// b.getInt64Ty()); +// e.update_gpr_value(i.DS.RT, v); + +// return 0; +// } + +// XEEMITTER(lwaux, 0x7C0002EA, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // RT <- EXTS(MEM(EA, 4)) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = b.CreateSExt(e.ReadMemory(i.address, ea, 4, false), +// b.getInt64Ty()); +// e.update_gpr_value(i.X.RT, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(lwax, 0x7C0002AA, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // RT <- EXTS(MEM(EA, 4)) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = b.CreateSExt(e.ReadMemory(i.address, ea, 4, false), +// b.getInt64Ty()); +// e.update_gpr_value(i.X.RT, v); + +// return 0; +// } + +// XEEMITTER(lwz, 0x80000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // RT <- i32.0 || MEM(EA, 4) + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 4, false); +// e.update_gpr_value(i.D.RT, v); + +// return 0; +// } + +// XEEMITTER(lwzu, 0x84000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // RT <- i32.0 || MEM(EA, 4) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.ReadMemory(i.address, ea, 4, false); +// e.update_gpr_value(i.D.RT, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(lwzux, 0x7C00006E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // RT <- i32.0 || MEM(EA, 4) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.ReadMemory(i.address, ea, 4, false); +// e.update_gpr_value(i.X.RT, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(lwzx, 0x7C00002E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // RT <- i32.0 || MEM(EA, 4) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 4, false); +// e.update_gpr_value(i.X.RT, v); + +// return 0; +// } + + +// // Integer store (A-14) + +// XEEMITTER(stb, 0x98000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // MEM(EA, 1) <- (RS)[56:63] + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.gpr_value(i.D.RT); +// e.WriteMemory(i.address, ea, 1, v); + +// return 0; +// } + +// XEEMITTER(stbu, 0x9C000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // MEM(EA, 1) <- (RS)[56:63] +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.gpr_value(i.D.RT); +// e.WriteMemory(i.address, ea, 1, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(stbux, 0x7C0001EE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // MEM(EA, 1) <- (RS)[56:63] +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.gpr_value(i.X.RT); +// e.WriteMemory(i.address, ea, 1, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(stbx, 0x7C0001AE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // MEM(EA, 1) <- (RS)[56:63] + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.gpr_value(i.X.RT); +// e.WriteMemory(i.address, ea, 1, v); + +// return 0; +// } + +// XEEMITTER(std, 0xF8000000, DS )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(DS || 0b00) +// // MEM(EA, 8) <- (RS) + +// Value* ea = b.getInt64(XEEXTS16(i.DS.DS << 2)); +// if (i.DS.RA) { +// ea = b.CreateAdd(e.gpr_value(i.DS.RA), ea); +// } +// Value* v = e.gpr_value(i.DS.RT); +// e.WriteMemory(i.address, ea, 8, v); + +// return 0; +// } + +// XEEMITTER(stdu, 0xF8000001, DS )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(DS || 0b00) +// // MEM(EA, 8) <- (RS) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.DS.RA), +// b.getInt64(XEEXTS16(i.DS.DS << 2))); +// Value* v = e.gpr_value(i.DS.RT); +// e.WriteMemory(i.address, ea, 8, v); +// e.update_gpr_value(i.DS.RA, ea); + +// return 0; +// } + +// XEEMITTER(stdux, 0x7C00016A, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // MEM(EA, 8) <- (RS) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.gpr_value(i.X.RT); +// e.WriteMemory(i.address, ea, 8, v); + +// return 0; +// } + +// XEEMITTER(stdx, 0x7C00012A, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // MEM(EA, 8) <- (RS) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.gpr_value(i.X.RT); +// e.WriteMemory(i.address, ea, 8, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(sth, 0xB0000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // MEM(EA, 2) <- (RS)[48:63] + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.gpr_value(i.D.RT); +// e.WriteMemory(i.address, ea, 2, v); + +// return 0; +// } + +// XEEMITTER(sthu, 0xB4000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // MEM(EA, 2) <- (RS)[48:63] +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), +// b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.gpr_value(i.D.RT); +// e.WriteMemory(i.address, ea, 2, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(sthux, 0x7C00036E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // MEM(EA, 2) <- (RS)[48:63] +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.gpr_value(i.X.RT); +// e.WriteMemory(i.address, ea, 2, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(sthx, 0x7C00032E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // MEM(EA, 2) <- (RS)[48:63] + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.gpr_value(i.X.RT); +// e.WriteMemory(i.address, ea, 2, v); + +// return 0; +// } + +// XEEMITTER(stw, 0x90000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // MEM(EA, 4) <- (RS)[32:63] + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.gpr_value(i.D.RT); +// e.WriteMemory(i.address, ea, 4, v); + +// return 0; +// } + +// XEEMITTER(stwu, 0x94000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // MEM(EA, 4) <- (RS)[32:63] +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), +// b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.gpr_value(i.D.RT); +// e.WriteMemory(i.address, ea, 4, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(stwux, 0x7C00016E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // MEM(EA, 4) <- (RS)[32:63] +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.gpr_value(i.X.RT); +// e.WriteMemory(i.address, ea, 4, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(stwx, 0x7C00012E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // MEM(EA, 4) <- (RS)[32:63] + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.gpr_value(i.X.RT); +// e.WriteMemory(i.address, ea, 4, v); + +// return 0; +// } + + +// // Integer load and store with byte reverse (A-1 + +// XEEMITTER(lhbrx, 0x7C00062C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(lwbrx, 0x7C00042C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(ldbrx, 0x7C000428, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(sthbrx, 0x7C00072C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(stwbrx, 0x7C00052C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(stdbrx, 0x7C000528, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + + +// // Integer load and store multiple (A-16) + +// XEEMITTER(lmw, 0xB8000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(stmw, 0xBC000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + + +// // Integer load and store string (A-17) + +// XEEMITTER(lswi, 0x7C0004AA, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(lswx, 0x7C00042A, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(stswi, 0x7C0005AA, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(stswx, 0x7C00052A, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + + +// // Memory synchronization (A-18) + +// XEEMITTER(eieio, 0x7C0006AC, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(isync, 0x4C00012C, XL )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(ldarx, 0x7C0000A8, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(lwarx, 0x7C000028, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // RESERVE <- 1 +// // RESERVE_LENGTH <- 4 +// // RESERVE_ADDR <- real_addr(EA) +// // RT <- i32.0 || MEM(EA, 4) + +// // TODO(benvanik): make this right + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 4, /* acquire */ true); +// e.update_gpr_value(i.X.RT, v); + +// return 0; +// } + +// XEEMITTER(stdcx, 0x7C0001AD, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(stwcx, 0x7C00012D, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // RESERVE stuff... +// // MEM(EA, 4) <- (RS)[32:63] +// // n <- 1 if store performed +// // CR0[LT GT EQ SO] = 0b00 || n || XER[SO] + +// // TODO(benvanik): make this right + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.gpr_value(i.D.RT); +// e.WriteMemory(i.address, ea, 4, v, /* release */ true); + +// // We always succeed. +// e.update_cr_value(0, b.getInt64(1 << 2)); + +// return 0; +// } + +// XEEMITTER(sync, 0x7C0004AC, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + + +// // Floating-point load (A-19) + +// XEEMITTER(lfd, 0xC8000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // FRT <- MEM(EA, 8) + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 8, false); +// v = b.CreateBitCast(v, b.getDoubleTy()); +// e.update_fpr_value(i.D.RT, v); + +// return 0; +// } + +// XEEMITTER(lfdu, 0xCC000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // FRT <- MEM(EA, 8) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.ReadMemory(i.address, ea, 8, false); +// v = b.CreateBitCast(v, b.getDoubleTy()); +// e.update_fpr_value(i.D.RT, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(lfdux, 0x7C0004EE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // FRT <- MEM(EA, 8) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.ReadMemory(i.address, ea, 8, false); +// v = b.CreateBitCast(v, b.getDoubleTy()); +// e.update_fpr_value(i.X.RT, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(lfdx, 0x7C0004AE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // FRT <- MEM(EA, 8) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 8, false); +// v = b.CreateBitCast(v, b.getDoubleTy()); +// e.update_fpr_value(i.X.RT, v); + +// return 0; +// } + +// XEEMITTER(lfs, 0xC0000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // FRT <- DOUBLE(MEM(EA, 4)) + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 4, false); +// v = b.CreateFPExt(b.CreateBitCast(v, b.getFloatTy()), b.getDoubleTy()); +// e.update_fpr_value(i.D.RT, v); + +// return 0; +// } + +// XEEMITTER(lfsu, 0xC4000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // FRT <- DOUBLE(MEM(EA, 4)) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.ReadMemory(i.address, ea, 4, false); +// v = b.CreateFPExt(b.CreateBitCast(v, b.getFloatTy()), b.getDoubleTy()); +// e.update_fpr_value(i.D.RT, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(lfsux, 0x7C00046E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // FRT <- DOUBLE(MEM(EA, 4)) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.ReadMemory(i.address, ea, 4, false); +// v = b.CreateFPExt(b.CreateBitCast(v, b.getFloatTy()), b.getDoubleTy()); +// e.update_fpr_value(i.X.RT, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(lfsx, 0x7C00042E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // FRT <- DOUBLE(MEM(EA, 4)) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.ReadMemory(i.address, ea, 4, false); +// v = b.CreateFPExt(b.CreateBitCast(v, b.getFloatTy()), b.getDoubleTy()); +// e.update_fpr_value(i.X.RT, v); + +// return 0; +// } + + +// // Floating-point store (A-20) + +// XEEMITTER(stfd, 0xD8000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // MEM(EA, 8) <- (FRS) + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.fpr_value(i.D.RT); +// v = b.CreateBitCast(v, b.getInt64Ty()); +// e.WriteMemory(i.address, ea, 8, v); + +// return 0; +// } + +// XEEMITTER(stfdu, 0xDC000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // MEM(EA, 8) <- (FRS) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), +// b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.fpr_value(i.D.RT); +// v = b.CreateBitCast(v, b.getInt64Ty()); +// e.WriteMemory(i.address, ea, 8, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(stfdux, 0x7C0005EE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // MEM(EA, 8) <- (FRS) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.fpr_value(i.X.RT); +// v = b.CreateBitCast(v, b.getInt64Ty()); +// e.WriteMemory(i.address, ea, 8, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(stfdx, 0x7C0005AE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // MEM(EA, 8) <- (FRS) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.fpr_value(i.X.RT); +// v = b.CreateBitCast(v, b.getInt64Ty()); +// e.WriteMemory(i.address, ea, 8, v); + +// return 0; +// } + +// XEEMITTER(stfiwx, 0x7C0007AE, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // MEM(EA, 4) <- (FRS)[32:63] + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.fpr_value(i.X.RT); +// v = b.CreateBitCast(v, b.getInt64Ty()); +// e.WriteMemory(i.address, ea, 4, v); + +// return 0; +// } + +// XEEMITTER(stfs, 0xD0000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + EXTS(D) +// // MEM(EA, 4) <- SINGLE(FRS) + +// Value* ea = b.getInt64(XEEXTS16(i.D.DS)); +// if (i.D.RA) { +// ea = b.CreateAdd(e.gpr_value(i.D.RA), ea); +// } +// Value* v = e.fpr_value(i.D.RT); +// v = b.CreateBitCast(b.CreateFPTrunc(v, b.getFloatTy()), b.getInt32Ty()); +// e.WriteMemory(i.address, ea, 4, v); + +// return 0; +// } + +// XEEMITTER(stfsu, 0xD4000000, D )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + EXTS(D) +// // MEM(EA, 4) <- SINGLE(FRS) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.D.RA), +// b.getInt64(XEEXTS16(i.D.DS))); +// Value* v = e.fpr_value(i.D.RT); +// v = b.CreateBitCast(b.CreateFPTrunc(v, b.getFloatTy()), b.getInt32Ty()); +// e.WriteMemory(i.address, ea, 4, v); +// e.update_gpr_value(i.D.RA, ea); + +// return 0; +// } + +// XEEMITTER(stfsux, 0x7C00056E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // EA <- (RA) + (RB) +// // MEM(EA, 4) <- SINGLE(FRS) +// // RA <- EA + +// Value* ea = b.CreateAdd(e.gpr_value(i.X.RA), e.gpr_value(i.X.RB)); +// Value* v = e.fpr_value(i.X.RT); +// v = b.CreateBitCast(b.CreateFPTrunc(v, b.getFloatTy()), b.getInt32Ty()); +// e.WriteMemory(i.address, ea, 4, v); +// e.update_gpr_value(i.X.RA, ea); + +// return 0; +// } + +// XEEMITTER(stfsx, 0x7C00052E, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // if RA = 0 then +// // b <- 0 +// // else +// // b <- (RA) +// // EA <- b + (RB) +// // MEM(EA, 4) <- SINGLE(FRS) + +// Value* ea = e.gpr_value(i.X.RB); +// if (i.X.RA) { +// ea = b.CreateAdd(e.gpr_value(i.X.RA), ea); +// } +// Value* v = e.fpr_value(i.X.RT); +// v = b.CreateBitCast(b.CreateFPTrunc(v, b.getFloatTy()), b.getInt32Ty()); +// e.WriteMemory(i.address, ea, 4, v); + +// return 0; +// } + + +// // Cache management (A-27) + +// XEEMITTER(dcbf, 0x7C0000AC, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(dcbst, 0x7C00006C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(dcbt, 0x7C00022C, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // No-op for now. +// // TODO(benvanik): use @llvm.prefetch +// return 0; +// } + +// XEEMITTER(dcbtst, 0x7C0001EC, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // No-op for now. +// // TODO(benvanik): use @llvm.prefetch +// return 0; +// } + +// XEEMITTER(dcbz, 0x7C0007EC, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// // or dcbz128 0x7C2007EC +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + +// XEEMITTER(icbi, 0x7C0007AC, X )(LibjitEmitter& e, jit_function_t f, InstrData& i) { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } + + +void LibjitRegisterEmitCategoryMemory() { + // XEREGISTERINSTR(lbz, 0x88000000); + // XEREGISTERINSTR(lbzu, 0x8C000000); + // XEREGISTERINSTR(lbzux, 0x7C0000EE); + // XEREGISTERINSTR(lbzx, 0x7C0000AE); + // XEREGISTERINSTR(ld, 0xE8000000); + // XEREGISTERINSTR(ldu, 0xE8000001); + // XEREGISTERINSTR(ldux, 0x7C00006A); + // XEREGISTERINSTR(ldx, 0x7C00002A); + // XEREGISTERINSTR(lha, 0xA8000000); + // XEREGISTERINSTR(lhau, 0xAC000000); + // XEREGISTERINSTR(lhaux, 0x7C0002EE); + // XEREGISTERINSTR(lhax, 0x7C0002AE); + // XEREGISTERINSTR(lhz, 0xA0000000); + // XEREGISTERINSTR(lhzu, 0xA4000000); + // XEREGISTERINSTR(lhzux, 0x7C00026E); + // XEREGISTERINSTR(lhzx, 0x7C00022E); + // XEREGISTERINSTR(lwa, 0xE8000002); + // XEREGISTERINSTR(lwaux, 0x7C0002EA); + // XEREGISTERINSTR(lwax, 0x7C0002AA); + // XEREGISTERINSTR(lwz, 0x80000000); + // XEREGISTERINSTR(lwzu, 0x84000000); + // XEREGISTERINSTR(lwzux, 0x7C00006E); + // XEREGISTERINSTR(lwzx, 0x7C00002E); + // XEREGISTERINSTR(stb, 0x98000000); + // XEREGISTERINSTR(stbu, 0x9C000000); + // XEREGISTERINSTR(stbux, 0x7C0001EE); + // XEREGISTERINSTR(stbx, 0x7C0001AE); + // XEREGISTERINSTR(std, 0xF8000000); + // XEREGISTERINSTR(stdu, 0xF8000001); + // XEREGISTERINSTR(stdux, 0x7C00016A); + // XEREGISTERINSTR(stdx, 0x7C00012A); + // XEREGISTERINSTR(sth, 0xB0000000); + // XEREGISTERINSTR(sthu, 0xB4000000); + // XEREGISTERINSTR(sthux, 0x7C00036E); + // XEREGISTERINSTR(sthx, 0x7C00032E); + // XEREGISTERINSTR(stw, 0x90000000); + // XEREGISTERINSTR(stwu, 0x94000000); + // XEREGISTERINSTR(stwux, 0x7C00016E); + // XEREGISTERINSTR(stwx, 0x7C00012E); + // XEREGISTERINSTR(lhbrx, 0x7C00062C); + // XEREGISTERINSTR(lwbrx, 0x7C00042C); + // XEREGISTERINSTR(ldbrx, 0x7C000428); + // XEREGISTERINSTR(sthbrx, 0x7C00072C); + // XEREGISTERINSTR(stwbrx, 0x7C00052C); + // XEREGISTERINSTR(stdbrx, 0x7C000528); + // XEREGISTERINSTR(lmw, 0xB8000000); + // XEREGISTERINSTR(stmw, 0xBC000000); + // XEREGISTERINSTR(lswi, 0x7C0004AA); + // XEREGISTERINSTR(lswx, 0x7C00042A); + // XEREGISTERINSTR(stswi, 0x7C0005AA); + // XEREGISTERINSTR(stswx, 0x7C00052A); + // XEREGISTERINSTR(eieio, 0x7C0006AC); + // XEREGISTERINSTR(isync, 0x4C00012C); + // XEREGISTERINSTR(ldarx, 0x7C0000A8); + // XEREGISTERINSTR(lwarx, 0x7C000028); + // XEREGISTERINSTR(stdcx, 0x7C0001AD); + // XEREGISTERINSTR(stwcx, 0x7C00012D); + // XEREGISTERINSTR(sync, 0x7C0004AC); + // XEREGISTERINSTR(lfd, 0xC8000000); + // XEREGISTERINSTR(lfdu, 0xCC000000); + // XEREGISTERINSTR(lfdux, 0x7C0004EE); + // XEREGISTERINSTR(lfdx, 0x7C0004AE); + // XEREGISTERINSTR(lfs, 0xC0000000); + // XEREGISTERINSTR(lfsu, 0xC4000000); + // XEREGISTERINSTR(lfsux, 0x7C00046E); + // XEREGISTERINSTR(lfsx, 0x7C00042E); + // XEREGISTERINSTR(stfd, 0xD8000000); + // XEREGISTERINSTR(stfdu, 0xDC000000); + // XEREGISTERINSTR(stfdux, 0x7C0005EE); + // XEREGISTERINSTR(stfdx, 0x7C0005AE); + // XEREGISTERINSTR(stfiwx, 0x7C0007AE); + // XEREGISTERINSTR(stfs, 0xD0000000); + // XEREGISTERINSTR(stfsu, 0xD4000000); + // XEREGISTERINSTR(stfsux, 0x7C00056E); + // XEREGISTERINSTR(stfsx, 0x7C00052E); + // XEREGISTERINSTR(dcbf, 0x7C0000AC); + // XEREGISTERINSTR(dcbst, 0x7C00006C); + // XEREGISTERINSTR(dcbt, 0x7C00022C); + // XEREGISTERINSTR(dcbtst, 0x7C0001EC); + // XEREGISTERINSTR(dcbz, 0x7C0007EC); + // XEREGISTERINSTR(icbi, 0x7C0007AC); +} + + +} // namespace libjit +} // namespace cpu +} // namespace xe diff --git a/src/xenia/cpu/libjit/libjit_emitter.cc b/src/xenia/cpu/libjit/libjit_emitter.cc new file mode 100644 index 000000000..340cbf22e --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_emitter.cc @@ -0,0 +1,1276 @@ +/** + ****************************************************************************** + * 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 + +#include +#include + + +using namespace xe::cpu::libjit; +using namespace xe::cpu::ppc; +using namespace xe::cpu::sdb; + + +DEFINE_bool(memory_address_verification, false, + "Whether to add additional checks to generated memory load/stores."); +DEFINE_bool(log_codegen, false, + "Log codegen to stdout."); + + +/** + * This generates function code. + * One context is created and shared 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 + */ + + +LibjitEmitter::LibjitEmitter(xe_memory_ref memory, jit_context_t context) { + memory_ = memory; + context_ = context; + + // Grab global exports. + cpu::GetGlobalExports(&global_exports_); + + // Function type for all functions. + // TODO(benvanik): evaluate using jit_abi_fastcall + jit_type_t fn_params[] = { + jit_type_void_ptr, + jit_type_uint + }; + fn_signature_ = jit_type_create_signature( + jit_abi_cdecl, + jit_type_void, + fn_params, XECOUNT(fn_params), + 0); + + jit_type_t global_export_params[] = { + jit_type_void_ptr, + jit_type_ulong, + jit_type_ulong, + jit_type_void_ptr, + }; + global_export_signature_ = jit_type_create_signature( + jit_abi_cdecl, + jit_type_void, + global_export_params, XECOUNT(global_export_params), + 0); +} + +LibjitEmitter::~LibjitEmitter() { + jit_type_free(fn_signature_); + jit_type_free(global_export_signature_); +} + +jit_context_t LibjitEmitter::context() { + return context_; +} + +jit_type_t LibjitEmitter::fn_signature() { + return fn_signature_; +} + +namespace { +int libjit_on_demand_compile(jit_function_t fn) { + LibjitEmitter* emitter = (LibjitEmitter*)jit_function_get_meta(fn, 0x1000); + FunctionSymbol* symbol = (FunctionSymbol*)jit_function_get_meta(fn, 0x1001); + XELOGE("Compile(%s): beginning on-demand compilation...", symbol->name()); + int result_code = emitter->MakeFunction(symbol, fn); + if (result_code) { + XELOGCPU("Compile(%s): failed to make function", symbol->name()); + return JIT_RESULT_COMPILE_ERROR; + } + return JIT_RESULT_OK; +} +} + +int LibjitEmitter::PrepareFunction(FunctionSymbol* symbol) { + if (symbol->impl_value) { + return 0; + } + + jit_context_build_start(context_); + + // Create the function and setup for on-demand compilation. + jit_function_t fn = jit_function_create(context_, fn_signature_); + jit_function_set_meta(fn, 0x1000, this, NULL, 0); + jit_function_set_meta(fn, 0x1001, symbol, NULL, 0); + jit_function_set_on_demand_compiler(fn, libjit_on_demand_compile); + + // Set optimization options. + // TODO(benvanik): add gflags + uint32_t opt_level = 0; + uint32_t max_level = jit_function_get_max_optimization_level(); + opt_level = MIN(max_level, MAX(0, opt_level)); + jit_function_set_optimization_level(fn, opt_level); + + // Stash for later. + symbol->impl_value = fn; + jit_context_build_end(context_); + + return 0; +} + +int LibjitEmitter::MakeFunction(FunctionSymbol* symbol, jit_function_t gen_fn) { + fn_ = symbol; + gen_fn_ = gen_fn; + + // fn_block_ = NULL; + // return_block_ = NULL; + // internal_indirection_block_ = NULL; + // external_indirection_block_ = NULL; + // bb_ = NULL; + + // insert_points_.clear(); + // bbs_.clear(); + + cia_ = 0; + + access_bits_.Clear(); + + locals_.indirection_target = NULL; + locals_.indirection_cia = NULL; + + locals_.xer = NULL; + locals_.lr = NULL; + locals_.ctr = NULL; + for (size_t n = 0; n < XECOUNT(locals_.cr); n++) { + locals_.cr[n] = NULL; + } + for (size_t n = 0; n < XECOUNT(locals_.gpr); n++) { + locals_.gpr[n] = NULL; + } + for (size_t n = 0; n < XECOUNT(locals_.fpr); n++) { + locals_.fpr[n] = NULL; + } + + if (FLAGS_log_codegen) { + printf("%s:\n", symbol->name()); + } + + int result_code = 0; + switch (symbol->type) { + case FunctionSymbol::User: + result_code = MakeUserFunction(); + break; + case FunctionSymbol::Kernel: + if (symbol->kernel_export && symbol->kernel_export->is_implemented) { + result_code = MakePresentImportFunction(); + } else { + result_code = MakeMissingImportFunction(); + } + break; + default: + XEASSERTALWAYS(); + result_code = 1; + break; + } + + if (!result_code) { + // pre + jit_dump_function(stdout, gen_fn_, symbol->name()); + jit_function_compile(gen_fn_); + // post + jit_dump_function(stdout, gen_fn_, symbol->name()); + } + + return result_code; +} + +int LibjitEmitter::MakeUserFunction() { + if (FLAGS_trace_user_calls) { + jit_value_t trace_args[] = { + jit_value_get_param(gen_fn_, 0), + jit_value_create_long_constant(gen_fn_, jit_type_ulong, + (jit_ulong)fn_->start_address), + jit_value_get_param(gen_fn_, 1), + jit_value_create_long_constant(gen_fn_, jit_type_ulong, + (jit_ulong)fn_), + }; + jit_insn_call_native( + gen_fn_, + "XeTraceUserCall", global_exports_.XeTraceUserCall, + global_export_signature_, + trace_args, XECOUNT(trace_args), + 0); + } + + // Emit. + //emitter_->GenerateBasicBlocks(); + jit_insn_return(gen_fn_, NULL); + return 0; +} + +int LibjitEmitter::MakePresentImportFunction() { + // LLVMContext& context = *context_; + + // Generate the function. + // Function* fn = NULL; + // result_code = cub_->MakeFunction(symbol, &fn); + // if (result_code) { + // XELOGE("Unable to generate import %s", symbol->name()); + // return result_code; + // } + + // // Set global mappings for shim and data. + // char shim_name[256]; + // xesnprintfa(shim_name, XECOUNT(shim_name), + // "__shim_%s", symbol->kernel_export->name); + // Function* shim = cub_module->getFunction(shim_name); + // if (shim) { + // engine_->updateGlobalMapping( + // shim, (void*)symbol->kernel_export->function_data.shim); + // } + // char shim_data_name[256]; + // xesnprintfa(shim_data_name, XECOUNT(shim_data_name), + // "__shim_data_%s", symbol->kernel_export->name); + // GlobalVariable* shim_data = cub_module->getGlobalVariable(shim_data_name); + // if (shim_data) { + // engine_->updateGlobalMapping( + // shim_data, (void*)symbol->kernel_export->function_data.shim_data); + // } + + // // Pick names. + // // We have both the shim function pointer and the shim data pointer. + // char shim_name[256]; + // xesnprintfa(shim_name, XECOUNT(shim_name), + // "__shim_%s", symbol->kernel_export->name); + // char shim_data_name[256]; + // xesnprintfa(shim_data_name, XECOUNT(shim_data_name), + // "__shim_data_%s", symbol->kernel_export->name); + + // // Hardcoded to 64bits. + // Type* intPtrTy = IntegerType::get(context, 64); + // Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context)); + + // // Declare shim function. + // std::vector shimArgs; + // shimArgs.push_back(int8PtrTy); + // shimArgs.push_back(int8PtrTy); + // FunctionType* shimTy = FunctionType::get( + // Type::getVoidTy(context), shimArgs, false); + // Function* shim = Function::Create( + // shimTy, Function::ExternalLinkage, shim_name, module_); + + // GlobalVariable* shim_data = new GlobalVariable( + // *module_, int8PtrTy, false, GlobalValue::ExternalLinkage, 0, + // shim_data_name); + // shim_data->setInitializer(ConstantExpr::getIntToPtr( + // ConstantInt::get(intPtrTy, 0), int8PtrTy)); + + // BasicBlock* block = BasicBlock::Create(context, "entry", fn); + // IRBuilder<> b(block); + + if (FLAGS_trace_kernel_calls) { + jit_value_t trace_args[] = { + jit_value_get_param(gen_fn_, 0), + jit_value_create_long_constant(gen_fn_, jit_type_ulong, + (jit_ulong)fn_->start_address), + jit_value_get_param(gen_fn_, 1), + jit_value_create_long_constant(gen_fn_, jit_type_ulong, + (jit_ulong)fn_->kernel_export), + }; + jit_insn_call_native( + gen_fn_, + "XeTraceKernelCall", global_exports_.XeTraceKernelCall, + global_export_signature_, + trace_args, XECOUNT(trace_args), + 0); + } + + // b.CreateCall2( + // shim, + // fn->arg_begin(), + // b.CreateLoad(shim_data)); + + jit_insn_return(gen_fn_, NULL); + + return 0; +} + +int LibjitEmitter::MakeMissingImportFunction() { + if (FLAGS_trace_kernel_calls) { + jit_value_t trace_args[] = { + jit_value_get_param(gen_fn_, 0), + jit_value_create_long_constant(gen_fn_, jit_type_ulong, + (jit_ulong)fn_->start_address), + jit_value_get_param(gen_fn_, 1), + jit_value_create_long_constant(gen_fn_, jit_type_ulong, + (jit_ulong)fn_->kernel_export), + }; + jit_insn_call_native( + gen_fn_, + "XeTraceKernelCall", global_exports_.XeTraceKernelCall, + global_export_signature_, + trace_args, XECOUNT(trace_args), + 0); + } + + jit_insn_return(gen_fn_, NULL); + + return 0; +} + +FunctionSymbol* LibjitEmitter::fn() { + return fn_; +} + +jit_function_t LibjitEmitter::gen_fn() { + return gen_fn_; +} + +//FunctionBlock* LibjitEmitter::fn_block() { +// return fn_block_; +//} +// +//void LibjitEmitter::PushInsertPoint() { +// IRBuilder<>& b = *builder_; +// insert_points_.push_back(std::pair( +// b.GetInsertBlock(), b.GetInsertPoint())); +//} +// +//void LibjitEmitter::PopInsertPoint() { +// IRBuilder<>& b = *builder_; +// std::pair back = insert_points_.back(); +// b.SetInsertPoint(back.first, back.second); +// insert_points_.pop_back(); +//} +// +//void LibjitEmitter::GenerateBasicBlocks() { +// IRBuilder<>& b = *builder_; +// +// // Always add an entry block. +// BasicBlock* entry = BasicBlock::Create(*context_, "entry", gen_fn_); +// b.SetInsertPoint(entry); +// +// if (FLAGS_trace_user_calls) { +// SpillRegisters(); +// Value* traceUserCall = gen_module_->getFunction("XeTraceUserCall"); +// b.CreateCall4( +// traceUserCall, +// gen_fn_->arg_begin(), +// b.getInt64(fn_->start_address), +// ++gen_fn_->arg_begin(), +// b.getInt64((uint64_t)fn_)); +// } +// +// // If this function is empty, abort! +// if (!fn_->blocks.size()) { +// b.CreateRetVoid(); +// return; +// } +// +// // Create a return block. +// // This spills registers and returns. All non-tail returns should branch +// // here to do the return and ensure registers are spilled. +// return_block_ = BasicBlock::Create(*context_, "return", gen_fn_); +// +// // Pass 1 creates all of the blocks - this way we can branch to them. +// // We also track registers used so that when know which ones to fill/spill. +// for (std::map::iterator it = fn_->blocks.begin(); +// it != fn_->blocks.end(); ++it) { +// FunctionBlock* block = it->second; +// XEIGNORE(PrepareBasicBlock(block)); +// } +// +// // Setup all local variables now that we know what we need. +// SetupLocals(); +// +// // Pass 2 fills in instructions. +// for (std::map::iterator it = fn_->blocks.begin(); +// it != fn_->blocks.end(); ++it) { +// FunctionBlock* block = it->second; +// GenerateBasicBlock(block); +// } +// +// // Setup the shared return/indirection/etc blocks now that we know all the +// // blocks we need and all the registers used. +// GenerateSharedBlocks(); +//} +// +//void LibjitEmitter::GenerateSharedBlocks() { +// IRBuilder<>& b = *builder_; +// +// Value* indirect_branch = gen_module_->getFunction("XeIndirectBranch"); +// +// // Setup initial register fill in the entry block. +// // We can only do this once all the locals have been created. +// b.SetInsertPoint(&gen_fn_->getEntryBlock()); +// FillRegisters(); +// // Entry always falls through to the second block. +// b.CreateBr(bbs_.begin()->second); +// +// // Setup the spill block in return. +// b.SetInsertPoint(return_block_); +// SpillRegisters(); +// b.CreateRetVoid(); +// +// // Build indirection block on demand. +// // We have already prepped all basic blocks, so we can build these tables now. +// if (external_indirection_block_) { +// // This will spill registers and call the external function. +// // It is only meant for LK=0. +// b.SetInsertPoint(external_indirection_block_); +// SpillRegisters(); +// b.CreateCall3(indirect_branch, +// gen_fn_->arg_begin(), +// b.CreateLoad(locals_.indirection_target), +// b.CreateLoad(locals_.indirection_cia)); +// b.CreateRetVoid(); +// } +// +// if (internal_indirection_block_) { +// // This will not spill registers and instead try to switch on local blocks. +// // If it fails then the external indirection path is taken. +// // NOTE: we only generate this if a likely local branch is taken. +// b.SetInsertPoint(internal_indirection_block_); +// SwitchInst* switch_i = b.CreateSwitch( +// b.CreateLoad(locals_.indirection_target), +// external_indirection_block_, +// static_cast(bbs_.size())); +// for (std::map::iterator it = bbs_.begin(); +// it != bbs_.end(); ++it) { +// switch_i->addCase(b.getInt64(it->first), it->second); +// } +// } +//} +// +//int LibjitEmitter::PrepareBasicBlock(FunctionBlock* block) { +// // Create the basic block that will end up getting filled during +// // generation. +// char name[32]; +// xesnprintfa(name, XECOUNT(name), "loc_%.8X", block->start_address); +// BasicBlock* bb = BasicBlock::Create(*context_, name, gen_fn_); +// bbs_.insert(std::pair(block->start_address, bb)); +// +// // Scan and disassemble each instruction in the block to get accurate +// // register access bits. In the future we could do other optimization checks +// // in this pass. +// // TODO(benvanik): perhaps we want to stash this for each basic block? +// // We could use this for faster checking of cr/ca checks/etc. +// InstrAccessBits access_bits; +// 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); +// +// // Ignore unknown or ones with no disassembler fn. +// if (!i.type || !i.type->disassemble) { +// continue; +// } +// +// // We really need to know the registers modified, so die if we've been lazy +// // and haven't implemented the disassemble method yet. +// ppc::InstrDisasm d; +// XEASSERTNOTNULL(i.type->disassemble); +// int result_code = i.type->disassemble(i, d); +// XEASSERTZERO(result_code); +// if (result_code) { +// return result_code; +// } +// +// // Accumulate access bits. +// access_bits.Extend(d.access_bits); +// } +// +// // Add in access bits to function access bits. +// access_bits_.Extend(access_bits); +// +// return 0; +//} +// +//void LibjitEmitter::GenerateBasicBlock(FunctionBlock* block) { +// IRBuilder<>& b = *builder_; +// +// BasicBlock* bb = GetBasicBlock(block->start_address); +// XEASSERTNOTNULL(bb); +// +// if (FLAGS_log_codegen) { +// printf(" bb %.8X-%.8X:\n", block->start_address, block->end_address); +// } +// +// fn_block_ = block; +// bb_ = bb; +// +// // Move the builder to this block and setup. +// b.SetInsertPoint(bb); +// //i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname))); +// +// Value* invalidInstruction = +// gen_module_->getFunction("XeInvalidInstruction"); +// Value* traceInstruction = +// gen_module_->getFunction("XeTraceInstruction"); +// +// // 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 (FLAGS_trace_instructions) { +// SpillRegisters(); +// b.CreateCall3( +// traceInstruction, +// gen_fn_->arg_begin(), +// b.getInt32(i.address), +// b.getInt32(i.code)); +// } +// +// if (!i.type) { +// XELOGCPU("Invalid instruction %.8X %.8X", ia, i.code); +// SpillRegisters(); +// b.CreateCall3( +// invalidInstruction, +// gen_fn_->arg_begin(), +// b.getInt32(i.address), +// b.getInt32(i.code)); +// continue; +// } +// +// if (FLAGS_log_codegen) { +// if (i.type->disassemble) { +// ppc::InstrDisasm d; +// i.type->disassemble(i, d); +// std::string disasm; +// d.Dump(disasm); +// printf(" %.8X: %.8X %s\n", ia, i.code, disasm.c_str()); +// } else { +// 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)); +// +// typedef int (*InstrEmitter)(LibjitEmitter& g, IRBuilder<>& b, +// InstrData& i); +// InstrEmitter emit = (InstrEmitter)i.type->emit; +// if (!i.type->emit || emit(*this, *builder_, i)) { +// // This printf is handy for sort/uniquify to find instructions. +// //printf("unimplinstr %s\n", i.type->name); +// +// XELOGCPU("Unimplemented instr %.8X %.8X %s", +// ia, i.code, i.type->name); +// SpillRegisters(); +// b.CreateCall3( +// invalidInstruction, +// gen_fn_->arg_begin(), +// b.getInt32(i.address), +// b.getInt32(i.code)); +// } +// } +// +// // If we fall through, create the branch. +// if (block->outgoing_type == FunctionBlock::kTargetNone) { +// BasicBlock* next_bb = GetNextBasicBlock(); +// XEASSERTNOTNULL(next_bb); +// b.CreateBr(next_bb); +// } else if (block->outgoing_type == FunctionBlock::kTargetUnknown) { +// // Hrm. +// // TODO(benvanik): assert this doesn't occur - means a bad sdb run! +// XELOGCPU("SDB function scan error in %.8X: bb %.8X has unknown exit", +// fn_->start_address, block->start_address); +// b.CreateRetVoid(); +// } +// +// // TODO(benvanik): finish up BB +//} +// +//BasicBlock* LibjitEmitter::GetBasicBlock(uint32_t address) { +// std::map::iterator it = bbs_.find(address); +// if (it != bbs_.end()) { +// return it->second; +// } +// return NULL; +//} +// +//BasicBlock* LibjitEmitter::GetNextBasicBlock() { +// std::map::iterator it = bbs_.find( +// fn_block_->start_address); +// ++it; +// if (it != bbs_.end()) { +// return it->second; +// } +// return NULL; +//} +// +//BasicBlock* LibjitEmitter::GetReturnBasicBlock() { +// return return_block_; +//} + +//int LibjitEmitter::GenerateIndirectionBranch(uint32_t cia, Value* target, +// bool lk, bool likely_local) { +// // This function is called by the control emitters when they know that an +// // indirect branch is required. +// // It first tries to see if the branch is to an address within the function +// // and, if so, uses a local switch table. If that fails because we don't know +// // the block the function is regenerated (ACK!). If the target is external +// // then an external call occurs. +// +// IRBuilder<>& b = *builder_; +// BasicBlock* next_block = GetNextBasicBlock(); +// +// PushInsertPoint(); +// +// // Request builds of the indirection blocks on demand. +// // We can't build here because we don't know what registers will be needed +// // yet, so we just create the blocks and let GenerateSharedBlocks handle it +// // after we are done with all user instructions. +// if (!external_indirection_block_) { +// // Setup locals in the entry block. +// b.SetInsertPoint(&gen_fn_->getEntryBlock()); +// locals_.indirection_target = b.CreateAlloca( +// b.getInt64Ty(), 0, "indirection_target"); +// locals_.indirection_cia = b.CreateAlloca( +// b.getInt64Ty(), 0, "indirection_cia"); +// +// external_indirection_block_ = BasicBlock::Create( +// *context_, "external_indirection_block", gen_fn_, return_block_); +// } +// if (likely_local && !internal_indirection_block_) { +// internal_indirection_block_ = BasicBlock::Create( +// *context_, "internal_indirection_block", gen_fn_, return_block_); +// } +// +// PopInsertPoint(); +// +// // Check to see if the target address is within the function. +// // If it is jump to that basic block. If the basic block is not found it means +// // we have a jump inside the function that wasn't identified via static +// // analysis. These are bad as they require function regeneration. +// if (likely_local) { +// // Note that we only support LK=0, as we are using shared tables. +// XEASSERT(!lk); +// b.CreateStore(target, locals_.indirection_target); +// b.CreateStore(b.getInt64(cia), locals_.indirection_cia); +// Value* fn_ge_cmp = b.CreateICmpUGE(target, b.getInt64(fn_->start_address)); +// Value* fn_l_cmp = b.CreateICmpULT(target, b.getInt64(fn_->end_address)); +// Value* fn_target_cmp = b.CreateAnd(fn_ge_cmp, fn_l_cmp); +// b.CreateCondBr(fn_target_cmp, +// internal_indirection_block_, external_indirection_block_); +// return 0; +// } +// +// // If we are LK=0 jump to the shared indirection block. This prevents us +// // from needing to fill the registers again after the call and shares more +// // code. +// if (!lk) { +// b.CreateStore(target, locals_.indirection_target); +// b.CreateStore(b.getInt64(cia), locals_.indirection_cia); +// b.CreateBr(external_indirection_block_); +// } else { +// // Slowest path - spill, call the external function, and fill. +// // We should avoid this at all costs. +// +// // Spill registers. We could probably share this. +// SpillRegisters(); +// +// // TODO(benvanik): keep function pointer lookup local. +// Value* indirect_branch = gen_module_->getFunction("XeIndirectBranch"); +// b.CreateCall3(indirect_branch, +// gen_fn_->arg_begin(), +// target, +// b.getInt64(cia)); +// +// if (next_block) { +// // Only refill if not a tail call. +// FillRegisters(); +// b.CreateBr(next_block); +// } else { +// b.CreateRetVoid(); +// } +// } +// +// return 0; +//} +// +//Value* LibjitEmitter::LoadStateValue(uint32_t offset, Type* type, +// const char* name) { +// IRBuilder<>& b = *builder_; +// PointerType* pointerTy = PointerType::getUnqual(type); +// Function::arg_iterator args = gen_fn_->arg_begin(); +// Value* state_ptr = args; +// Value* address = b.CreateInBoundsGEP(state_ptr, b.getInt32(offset)); +// Value* ptr = b.CreatePointerCast(address, pointerTy); +// return b.CreateLoad(ptr, name); +//} +// +//void LibjitEmitter::StoreStateValue(uint32_t offset, Type* type, +// Value* value) { +// IRBuilder<>& b = *builder_; +// PointerType* pointerTy = PointerType::getUnqual(type); +// Function::arg_iterator args = gen_fn_->arg_begin(); +// Value* state_ptr = args; +// Value* address = b.CreateInBoundsGEP(state_ptr, b.getInt32(offset)); +// Value* ptr = b.CreatePointerCast(address, pointerTy); +// b.CreateStore(value, ptr); +//} +// +//void LibjitEmitter::SetupLocals() { +// IRBuilder<>& b = *builder_; +// +// uint64_t spr_t = access_bits_.spr; +// if (spr_t & 0x3) { +// locals_.xer = SetupLocal(b.getInt64Ty(), "xer"); +// } +// spr_t >>= 2; +// if (spr_t & 0x3) { +// locals_.lr = SetupLocal(b.getInt64Ty(), "lr"); +// } +// spr_t >>= 2; +// if (spr_t & 0x3) { +// locals_.ctr = SetupLocal(b.getInt64Ty(), "ctr"); +// } +// spr_t >>= 2; +// // TODO: FPCSR +// +// char name[32]; +// +// uint64_t cr_t = access_bits_.cr; +// for (int n = 0; n < 8; n++) { +// if (cr_t & 3) { +// xesnprintfa(name, XECOUNT(name), "cr%d", n); +// locals_.cr[n] = SetupLocal(b.getInt8Ty(), name); +// } +// cr_t >>= 2; +// } +// +// uint64_t gpr_t = access_bits_.gpr; +// for (int n = 0; n < 32; n++) { +// if (gpr_t & 3) { +// xesnprintfa(name, XECOUNT(name), "r%d", n); +// locals_.gpr[n] = SetupLocal(b.getInt64Ty(), name); +// } +// gpr_t >>= 2; +// } +// +// uint64_t fpr_t = access_bits_.fpr; +// for (int n = 0; n < 32; n++) { +// if (fpr_t & 3) { +// xesnprintfa(name, XECOUNT(name), "f%d", n); +// locals_.fpr[n] = SetupLocal(b.getDoubleTy(), name); +// } +// fpr_t >>= 2; +// } +//} +// +//Value* LibjitEmitter::SetupLocal(llvm::Type* type, const char* name) { +// IRBuilder<>& b = *builder_; +// // Insert into the entry block. +// PushInsertPoint(); +// b.SetInsertPoint(&gen_fn_->getEntryBlock()); +// Value* v = b.CreateAlloca(type, 0, name); +// PopInsertPoint(); +// return v; +//} +// +//Value* LibjitEmitter::cia_value() { +// return builder_->getInt32(cia_); +//} +// +//void LibjitEmitter::FillRegisters() { +// // This updates all of the local register values from the state memory. +// // It should be called on function entry for initial setup and after any +// // calls that may modify the registers. +// +// // TODO(benvanik): use access flags to see if we need to do reads/writes. +// // Though LLVM may do a better job than we can, except across calls. +// +// IRBuilder<>& b = *builder_; +// +// if (locals_.xer) { +// b.CreateStore(LoadStateValue( +// offsetof(xe_ppc_state_t, xer), +// b.getInt64Ty()), locals_.xer); +// } +// +// if (locals_.lr) { +// b.CreateStore(LoadStateValue( +// offsetof(xe_ppc_state_t, lr), +// b.getInt64Ty()), locals_.lr); +// } +// +// if (locals_.ctr) { +// b.CreateStore(LoadStateValue( +// offsetof(xe_ppc_state_t, ctr), +// b.getInt64Ty()), locals_.ctr); +// } +// +// // Fill the split CR values by extracting each one from the CR. +// // This could probably be done faster via an extractvalues or something. +// // Perhaps we could also change it to be a vector<8*i8>. +// Value* cr = NULL; +// for (size_t n = 0; n < XECOUNT(locals_.cr); n++) { +// Value* cr_n = locals_.cr[n]; +// if (!cr_n) { +// continue; +// } +// if (!cr) { +// cr = LoadStateValue( +// offsetof(xe_ppc_state_t, cr), +// b.getInt64Ty()); +// } +// b.CreateStore( +// b.CreateTrunc(b.CreateAnd(b.CreateLShr(cr, (28 - n * 4)), 0xF), +// b.getInt8Ty()), cr_n); +// } +// +// for (size_t n = 0; n < XECOUNT(locals_.gpr); n++) { +// if (locals_.gpr[n]) { +// b.CreateStore(LoadStateValue( +// (uint32_t)offsetof(xe_ppc_state_t, r) + 8 * n, +// b.getInt64Ty()), locals_.gpr[n]); +// } +// } +// +// for (size_t n = 0; n < XECOUNT(locals_.fpr); n++) { +// if (locals_.fpr[n]) { +// b.CreateStore(LoadStateValue( +// (uint32_t)offsetof(xe_ppc_state_t, f) + 8 * n, +// b.getDoubleTy()), locals_.fpr[n]); +// } +// } +//} +// +//void LibjitEmitter::SpillRegisters() { +// // This flushes all local registers (if written) to the register bank and +// // resets their values. +// // +// // TODO(benvanik): only flush if actually required, or selective flushes. +// +// IRBuilder<>& b = *builder_; +// +// if (locals_.xer) { +// StoreStateValue( +// offsetof(xe_ppc_state_t, xer), +// b.getInt64Ty(), +// b.CreateLoad(locals_.xer)); +// } +// +// if (locals_.lr) { +// StoreStateValue( +// offsetof(xe_ppc_state_t, lr), +// b.getInt64Ty(), +// b.CreateLoad(locals_.lr)); +// } +// +// if (locals_.ctr) { +// StoreStateValue( +// offsetof(xe_ppc_state_t, ctr), +// b.getInt64Ty(), +// b.CreateLoad(locals_.ctr)); +// } +// +// // Stitch together all split CR values. +// // TODO(benvanik): don't flush across calls? +// Value* cr = NULL; +// for (size_t n = 0; n < XECOUNT(locals_.cr); n++) { +// Value* cr_n = locals_.cr[n]; +// if (!cr_n) { +// continue; +// } +// cr_n = b.CreateZExt(b.CreateLoad(cr_n), b.getInt64Ty()); +// if (!cr) { +// cr = b.CreateShl(cr_n, n * 4); +// } else { +// cr = b.CreateOr(cr, b.CreateShl(cr_n, n * 4)); +// } +// } +// if (cr) { +// StoreStateValue( +// offsetof(xe_ppc_state_t, cr), +// b.getInt64Ty(), +// cr); +// } +// +// for (uint32_t n = 0; n < XECOUNT(locals_.gpr); n++) { +// Value* v = locals_.gpr[n]; +// if (v) { +// StoreStateValue( +// offsetof(xe_ppc_state_t, r) + 8 * n, +// b.getInt64Ty(), +// b.CreateLoad(locals_.gpr[n])); +// } +// } +// +// for (uint32_t n = 0; n < XECOUNT(locals_.fpr); n++) { +// Value* v = locals_.fpr[n]; +// if (v) { +// StoreStateValue( +// offsetof(xe_ppc_state_t, f) + 8 * n, +// b.getDoubleTy(), +// b.CreateLoad(locals_.fpr[n])); +// } +// } +//} +// +//Value* LibjitEmitter::xer_value() { +// XEASSERTNOTNULL(locals_.xer); +// IRBuilder<>& b = *builder_; +// return b.CreateLoad(locals_.xer); +//} +// +//void LibjitEmitter::update_xer_value(Value* value) { +// XEASSERTNOTNULL(locals_.xer); +// IRBuilder<>& b = *builder_; +// +// // Extend to 64bits if needed. +// if (!value->getType()->isIntegerTy(64)) { +// value = b.CreateZExt(value, b.getInt64Ty()); +// } +// b.CreateStore(value, locals_.xer); +//} +// +//void LibjitEmitter::update_xer_with_overflow(Value* value) { +// XEASSERTNOTNULL(locals_.xer); +// IRBuilder<>& b = *builder_; +// +// // Expects a i1 indicating overflow. +// // Trust the caller that if it's larger than that it's already truncated. +// if (!value->getType()->isIntegerTy(64)) { +// value = b.CreateZExt(value, b.getInt64Ty()); +// } +// +// Value* xer = xer_value(); +// xer = b.CreateAnd(xer, 0xFFFFFFFFBFFFFFFF); // clear bit 30 +// xer = b.CreateOr(xer, b.CreateShl(value, 31)); +// xer = b.CreateOr(xer, b.CreateShl(value, 30)); +// b.CreateStore(xer, locals_.xer); +//} +// +//void LibjitEmitter::update_xer_with_carry(Value* value) { +// XEASSERTNOTNULL(locals_.xer); +// IRBuilder<>& b = *builder_; +// +// // Expects a i1 indicating carry. +// // Trust the caller that if it's larger than that it's already truncated. +// if (!value->getType()->isIntegerTy(64)) { +// value = b.CreateZExt(value, b.getInt64Ty()); +// } +// +// Value* xer = xer_value(); +// xer = b.CreateAnd(xer, 0xFFFFFFFFDFFFFFFF); // clear bit 29 +// xer = b.CreateOr(xer, b.CreateShl(value, 29)); +// b.CreateStore(xer, locals_.xer); +//} +// +//void LibjitEmitter::update_xer_with_overflow_and_carry(Value* value) { +// XEASSERTNOTNULL(locals_.xer); +// IRBuilder<>& b = *builder_; +// +// // Expects a i1 indicating overflow. +// // Trust the caller that if it's larger than that it's already truncated. +// if (!value->getType()->isIntegerTy(64)) { +// value = b.CreateZExt(value, b.getInt64Ty()); +// } +// +// // This is effectively an update_xer_with_overflow followed by an +// // update_xer_with_carry, but since the logic is largely the same share it. +// Value* xer = xer_value(); +// xer = b.CreateAnd(xer, 0xFFFFFFFF9FFFFFFF); // clear bit 30 & 29 +// xer = b.CreateOr(xer, b.CreateShl(value, 31)); +// xer = b.CreateOr(xer, b.CreateShl(value, 30)); +// xer = b.CreateOr(xer, b.CreateShl(value, 29)); +// b.CreateStore(xer, locals_.xer); +//} +// +//Value* LibjitEmitter::lr_value() { +// XEASSERTNOTNULL(locals_.lr); +// IRBuilder<>& b = *builder_; +// return b.CreateLoad(locals_.lr); +//} +// +//void LibjitEmitter::update_lr_value(Value* value) { +// XEASSERTNOTNULL(locals_.lr); +// IRBuilder<>& b = *builder_; +// +// // Extend to 64bits if needed. +// if (!value->getType()->isIntegerTy(64)) { +// value = b.CreateZExt(value, b.getInt64Ty()); +// } +// b.CreateStore(value, locals_.lr); +//} +// +//Value* LibjitEmitter::ctr_value() { +// XEASSERTNOTNULL(locals_.ctr); +// IRBuilder<>& b = *builder_; +// +// return b.CreateLoad(locals_.ctr); +//} +// +//void LibjitEmitter::update_ctr_value(Value* value) { +// XEASSERTNOTNULL(locals_.ctr); +// IRBuilder<>& b = *builder_; +// +// // Extend to 64bits if needed. +// if (!value->getType()->isIntegerTy(64)) { +// value = b.CreateZExt(value, b.getInt64Ty()); +// } +// b.CreateStore(value, locals_.ctr); +//} +// +//Value* LibjitEmitter::cr_value(uint32_t n) { +// XEASSERT(n >= 0 && n < 8); +// XEASSERTNOTNULL(locals_.cr[n]); +// IRBuilder<>& b = *builder_; +// +// Value* v = b.CreateLoad(locals_.cr[n]); +// v = b.CreateZExt(v, b.getInt64Ty()); +// return v; +//} +// +//void LibjitEmitter::update_cr_value(uint32_t n, Value* value) { +// XEASSERT(n >= 0 && n < 8); +// XEASSERTNOTNULL(locals_.cr[n]); +// IRBuilder<>& b = *builder_; +// +// // Truncate to 8 bits if needed. +// // TODO(benvanik): also widen? +// if (!value->getType()->isIntegerTy(8)) { +// value = b.CreateTrunc(value, b.getInt8Ty()); +// } +// +// b.CreateStore(value, locals_.cr[n]); +//} +// +//void LibjitEmitter::update_cr_with_cond( +// uint32_t n, Value* lhs, Value* rhs, bool is_signed) { +// IRBuilder<>& b = *builder_; +// +// // bit0 = RA < RB +// // bit1 = RA > RB +// // bit2 = RA = RB +// // bit3 = XER[SO] +// +// // TODO(benvanik): inline this using the x86 cmp instruction - this prevents +// // the need for a lot of the compares and ensures we lower to the best +// // possible x86. +// // Value* cmp = InlineAsm::get( +// // FunctionType::get(), +// // "cmp $0, $1 \n" +// // "mov from compare registers \n", +// // "r,r", ?? +// // true); +// +// Value* is_lt = is_signed ? +// b.CreateICmpSLT(lhs, rhs) : b.CreateICmpULT(lhs, rhs); +// Value* is_gt = is_signed ? +// b.CreateICmpSGT(lhs, rhs) : b.CreateICmpUGT(lhs, rhs); +// Value* cp = b.CreateSelect(is_gt, b.getInt8(1 << 1), b.getInt8(1 << 2)); +// Value* c = b.CreateSelect(is_lt, b.getInt8(1 << 0), cp); +// +// // TODO(benvanik): set bit 4 to XER[SO] +// +// // Insert the 4 bits into their location in the CR. +// update_cr_value(n, c); +//} +// +//Value* LibjitEmitter::gpr_value(uint32_t n) { +// XEASSERT(n >= 0 && n < 32); +// XEASSERTNOTNULL(locals_.gpr[n]); +// IRBuilder<>& b = *builder_; +// +// // Actually r0 is writable, even though nobody should ever do that. +// // Perhaps we can check usage and enable this if safe? +// // if (n == 0) { +// // // Always force zero to a constant - this should help LLVM. +// // return b.getInt64(0); +// // } +// +// return b.CreateLoad(locals_.gpr[n]); +//} +// +//void LibjitEmitter::update_gpr_value(uint32_t n, Value* value) { +// XEASSERT(n >= 0 && n < 32); +// XEASSERTNOTNULL(locals_.gpr[n]); +// IRBuilder<>& b = *builder_; +// +// // See above - r0 can be written. +// // if (n == 0) { +// // // Ignore writes to zero. +// // return; +// // } +// +// // Extend to 64bits if needed. +// if (!value->getType()->isIntegerTy(64)) { +// value = b.CreateZExt(value, b.getInt64Ty()); +// } +// +// b.CreateStore(value, locals_.gpr[n]); +//} +// +//Value* LibjitEmitter::fpr_value(uint32_t n) { +// XEASSERT(n >= 0 && n < 32); +// XEASSERTNOTNULL(locals_.fpr[n]); +// IRBuilder<>& b = *builder_; +// return b.CreateLoad(locals_.fpr[n]); +//} +// +//void LibjitEmitter::update_fpr_value(uint32_t n, Value* value) { +// XEASSERT(n >= 0 && n < 32); +// XEASSERTNOTNULL(locals_.fpr[n]); +// IRBuilder<>& b = *builder_; +// value = b.CreateFPExtOrFPTrunc(value, b.getDoubleTy()); +// b.CreateStore(value, locals_.fpr[n]); +//} +// +//Value* LibjitEmitter::GetMembase() { +// Value* v = gen_module_->getGlobalVariable("xe_memory_base"); +// return builder_->CreateLoad(v); +//} +// +//Value* LibjitEmitter::GetMemoryAddress(uint32_t cia, Value* addr) { +// IRBuilder<>& b = *builder_; +// +// // Input address is always in 32-bit space. +// addr = b.CreateAnd(addr, UINT_MAX); +// +// // Add runtime memory address checks, if needed. +// if (FLAGS_memory_address_verification) { +// BasicBlock* invalid_bb = BasicBlock::Create(*context_, "", gen_fn_); +// BasicBlock* valid_bb = BasicBlock::Create(*context_, "", gen_fn_); +// +// // The heap starts at 0x1000 - if we write below that we're boned. +// Value* gt = b.CreateICmpUGE(addr, b.getInt64(0x00001000)); +// b.CreateCondBr(gt, valid_bb, invalid_bb); +// +// b.SetInsertPoint(invalid_bb); +// Value* access_violation = gen_module_->getFunction("XeAccessViolation"); +// SpillRegisters(); +// b.CreateCall3(access_violation, +// gen_fn_->arg_begin(), +// b.getInt32(cia), +// addr); +// b.CreateBr(valid_bb); +// +// b.SetInsertPoint(valid_bb); +// } +// +// // Rebase off of memory base pointer. +// return b.CreateInBoundsGEP(GetMembase(), addr); +//} +// +//Value* LibjitEmitter::ReadMemory( +// uint32_t cia, Value* addr, uint32_t size, bool acquire) { +// IRBuilder<>& b = *builder_; +// +// Type* dataTy = NULL; +// bool needs_swap = false; +// switch (size) { +// case 1: +// dataTy = b.getInt8Ty(); +// break; +// case 2: +// dataTy = b.getInt16Ty(); +// needs_swap = true; +// break; +// case 4: +// dataTy = b.getInt32Ty(); +// needs_swap = true; +// break; +// case 8: +// dataTy = b.getInt64Ty(); +// needs_swap = true; +// break; +// default: +// XEASSERTALWAYS(); +// return NULL; +// } +// PointerType* pointerTy = PointerType::getUnqual(dataTy); +// +// Value* address = GetMemoryAddress(cia, addr); +// Value* ptr = b.CreatePointerCast(address, pointerTy); +// LoadInst* load_value = b.CreateLoad(ptr); +// if (acquire) { +// load_value->setAlignment(size); +// load_value->setVolatile(true); +// load_value->setAtomic(Acquire); +// } +// Value* value = load_value; +// +// // Swap after loading. +// // TODO(benvanik): find a way to avoid this! +// if (needs_swap) { +// Function* bswap = Intrinsic::getDeclaration( +// gen_module_, Intrinsic::bswap, dataTy); +// value = b.CreateCall(bswap, value); +// } +// +// return value; +//} +// +//void LibjitEmitter::WriteMemory( +// uint32_t cia, Value* addr, uint32_t size, Value* value, bool release) { +// IRBuilder<>& b = *builder_; +// +// Type* dataTy = NULL; +// bool needs_swap = false; +// switch (size) { +// case 1: +// dataTy = b.getInt8Ty(); +// break; +// case 2: +// dataTy = b.getInt16Ty(); +// needs_swap = true; +// break; +// case 4: +// dataTy = b.getInt32Ty(); +// needs_swap = true; +// break; +// case 8: +// dataTy = b.getInt64Ty(); +// needs_swap = true; +// break; +// default: +// XEASSERTALWAYS(); +// return; +// } +// PointerType* pointerTy = PointerType::getUnqual(dataTy); +// +// Value* address = GetMemoryAddress(cia, addr); +// Value* ptr = b.CreatePointerCast(address, pointerTy); +// +// // Truncate, if required. +// if (value->getType() != dataTy) { +// value = b.CreateTrunc(value, dataTy); +// } +// +// // Swap before storing. +// // TODO(benvanik): find a way to avoid this! +// if (needs_swap) { +// Function* bswap = Intrinsic::getDeclaration( +// gen_module_, Intrinsic::bswap, dataTy); +// value = b.CreateCall(bswap, value); +// } +// +// StoreInst* store_value = b.CreateStore(value, ptr); +// if (release) { +// store_value->setAlignment(size); +// store_value->setVolatile(true); +// store_value->setAtomic(Release); +// } +//} diff --git a/src/xenia/cpu/libjit/libjit_emitter.h b/src/xenia/cpu/libjit/libjit_emitter.h new file mode 100644 index 000000000..0a52378c1 --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_emitter.h @@ -0,0 +1,143 @@ +/** + ****************************************************************************** + * 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_LIBJIT_LIBJIT_EMITTER_H_ +#define XENIA_CPU_LIBJIT_LIBJIT_EMITTER_H_ + +#include +#include +#include + +#include + + +namespace xe { +namespace cpu { +namespace libjit { + + +class LibjitEmitter { +public: + LibjitEmitter(xe_memory_ref memory, jit_context_t context); + ~LibjitEmitter(); + + jit_context_t context(); + jit_type_t fn_signature(); + + int PrepareFunction(sdb::FunctionSymbol* symbol); + int MakeFunction(sdb::FunctionSymbol* symbol, jit_function_t fn); + + sdb::FunctionSymbol* fn(); + jit_function_t gen_fn(); + sdb::FunctionBlock* fn_block(); + + void PushInsertPoint(); + void PopInsertPoint(); + + void GenerateBasicBlocks(); +// llvm::BasicBlock* GetBasicBlock(uint32_t address); +// llvm::BasicBlock* GetNextBasicBlock(); +// llvm::BasicBlock* GetReturnBasicBlock(); + + int GenerateIndirectionBranch(uint32_t cia, jit_value_t target, + bool lk, bool likely_local); + + jit_value_t LoadStateValue(uint32_t offset, jit_type_t type, + const char* name = ""); + void StoreStateValue(uint32_t offset, jit_type_t type, jit_value_t value); + + jit_value_t cia_value(); + + jit_value_t SetupLocal(jit_type_t type, const char* name); + void FillRegisters(); + void SpillRegisters(); + + jit_value_t xer_value(); + void update_xer_value(jit_value_t value); + void update_xer_with_overflow(jit_value_t value); + void update_xer_with_carry(jit_value_t value); + void update_xer_with_overflow_and_carry(jit_value_t value); + + jit_value_t lr_value(); + void update_lr_value(jit_value_t value); + + jit_value_t ctr_value(); + void update_ctr_value(jit_value_t value); + + jit_value_t cr_value(uint32_t n); + void update_cr_value(uint32_t n, jit_value_t value); + void update_cr_with_cond(uint32_t n, jit_value_t lhs, jit_value_t rhs, + bool is_signed); + + jit_value_t gpr_value(uint32_t n); + void update_gpr_value(uint32_t n, jit_value_t value); + jit_value_t fpr_value(uint32_t n); + void update_fpr_value(uint32_t n, jit_value_t value); + + jit_value_t GetMembase(); + jit_value_t GetMemoryAddress(uint32_t cia, jit_value_t addr); + jit_value_t ReadMemory( + uint32_t cia, jit_value_t addr, uint32_t size, bool acquire = false); + void WriteMemory( + uint32_t cia, jit_value_t addr, uint32_t size, jit_value_t value, + bool release = false); + +private: + int MakeUserFunction(); + int MakePresentImportFunction(); + int MakeMissingImportFunction(); + + void GenerateSharedBlocks(); + int PrepareBasicBlock(sdb::FunctionBlock* block); + void GenerateBasicBlock(sdb::FunctionBlock* block); + void SetupLocals(); + + xe_memory_ref memory_; + jit_context_t context_; + GlobalExports global_exports_; + jit_type_t fn_signature_; + jit_type_t global_export_signature_; + + sdb::FunctionSymbol* fn_; + jit_function_t gen_fn_; + sdb::FunctionBlock* fn_block_; + // llvm::BasicBlock* return_block_; + // llvm::BasicBlock* internal_indirection_block_; + // llvm::BasicBlock* external_indirection_block_; + // llvm::BasicBlock* bb_; + + // std::vector > + // insert_points_; + + //std::map bbs_; + + // Address of the instruction being generated. + uint32_t cia_; + + ppc::InstrAccessBits access_bits_; + struct { + jit_value_t indirection_target; + jit_value_t indirection_cia; + + jit_value_t xer; + jit_value_t lr; + jit_value_t ctr; + jit_value_t cr[8]; + jit_value_t gpr[32]; + jit_value_t fpr[32]; + } locals_; +}; + + +} // namespace libjit +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LIBJIT_LIBJIT_EMITTER_H_ diff --git a/src/xenia/cpu/libjit/libjit_jit.cc b/src/xenia/cpu/libjit/libjit_jit.cc new file mode 100644 index 000000000..56f5ed68a --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_jit.cc @@ -0,0 +1,113 @@ +/** + ****************************************************************************** + * 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 + +#include +#include +#include + + +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::libjit; +using namespace xe::cpu::sdb; + + +LibjitJIT::LibjitJIT(xe_memory_ref memory, SymbolTable* sym_table) : + JIT(memory, sym_table), + context_(NULL), emitter_(NULL) { +} + +LibjitJIT::~LibjitJIT() { + delete emitter_; + if (context_) { + jit_context_destroy(context_); + } +} + +int LibjitJIT::Setup() { + int result_code = 1; + + // Shared libjit context. + context_ = jit_context_create(); + XEEXPECTNOTNULL(context_); + + // Create the emitter used to generate functions. + emitter_ = new LibjitEmitter(memory_, context_); + + // Inject global functions/variables/etc. + XEEXPECTZERO(InjectGlobals()); + + result_code = 0; +XECLEANUP: + return result_code; +} + +int LibjitJIT::InjectGlobals() { + // LLVMContext& context = *context_; + // const DataLayout* dl = engine_->getDataLayout(); + // Type* intPtrTy = dl->getIntPtrType(context); + // Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context)); + // GlobalVariable* gv; + + // // xe_memory_base + // // This is the base void* pointer to the memory space. + // gv = new GlobalVariable( + // *module_, + // int8PtrTy, + // true, + // GlobalValue::ExternalLinkage, + // 0, + // "xe_memory_base"); + // // Align to 64b - this makes SSE faster. + // gv->setAlignment(64); + // gv->setInitializer(ConstantExpr::getIntToPtr( + // ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)), + // int8PtrTy)); + + return 0; +} + +int LibjitJIT::InitModule(ExecModule* module) { + return 0; +} + +int LibjitJIT::UninitModule(ExecModule* module) { + return 0; +} + +int LibjitJIT::Execute(xe_ppc_state_t* ppc_state, FunctionSymbol* fn_symbol) { + XELOGCPU("Execute(%.8X): %s...", fn_symbol->start_address, fn_symbol->name()); + + // Check function. + jit_function_t jit_fn = (jit_function_t)fn_symbol->impl_value; + if (!jit_fn) { + // Function hasn't been prepped yet - prep it. + if (emitter_->PrepareFunction(fn_symbol)) { + XELOGCPU("Execute(%.8X): unable to make function %s", + fn_symbol->start_address, fn_symbol->name()); + return 1; + } + jit_fn = (jit_function_t)fn_symbol->impl_value; + XEASSERTNOTNULL(jit_fn); + } + + // TODO(benvanik): replace generic apply with special trampoline. + void* args[] = {&ppc_state, &ppc_state->lr}; + uint64_t return_value; + int apply_result = jit_function_apply(jit_fn, (void**)&args, &return_value); + if (apply_result) { + XELOGCPU("Execute(%.8X): apply failed with %d", + fn_symbol->start_address, apply_result); + return 1; + } + + return 0; +} diff --git a/src/xenia/cpu/libjit/libjit_jit.h b/src/xenia/cpu/libjit/libjit_jit.h new file mode 100644 index 000000000..27ef76799 --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_jit.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * 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_LIBJIT_LIBJIT_JIT_H_ +#define XENIA_CPU_LIBJIT_LIBJIT_JIT_H_ + +#include + +#include +#include +#include +#include + +#include + + +namespace xe { +namespace cpu { +namespace libjit { + + +class LibjitJIT : public JIT { +public: + LibjitJIT(xe_memory_ref memory, sdb::SymbolTable* sym_table); + virtual ~LibjitJIT(); + + virtual int Setup(); + + virtual int InitModule(ExecModule* module); + virtual int UninitModule(ExecModule* module); + + virtual int Execute(xe_ppc_state_t* ppc_state, + sdb::FunctionSymbol* fn_symbol); + +protected: + int InjectGlobals(); + + jit_context_t context_; + LibjitEmitter* emitter_; +}; + + +} // namespace libjit +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LIBJIT_LIBJIT_JIT_H_ diff --git a/src/xenia/cpu/libjit/libjit_library_loader.cc b/src/xenia/cpu/libjit/libjit_library_loader.cc new file mode 100644 index 000000000..83a3a35f5 --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_library_loader.cc @@ -0,0 +1,24 @@ +/** + ****************************************************************************** + * 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 + + +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::libjit; + + +LibjitLibraryLoader::LibjitLibraryLoader( + xe_memory_ref memory, kernel::ExportResolver* export_resolver) : + LibraryLoader(memory, export_resolver) { +} + +LibjitLibraryLoader::~LibjitLibraryLoader() { +} diff --git a/src/xenia/cpu/libjit/libjit_library_loader.h b/src/xenia/cpu/libjit/libjit_library_loader.h new file mode 100644 index 000000000..612913167 --- /dev/null +++ b/src/xenia/cpu/libjit/libjit_library_loader.h @@ -0,0 +1,37 @@ +/** + ****************************************************************************** + * 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_LIBJIT_LIBJIT_LIBRARY_LOADER_H_ +#define XENIA_CPU_LIBJIT_LIBJIT_LIBRARY_LOADER_H_ + +#include +#include + +#include + + +namespace xe { +namespace cpu { +namespace libjit { + + +class LibjitLibraryLoader : public LibraryLoader { +public: + LibjitLibraryLoader(xe_memory_ref memory, + kernel::ExportResolver* export_resolver); + virtual ~LibjitLibraryLoader(); +}; + + +} // namespace libjit +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LIBJIT_LIBJIT_LIBRARY_LOADER_H_ diff --git a/src/xenia/cpu/libjit/sources.gypi b/src/xenia/cpu/libjit/sources.gypi new file mode 100644 index 000000000..1fc277670 --- /dev/null +++ b/src/xenia/cpu/libjit/sources.gypi @@ -0,0 +1,18 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'libjit_backend.cc', + 'libjit_backend.h', + 'libjit_emit.h', + 'libjit_emit_alu.cc', + 'libjit_emit_control.cc', + 'libjit_emit_fpu.cc', + 'libjit_emit_memory.cc', + 'libjit_emitter.cc', + 'libjit_emitter.h', + 'libjit_jit.cc', + 'libjit_jit.h', + 'libjit_library_loader.cc', + 'libjit_library_loader.h', + ], +} diff --git a/src/xenia/cpu/llvmbe/llvm_backend.cc b/src/xenia/cpu/llvmbe/llvm_backend.cc index 97799d87d..f429db4c5 100644 --- a/src/xenia/cpu/llvmbe/llvm_backend.cc +++ b/src/xenia/cpu/llvmbe/llvm_backend.cc @@ -69,10 +69,6 @@ CodeUnitBuilder* LLVMBackend::CreateCodeUnitBuilder() { return NULL; } -LibraryLinker* LLVMBackend::CreateLibraryLinker() { - return NULL; -} - LibraryLoader* LLVMBackend::CreateLibraryLoader() { return NULL; } diff --git a/src/xenia/cpu/ppc/instr_tables.h b/src/xenia/cpu/ppc/instr_tables.h index c87156494..73659ba6e 100644 --- a/src/xenia/cpu/ppc/instr_tables.h +++ b/src/xenia/cpu/ppc/instr_tables.h @@ -21,7 +21,7 @@ namespace tables { static InstrType* instr_table_prep( InstrType* unprep, int unprep_count, int a, int b) { - int prep_count = pow(2.0, b - a + 1); + int prep_count = (int)pow(2, b - a + 1); InstrType* prep = (InstrType*)xe_calloc(prep_count * sizeof(InstrType)); for (int n = 0; n < unprep_count; n++) { int ordinal = XESELECTBITS(unprep[n].opcode, a, b); diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 178ece776..e6cc5d7d7 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -15,6 +15,7 @@ using namespace xe; using namespace xe::cpu; +using namespace xe::cpu::sdb; using namespace xe::kernel; @@ -43,7 +44,7 @@ namespace { Processor::Processor(xe_memory_ref memory, shared_ptr backend) : - fn_table_(NULL), jit_(NULL) { + sym_table_(NULL), jit_(NULL) { memory_ = xe_memory_retain(memory); backend_ = backend; @@ -63,7 +64,7 @@ Processor::~Processor() { modules_.clear(); delete jit_; - delete fn_table_; + delete sym_table_; export_resolver_.reset(); backend_.reset(); @@ -86,9 +87,9 @@ void Processor::set_export_resolver( int Processor::Setup() { XEASSERTNULL(jit_); - fn_table_ = new FunctionTable(); + sym_table_ = new SymbolTable(); - jit_ = backend_->CreateJIT(memory_, fn_table_); + jit_ = backend_->CreateJIT(memory_, sym_table_); if (jit_->Setup()) { XELOGE("Unable to create JIT"); return 1; @@ -125,7 +126,7 @@ int Processor::LoadRawBinary(const xechar_t* path, uint32_t start_address) { // This will analyze it, generate code (if needed), and adds methods to // the function table. exec_module = new ExecModule( - memory_, export_resolver_, fn_table_, name_a, path_a); + memory_, export_resolver_, sym_table_, name_a, path_a); XEEXPECTZERO(exec_module->PrepareRawBinary( start_address, start_address + (uint32_t)length)); @@ -151,7 +152,7 @@ int Processor::LoadXexModule(const char* name, const char* path, // This will analyze it, generate code (if needed), and adds methods to // the function table. ExecModule* exec_module = new ExecModule( - memory_, export_resolver_, fn_table_, name, path); + memory_, export_resolver_, sym_table_, name, path); XEEXPECTZERO(exec_module->PrepareXexModule(xex)); // Initialize the module and prepare it for execution. @@ -183,34 +184,30 @@ void Processor::DeallocThread(ThreadState* thread_state) { delete thread_state; } -FunctionPointer Processor::GenerateFunction(uint32_t address) { - // Search all modules for the function symbol. - // Each module will see if the address is within its code range and if the - // symbol is not found (likely) it will do analysis on it. - // TODO(benvanik): make this more efficient. Could use a binary search or - // something more clever. - sdb::FunctionSymbol* fn_symbol = NULL; - for (std::vector::iterator it = modules_.begin(); - it != modules_.end(); ++it) { - fn_symbol = (*it)->FindFunctionSymbol(address); - if (fn_symbol) { - break; +int Processor::Execute(ThreadState* thread_state, uint32_t address) { + // Attempt to grab the function symbol from the global lookup table. + FunctionSymbol* fn_symbol = sym_table_->GetFunction(address); + if (!fn_symbol) { + // Search all modules for the function symbol. + // Each module will see if the address is within its code range and if the + // symbol is not found (likely) it will do analysis on it. + // TODO(benvanik): make this more efficient. Could use a binary search or + // something more clever. + sdb::FunctionSymbol* fn_symbol = NULL; + for (std::vector::iterator it = modules_.begin(); + it != modules_.end(); ++it) { + fn_symbol = (*it)->FindFunctionSymbol(address); + if (fn_symbol) { + break; + } + } + if (!fn_symbol) { + // Symbol not found in any module. + XELOGCPU("Execute(%.8X): failed to find function", address); + return NULL; } } - if (!fn_symbol) { - return NULL; - } - // JIT the function. - FunctionPointer f = jit_->GenerateFunction(fn_symbol); - if (!f) { - return NULL; - } - - return f; -} - -int Processor::Execute(ThreadState* thread_state, uint32_t address) { xe_ppc_state_t* ppc_state = thread_state->ppc_state(); // This could be set to anything to give us a unique identifier to track @@ -220,25 +217,8 @@ int Processor::Execute(ThreadState* thread_state, uint32_t address) { // Setup registers. ppc_state->lr = lr; - // Find the function to execute. - FunctionPointer f = fn_table_->GetFunction(address); - - // JIT, if needed. - if (!f) { - f = this->GenerateFunction(address); - } - - // If JIT failed, die. - if (!f) { - XELOGCPU("Execute(%.8X): failed to find function", address); - return 1; - } - - // Execute the function pointer. - // Messes with the stack in such a way as to cause Xcode to behave oddly. - f(ppc_state, lr); - - return 0; + // Execute the function. + return jit_->Execute(ppc_state, fn_symbol); } uint64_t Processor::Execute(ThreadState* thread_state, uint32_t address, diff --git a/src/xenia/cpu/processor.h b/src/xenia/cpu/processor.h index c6bd7980e..53807cc21 100644 --- a/src/xenia/cpu/processor.h +++ b/src/xenia/cpu/processor.h @@ -16,8 +16,8 @@ #include #include -#include #include +#include #include #include @@ -50,14 +50,12 @@ public: uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t arg0); private: - FunctionPointer GenerateFunction(uint32_t address); - xe_memory_ref memory_; shared_ptr backend_; shared_ptr export_resolver_; - FunctionTable* fn_table_; - JIT* jit_; + sdb::SymbolTable* sym_table_; + JIT* jit_; std::vector modules_; }; diff --git a/src/xenia/cpu/sdb.h b/src/xenia/cpu/sdb.h index b29a11d11..24df9ec17 100644 --- a/src/xenia/cpu/sdb.h +++ b/src/xenia/cpu/sdb.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #endif // XENIA_CPU_SDB_H_ diff --git a/src/xenia/cpu/sdb/raw_symbol_database.cc b/src/xenia/cpu/sdb/raw_symbol_database.cc index ac594fd0c..9b4b1356d 100644 --- a/src/xenia/cpu/sdb/raw_symbol_database.cc +++ b/src/xenia/cpu/sdb/raw_symbol_database.cc @@ -22,8 +22,9 @@ using namespace xe::kernel; RawSymbolDatabase::RawSymbolDatabase( xe_memory_ref memory, ExportResolver* export_resolver, + SymbolTable* sym_table, uint32_t start_address, uint32_t end_address) : - SymbolDatabase(memory, export_resolver) { + SymbolDatabase(memory, export_resolver, sym_table) { start_address_ = start_address; end_address_ = end_address; } diff --git a/src/xenia/cpu/sdb/raw_symbol_database.h b/src/xenia/cpu/sdb/raw_symbol_database.h index b39609139..c6329aea6 100644 --- a/src/xenia/cpu/sdb/raw_symbol_database.h +++ b/src/xenia/cpu/sdb/raw_symbol_database.h @@ -22,6 +22,7 @@ class RawSymbolDatabase : public SymbolDatabase { public: RawSymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver, + SymbolTable* sym_table, uint32_t start_address, uint32_t end_address); virtual ~RawSymbolDatabase(); diff --git a/src/xenia/cpu/sdb/sources.gypi b/src/xenia/cpu/sdb/sources.gypi index ba19242e8..7e8254f7f 100644 --- a/src/xenia/cpu/sdb/sources.gypi +++ b/src/xenia/cpu/sdb/sources.gypi @@ -7,6 +7,8 @@ 'symbol.h', 'symbol_database.cc', 'symbol_database.h', + 'symbol_table.cc', + 'symbol_table.h', 'xex_symbol_database.cc', 'xex_symbol_database.h', ] diff --git a/src/xenia/cpu/sdb/symbol.cc b/src/xenia/cpu/sdb/symbol.cc index 23e20886b..9a3db0a12 100644 --- a/src/xenia/cpu/sdb/symbol.cc +++ b/src/xenia/cpu/sdb/symbol.cc @@ -57,7 +57,8 @@ FunctionSymbol::FunctionSymbol() : Symbol(Function), start_address(0), end_address(0), type(Unknown), flags(0), - kernel_export(0), ee(0) { + kernel_export(0), ee(0), + impl_value(NULL) { } FunctionSymbol::~FunctionSymbol() { diff --git a/src/xenia/cpu/sdb/symbol.h b/src/xenia/cpu/sdb/symbol.h index bfae74ca0..7aeb3833d 100644 --- a/src/xenia/cpu/sdb/symbol.h +++ b/src/xenia/cpu/sdb/symbol.h @@ -124,6 +124,10 @@ public: kernel::KernelExport* kernel_export; ExceptionEntrySymbol* ee; + // Implementation-specific value. This could be a JIT'ed function ref + // or some other structure. Never freed. + void* impl_value; + std::vector incoming_calls; std::vector outgoing_calls; std::vector variable_accesses; diff --git a/src/xenia/cpu/sdb/symbol_database.cc b/src/xenia/cpu/sdb/symbol_database.cc index 0ee569a84..eddcb1b73 100644 --- a/src/xenia/cpu/sdb/symbol_database.cc +++ b/src/xenia/cpu/sdb/symbol_database.cc @@ -24,9 +24,11 @@ using namespace xe::kernel; SymbolDatabase::SymbolDatabase(xe_memory_ref memory, - ExportResolver* export_resolver) { + ExportResolver* export_resolver, + SymbolTable* sym_table) { memory_ = xe_memory_retain(memory); export_resolver_ = export_resolver; + sym_table_ = sym_table; } SymbolDatabase::~SymbolDatabase() { @@ -150,7 +152,18 @@ FunctionSymbol* SymbolDatabase::GetFunction(uint32_t address) { if (i != symbols_.end() && i->second->symbol_type == Symbol::Function) { return static_cast(i->second); } - return NULL; + + // Missing function - analyze on demand. + // TODO(benvanik): track this for statistics. + FunctionSymbol* fn = new FunctionSymbol(); + fn->start_address = address; + function_count_++; + symbols_.insert(SymbolMap::value_type(address, fn)); + scan_queue_.push_back(fn); + + FlushQueue(); + + return fn; } VariableSymbol* SymbolDatabase::GetVariable(uint32_t address) { @@ -432,6 +445,9 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) { // - if present, flag function as needing a stack // - record prolog/epilog lengths/stack size/etc + // TODO(benvanik): queue for add without expensive locks? + sym_table_->AddFunction(fn->start_address, fn); + XELOGSDB("Finished analyzing %.8X", fn->start_address); return 0; } @@ -649,7 +665,7 @@ void SymbolDatabase::ReadMap(const char* file_name) { sstream >> std::ws; sstream >> type_str; - uint32_t addr = (uint32_t)strtol(addr_str.c_str(), NULL, 16); + uint32_t addr = (uint32_t)strtoul(addr_str.c_str(), NULL, 16); if (!addr) { continue; } diff --git a/src/xenia/cpu/sdb/symbol_database.h b/src/xenia/cpu/sdb/symbol_database.h index 45bcb65ba..5839e390f 100644 --- a/src/xenia/cpu/sdb/symbol_database.h +++ b/src/xenia/cpu/sdb/symbol_database.h @@ -18,6 +18,7 @@ #include #include +#include namespace xe { @@ -27,7 +28,8 @@ namespace sdb { class SymbolDatabase { public: - SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver); + SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver, + SymbolTable* sym_table); virtual ~SymbolDatabase(); virtual int Analyze(); @@ -63,6 +65,7 @@ protected: xe_memory_ref memory_; kernel::ExportResolver* export_resolver_; + SymbolTable* sym_table_; size_t function_count_; size_t variable_count_; SymbolMap symbols_; diff --git a/src/xenia/cpu/function_table.cc b/src/xenia/cpu/sdb/symbol_table.cc similarity index 53% rename from src/xenia/cpu/function_table.cc rename to src/xenia/cpu/sdb/symbol_table.cc index 1077d67cd..4d9100954 100644 --- a/src/xenia/cpu/function_table.cc +++ b/src/xenia/cpu/sdb/symbol_table.cc @@ -1,44 +1,32 @@ -/** - ****************************************************************************** - * 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 - - -using namespace xe; -using namespace xe::cpu; - - -FunctionTable::FunctionTable() { -} - -FunctionTable::~FunctionTable() { -} - -int FunctionTable::AddCodeRange(uint32_t low_address, uint32_t high_address) { - return 0; -} - -FunctionPointer FunctionTable::BeginAddFunction(uint32_t address) { - FunctionPointer ptr = map_[address]; - if (ptr) { - return ptr; - } - map_[address] = reinterpret_cast(0x1); - return NULL; -} - -int FunctionTable::AddFunction(uint32_t address, FunctionPointer ptr) { - map_[address] = ptr; - return 0; -} - -FunctionPointer FunctionTable::GetFunction(uint32_t address) { - FunctionMap::const_iterator it = map_.find(address); - return it != map_.end() ? it->second : NULL; -} +/** + ****************************************************************************** + * 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 + + +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::sdb; + + +SymbolTable::SymbolTable() { +} + +SymbolTable::~SymbolTable() { +} + +int SymbolTable::AddFunction(uint32_t address, FunctionSymbol* symbol) { + map_[address] = symbol; + return 0; +} + +FunctionSymbol* SymbolTable::GetFunction(uint32_t address) { + FunctionMap::const_iterator it = map_.find(address); + return it != map_.end() ? it->second : NULL; +} diff --git a/src/xenia/cpu/function_table.h b/src/xenia/cpu/sdb/symbol_table.h similarity index 53% rename from src/xenia/cpu/function_table.h rename to src/xenia/cpu/sdb/symbol_table.h index db0f56f2f..b3df9ec99 100644 --- a/src/xenia/cpu/function_table.h +++ b/src/xenia/cpu/sdb/symbol_table.h @@ -1,45 +1,42 @@ -/** - ****************************************************************************** - * 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_FUNCTION_TABLE_H_ -#define XENIA_CPU_FUNCTION_TABLE_H_ - -#include - -#include - - -namespace xe { -namespace cpu { - - -typedef void (*FunctionPointer)(xe_ppc_state_t*, uint64_t); - - -class FunctionTable { -public: - FunctionTable(); - ~FunctionTable(); - - int AddCodeRange(uint32_t low_address, uint32_t high_address); - FunctionPointer BeginAddFunction(uint32_t address); - int AddFunction(uint32_t address, FunctionPointer ptr); - FunctionPointer GetFunction(uint32_t address); - -private: - typedef std::tr1::unordered_map FunctionMap; - FunctionMap map_; -}; - - -} // namespace cpu -} // namespace xe - - -#endif // XENIA_CPU_FUNCTION_TABLE_H_ +/** + ****************************************************************************** + * 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_SDB_SYMBOL_TABLE_H_ +#define XENIA_CPU_SDB_SYMBOL_TABLE_H_ + +#include + +#include + + +namespace xe { +namespace cpu { +namespace sdb { + + +class SymbolTable { +public: + SymbolTable(); + ~SymbolTable(); + + int AddFunction(uint32_t address, sdb::FunctionSymbol* symbol); + sdb::FunctionSymbol* GetFunction(uint32_t address); + +private: + typedef std::tr1::unordered_map FunctionMap; + FunctionMap map_; +}; + + +} // namespace sdb +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_SDB_SYMBOL_TABLE_H_ diff --git a/src/xenia/cpu/sdb/xex_symbol_database.cc b/src/xenia/cpu/sdb/xex_symbol_database.cc index 8ca26f8fa..4220d8320 100644 --- a/src/xenia/cpu/sdb/xex_symbol_database.cc +++ b/src/xenia/cpu/sdb/xex_symbol_database.cc @@ -51,8 +51,9 @@ public: XexSymbolDatabase::XexSymbolDatabase( - xe_memory_ref memory, ExportResolver* export_resolver, xe_xex2_ref xex) : - SymbolDatabase(memory, export_resolver) { + xe_memory_ref memory, ExportResolver* export_resolver, + SymbolTable* sym_table, xe_xex2_ref xex) : + SymbolDatabase(memory, export_resolver, sym_table) { xex_ = xe_xex2_retain(xex); } diff --git a/src/xenia/cpu/sdb/xex_symbol_database.h b/src/xenia/cpu/sdb/xex_symbol_database.h index 060315109..4bbde3f45 100644 --- a/src/xenia/cpu/sdb/xex_symbol_database.h +++ b/src/xenia/cpu/sdb/xex_symbol_database.h @@ -24,7 +24,7 @@ class XexSymbolDatabase : public SymbolDatabase { public: XexSymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver, - xe_xex2_ref xex); + SymbolTable* sym_table, xe_xex2_ref xex); virtual ~XexSymbolDatabase(); virtual int Analyze(); diff --git a/src/xenia/cpu/sources.gypi b/src/xenia/cpu/sources.gypi index d96065515..9a61a71d0 100644 --- a/src/xenia/cpu/sources.gypi +++ b/src/xenia/cpu/sources.gypi @@ -2,14 +2,11 @@ { 'sources': [ 'backend.h', - 'code_unit_builder.h', 'cpu-private.h', 'cpu.cc', 'cpu.h', 'exec_module.cc', 'exec_module.h', - 'function_table.cc', - 'function_table.h', 'global_exports.cc', 'global_exports.h', 'jit.h', @@ -23,7 +20,7 @@ ], 'includes': [ - #'llvmbe/sources.gypi', + 'libjit/sources.gypi', 'ppc/sources.gypi', 'sdb/sources.gypi', ], diff --git a/third_party/libjit b/third_party/libjit index 833b8e9d9..542a478da 160000 --- a/third_party/libjit +++ b/third_party/libjit @@ -1 +1 @@ -Subproject commit 833b8e9d972cd410e800881e0e90a500c8541db0 +Subproject commit 542a478da976013a748f37e83825c95d45a965ec diff --git a/tools/xenia-run/xenia-run.cc b/tools/xenia-run/xenia-run.cc index 5f8542408..09753f861 100644 --- a/tools/xenia-run/xenia-run.cc +++ b/tools/xenia-run/xenia-run.cc @@ -46,7 +46,7 @@ int Run::Setup() { xe_zero_struct(&pal_options, sizeof(pal_options)); XEEXPECTZERO(xe_pal_init(pal_options)); - //backend_ = shared_ptr(new xe::cpu::llvmbe::LLVMBackend()); + backend_ = shared_ptr(new xe::cpu::libjit::LibjitBackend()); debugger_ = shared_ptr(new Debugger()); @@ -116,8 +116,6 @@ int xenia_run(int argc, xechar_t **argv) { result_code = run->Setup(); XEEXPECTZERO(result_code); - //xe_module_dump(run->module); - run->Launch(path); result_code = 0; diff --git a/tools/xenia-test/xenia-test.cc b/tools/xenia-test/xenia-test.cc index 8308a8e59..98bab1d50 100644 --- a/tools/xenia-test/xenia-test.cc +++ b/tools/xenia-test/xenia-test.cc @@ -120,7 +120,7 @@ int run_test(string& src_file_path) { memory = xe_memory_create(memory_options); XEEXPECTNOTNULL(memory); - //backend = shared_ptr(new xe::cpu::llvmbe::LLVMBackend()); + backend_ = shared_ptr(new xe::cpu::libjit::LibjitBackend()); processor = shared_ptr(new Processor(memory, backend)); XEEXPECTZERO(processor->Setup()); diff --git a/xenia-build.py b/xenia-build.py index d1b7a47c0..d16c30762 100755 --- a/xenia-build.py +++ b/xenia-build.py @@ -300,7 +300,7 @@ def run_gyp(format): '-f %s' % (format), # Set the VS version. # TODO(benvanik): allow user to set? - '-G msvs_version=2010', + '-G msvs_version=2012e', # Removes the out/ from ninja builds. '-G output_dir=.', '--depth=.',