diff --git a/TODO.md b/TODO.md index c45d1d007..00ba5c1f0 100644 --- a/TODO.md +++ b/TODO.md @@ -1,23 +1,13 @@ +refactor: + module gen + recompiler (move to cpu) +implement: + function table + exec_module FindFunctionSymbol - - -ExecModule: - Prepare(memory, export_resolver) - Init() - Uninit() - Execute(ppc_state, addr) - -JITExecModule: - -LibraryExecModule: - - -Processor::Execute(addr): - // TODO: faster search, if needed - for each exec_module: - if (exec_module->Execute(addr)) { - break; - } +jit: +- add imports/exports/etc to module +- function generator (thread safe) diff --git a/src/xenia/core/pal_mac.cc b/src/xenia/core/pal_mac.cc index 8bc3487f9..edcfef4aa 100644 --- a/src/xenia/core/pal_mac.cc +++ b/src/xenia/core/pal_mac.cc @@ -28,7 +28,7 @@ xe_pal_mac_t* pal; void xe_pal_dealloc(); int xe_pal_init(xe_pal_options_t options) { - pal = (xe_pal_mac_t)xe_calloc(sizeof(pal)); + pal = (xe_pal_mac_t*)xe_calloc(sizeof(pal)); mach_timebase_info_data_t info; mach_timebase_info(&info); diff --git a/src/xenia/cpu/backend.h b/src/xenia/cpu/backend.h new file mode 100644 index 000000000..0e1f28c47 --- /dev/null +++ b/src/xenia/cpu/backend.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * 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_BACKEND_H_ +#define XENIA_CPU_BACKEND_H_ + +#include + +#include + + +namespace xe { +namespace cpu { + + +class CodeUnitBuilder; +class FunctionTable; +class JIT; +class LibraryLinker; +class LibraryLoader; + + +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; + +protected: + Backend() {} +}; + + +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_BACKEND_H_ diff --git a/src/xenia/cpu/code_unit_builder.h b/src/xenia/cpu/code_unit_builder.h new file mode 100644 index 000000000..61603f03c --- /dev/null +++ b/src/xenia/cpu/code_unit_builder.h @@ -0,0 +1,51 @@ +/** + ****************************************************************************** + * 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/codegen/emit_memory.cc b/src/xenia/cpu/codegen/emit_memory.cc deleted file mode 100644 index 75b799b5e..000000000 --- a/src/xenia/cpu/codegen/emit_memory.cc +++ /dev/null @@ -1,1170 +0,0 @@ -/* - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include - -#include - - -using namespace llvm; -using namespace xe::cpu::codegen; -using namespace xe::cpu::ppc; - - -namespace xe { -namespace cpu { -namespace codegen { - - -// Integer load (A-13) - -XEEMITTER(lbz, 0x88000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 1, false); - g.update_gpr_value(i.D.RT, v); - - return 0; -} - -XEEMITTER(lbzu, 0x8C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // RT <- i56.0 || MEM(EA, 1) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.ReadMemory(i.address, ea, 1, false); - g.update_gpr_value(i.D.RT, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(lbzux, 0x7C0000EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // RT <- i56.0 || MEM(EA, 1) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.ReadMemory(i.address, ea, 1, false); - g.update_gpr_value(i.X.RT, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(lbzx, 0x7C0000AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // RT <- i56.0 || MEM(EA, 1) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 1, false); - g.update_gpr_value(i.X.RT, v); - - return 0; -} - -XEEMITTER(ld, 0xE8000000, DS )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.DS.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 8, false); - g.update_gpr_value(i.DS.RT, v); - - return 0; -} - -XEEMITTER(ldu, 0xE8000001, DS )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(DS || 0b00) - // RT <- MEM(EA, 8) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.DS.RA), - b.getInt64(XEEXTS16(i.DS.DS << 2))); - Value* v = g.ReadMemory(i.address, ea, 8, false); - g.update_gpr_value(i.DS.RT, v); - g.update_gpr_value(i.DS.RA, ea); - - return 0; -} - -XEEMITTER(ldux, 0x7C00006A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(ldx, 0x7C00002A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lha, 0xA8000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = b.CreateSExt(g.ReadMemory(i.address, ea, 2, false), - b.getInt64Ty()); - g.update_gpr_value(i.D.RT, v); - - return 0; -} - -XEEMITTER(lhau, 0xAC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lhaux, 0x7C0002EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lhax, 0x7C0002AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // RT <- EXTS(MEM(EA, 2)) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = b.CreateSExt(g.ReadMemory(i.address, ea, 2, false), - b.getInt64Ty()); - g.update_gpr_value(i.X.RT, v); - - return 0; -} - -XEEMITTER(lhz, 0xA0000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 2, false); - g.update_gpr_value(i.D.RT, v); - - return 0; -} - -XEEMITTER(lhzu, 0xA4000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // RT <- i48.0 || MEM(EA, 2) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.ReadMemory(i.address, ea, 2, false); - g.update_gpr_value(i.D.RT, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(lhzux, 0x7C00026E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // RT <- i48.0 || MEM(EA, 2) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.ReadMemory(i.address, ea, 2, false); - g.update_gpr_value(i.X.RT, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(lhzx, 0x7C00022E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // RT <- i48.0 || MEM(EA, 2) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 2, false); - g.update_gpr_value(i.X.RT, v); - - return 0; -} - -XEEMITTER(lwa, 0xE8000002, DS )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.DS.RA), ea); - } - Value* v = b.CreateSExt(g.ReadMemory(i.address, ea, 4, false), - b.getInt64Ty()); - g.update_gpr_value(i.DS.RT, v); - - return 0; -} - -XEEMITTER(lwaux, 0x7C0002EA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // RT <- EXTS(MEM(EA, 4)) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = b.CreateSExt(g.ReadMemory(i.address, ea, 4, false), - b.getInt64Ty()); - g.update_gpr_value(i.X.RT, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(lwax, 0x7C0002AA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // RT <- EXTS(MEM(EA, 4)) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = b.CreateSExt(g.ReadMemory(i.address, ea, 4, false), - b.getInt64Ty()); - g.update_gpr_value(i.X.RT, v); - - return 0; -} - -XEEMITTER(lwz, 0x80000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 4, false); - g.update_gpr_value(i.D.RT, v); - - return 0; -} - -XEEMITTER(lwzu, 0x84000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // RT <- i32.0 || MEM(EA, 4) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.ReadMemory(i.address, ea, 4, false); - g.update_gpr_value(i.D.RT, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(lwzux, 0x7C00006E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // RT <- i32.0 || MEM(EA, 4) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.ReadMemory(i.address, ea, 4, false); - g.update_gpr_value(i.X.RT, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(lwzx, 0x7C00002E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // RT <- i32.0 || MEM(EA, 4) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 4, false); - g.update_gpr_value(i.X.RT, v); - - return 0; -} - - -// Integer store (A-14) - -XEEMITTER(stb, 0x98000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.gpr_value(i.D.RT); - g.WriteMemory(i.address, ea, 1, v); - - return 0; -} - -XEEMITTER(stbu, 0x9C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // MEM(EA, 1) <- (RS)[56:63] - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.gpr_value(i.D.RT); - g.WriteMemory(i.address, ea, 1, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(stbux, 0x7C0001EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // MEM(EA, 1) <- (RS)[56:63] - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.gpr_value(i.X.RT); - g.WriteMemory(i.address, ea, 1, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(stbx, 0x7C0001AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // MEM(EA, 1) <- (RS)[56:63] - - Value* ea = g.gpr_value(i.X.RB); - if (i.D.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.gpr_value(i.X.RT); - g.WriteMemory(i.address, ea, 1, v); - - return 0; -} - -XEEMITTER(std, 0xF8000000, DS )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.DS.RA), ea); - } - Value* v = g.gpr_value(i.DS.RT); - g.WriteMemory(i.address, ea, 8, v); - - return 0; -} - -XEEMITTER(stdu, 0xF8000001, DS )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(DS || 0b00) - // MEM(EA, 8) <- (RS) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.DS.RA), - b.getInt64(XEEXTS16(i.DS.DS << 2))); - Value* v = g.gpr_value(i.DS.RT); - g.WriteMemory(i.address, ea, 8, v); - g.update_gpr_value(i.DS.RA, ea); - - return 0; -} - -XEEMITTER(stdux, 0x7C00016A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // MEM(EA, 8) <- (RS) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.gpr_value(i.X.RT); - g.WriteMemory(i.address, ea, 8, v); - - return 0; -} - -XEEMITTER(stdx, 0x7C00012A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // MEM(EA, 8) <- (RS) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.gpr_value(i.X.RT); - g.WriteMemory(i.address, ea, 8, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(sth, 0xB0000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.gpr_value(i.D.RT); - g.WriteMemory(i.address, ea, 2, v); - - return 0; -} - -XEEMITTER(sthu, 0xB4000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // MEM(EA, 2) <- (RS)[48:63] - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), - b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.gpr_value(i.D.RT); - g.WriteMemory(i.address, ea, 2, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(sthux, 0x7C00036E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // MEM(EA, 2) <- (RS)[48:63] - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.gpr_value(i.X.RT); - g.WriteMemory(i.address, ea, 2, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(sthx, 0x7C00032E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // MEM(EA, 2) <- (RS)[48:63] - - Value* ea = g.gpr_value(i.X.RB); - if (i.D.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.gpr_value(i.X.RT); - g.WriteMemory(i.address, ea, 2, v); - - return 0; -} - -XEEMITTER(stw, 0x90000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.gpr_value(i.D.RT); - g.WriteMemory(i.address, ea, 4, v); - - return 0; -} - -XEEMITTER(stwu, 0x94000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // MEM(EA, 4) <- (RS)[32:63] - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), - b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.gpr_value(i.D.RT); - g.WriteMemory(i.address, ea, 4, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(stwux, 0x7C00016E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // MEM(EA, 4) <- (RS)[32:63] - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.gpr_value(i.X.RT); - g.WriteMemory(i.address, ea, 4, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(stwx, 0x7C00012E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // MEM(EA, 4) <- (RS)[32:63] - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.gpr_value(i.X.RT); - g.WriteMemory(i.address, ea, 4, v); - - return 0; -} - - -// Integer load and store with byte reverse (A-1 - -XEEMITTER(lhbrx, 0x7C00062C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lwbrx, 0x7C00042C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(ldbrx, 0x7C000428, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(sthbrx, 0x7C00072C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stwbrx, 0x7C00052C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stdbrx, 0x7C000528, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - - -// Integer load and store multiple (A-16) - -XEEMITTER(lmw, 0xB8000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stmw, 0xBC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - - -// Integer load and store string (A-17) - -XEEMITTER(lswi, 0x7C0004AA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lswx, 0x7C00042A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stswi, 0x7C0005AA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stswx, 0x7C00052A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - - -// Memory synchronization (A-18) - -XEEMITTER(eieio, 0x7C0006AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(isync, 0x4C00012C, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(ldarx, 0x7C0000A8, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lwarx, 0x7C000028, X )(FunctionGenerator& g, IRBuilder<>& b, 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 = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 4, /* acquire */ true); - g.update_gpr_value(i.X.RT, v); - - return 0; -} - -XEEMITTER(stdcx, 0x7C0001AD, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stwcx, 0x7C00012D, X )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.gpr_value(i.D.RT); - g.WriteMemory(i.address, ea, 4, v, /* release */ true); - - // We always succeed. - g.update_cr_value(0, b.getInt64(1 << 2)); - - return 0; -} - -XEEMITTER(sync, 0x7C0004AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - - -// Floating-point load (A-19) - -XEEMITTER(lfd, 0xC8000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 8, false); - v = b.CreateBitCast(v, b.getDoubleTy()); - g.update_fpr_value(i.D.RT, v); - - return 0; -} - -XEEMITTER(lfdu, 0xCC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // FRT <- MEM(EA, 8) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.ReadMemory(i.address, ea, 8, false); - v = b.CreateBitCast(v, b.getDoubleTy()); - g.update_fpr_value(i.D.RT, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(lfdux, 0x7C0004EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // FRT <- MEM(EA, 8) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.ReadMemory(i.address, ea, 8, false); - v = b.CreateBitCast(v, b.getDoubleTy()); - g.update_fpr_value(i.X.RT, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(lfdx, 0x7C0004AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // FRT <- MEM(EA, 8) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 8, false); - v = b.CreateBitCast(v, b.getDoubleTy()); - g.update_fpr_value(i.X.RT, v); - - return 0; -} - -XEEMITTER(lfs, 0xC0000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 4, false); - v = b.CreateFPExt(b.CreateBitCast(v, b.getFloatTy()), b.getDoubleTy()); - g.update_fpr_value(i.D.RT, v); - - return 0; -} - -XEEMITTER(lfsu, 0xC4000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // FRT <- DOUBLE(MEM(EA, 4)) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.ReadMemory(i.address, ea, 4, false); - v = b.CreateFPExt(b.CreateBitCast(v, b.getFloatTy()), b.getDoubleTy()); - g.update_fpr_value(i.D.RT, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(lfsux, 0x7C00046E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // FRT <- DOUBLE(MEM(EA, 4)) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.ReadMemory(i.address, ea, 4, false); - v = b.CreateFPExt(b.CreateBitCast(v, b.getFloatTy()), b.getDoubleTy()); - g.update_fpr_value(i.X.RT, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(lfsx, 0x7C00042E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // FRT <- DOUBLE(MEM(EA, 4)) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.ReadMemory(i.address, ea, 4, false); - v = b.CreateFPExt(b.CreateBitCast(v, b.getFloatTy()), b.getDoubleTy()); - g.update_fpr_value(i.X.RT, v); - - return 0; -} - - -// Floating-point store (A-20) - -XEEMITTER(stfd, 0xD8000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.fpr_value(i.D.RT); - v = b.CreateBitCast(v, b.getInt64Ty()); - g.WriteMemory(i.address, ea, 8, v); - - return 0; -} - -XEEMITTER(stfdu, 0xDC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // MEM(EA, 8) <- (FRS) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), - b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.fpr_value(i.D.RT); - v = b.CreateBitCast(v, b.getInt64Ty()); - g.WriteMemory(i.address, ea, 8, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(stfdux, 0x7C0005EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // MEM(EA, 8) <- (FRS) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.fpr_value(i.X.RT); - v = b.CreateBitCast(v, b.getInt64Ty()); - g.WriteMemory(i.address, ea, 8, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(stfdx, 0x7C0005AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // MEM(EA, 8) <- (FRS) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.fpr_value(i.X.RT); - v = b.CreateBitCast(v, b.getInt64Ty()); - g.WriteMemory(i.address, ea, 8, v); - - return 0; -} - -XEEMITTER(stfiwx, 0x7C0007AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // MEM(EA, 4) <- (FRS)[32:63] - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.D.RA), ea); - } - Value* v = g.fpr_value(i.X.RT); - v = b.CreateBitCast(v, b.getInt64Ty()); - g.WriteMemory(i.address, ea, 4, v); - - return 0; -} - -XEEMITTER(stfs, 0xD0000000, D )(FunctionGenerator& g, IRBuilder<>& b, 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(g.gpr_value(i.D.RA), ea); - } - Value* v = g.fpr_value(i.D.RT); - v = b.CreateBitCast(b.CreateFPTrunc(v, b.getFloatTy()), b.getInt32Ty()); - g.WriteMemory(i.address, ea, 4, v); - - return 0; -} - -XEEMITTER(stfsu, 0xD4000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + EXTS(D) - // MEM(EA, 4) <- SINGLE(FRS) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.D.RA), - b.getInt64(XEEXTS16(i.D.DS))); - Value* v = g.fpr_value(i.D.RT); - v = b.CreateBitCast(b.CreateFPTrunc(v, b.getFloatTy()), b.getInt32Ty()); - g.WriteMemory(i.address, ea, 4, v); - g.update_gpr_value(i.D.RA, ea); - - return 0; -} - -XEEMITTER(stfsux, 0x7C00056E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // EA <- (RA) + (RB) - // MEM(EA, 4) <- SINGLE(FRS) - // RA <- EA - - Value* ea = b.CreateAdd(g.gpr_value(i.X.RA), g.gpr_value(i.X.RB)); - Value* v = g.fpr_value(i.X.RT); - v = b.CreateBitCast(b.CreateFPTrunc(v, b.getFloatTy()), b.getInt32Ty()); - g.WriteMemory(i.address, ea, 4, v); - g.update_gpr_value(i.X.RA, ea); - - return 0; -} - -XEEMITTER(stfsx, 0x7C00052E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // if RA = 0 then - // b <- 0 - // else - // b <- (RA) - // EA <- b + (RB) - // MEM(EA, 4) <- SINGLE(FRS) - - Value* ea = g.gpr_value(i.X.RB); - if (i.X.RA) { - ea = b.CreateAdd(g.gpr_value(i.X.RA), ea); - } - Value* v = g.fpr_value(i.X.RT); - v = b.CreateBitCast(b.CreateFPTrunc(v, b.getFloatTy()), b.getInt32Ty()); - g.WriteMemory(i.address, ea, 4, v); - - return 0; -} - - -// Cache management (A-27) - -XEEMITTER(dcbf, 0x7C0000AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(dcbst, 0x7C00006C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(dcbt, 0x7C00022C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // No-op for now. - // TODO(benvanik): use @llvm.prefetch - return 0; -} - -XEEMITTER(dcbtst, 0x7C0001EC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // No-op for now. - // TODO(benvanik): use @llvm.prefetch - return 0; -} - -XEEMITTER(dcbz, 0x7C0007EC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - // or dcbz128 0x7C2007EC - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(icbi, 0x7C0007AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - - -void RegisterEmitCategoryMemory() { - 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 codegen -} // namespace cpu -} // namespace xe diff --git a/src/xenia/cpu/codegen/module_generator.cc b/src/xenia/cpu/codegen/module_generator.cc index 70eb272ce..a2a1c0acd 100644 --- a/src/xenia/cpu/codegen/module_generator.cc +++ b/src/xenia/cpu/codegen/module_generator.cc @@ -28,96 +28,6 @@ #include #include - -using namespace llvm; -using namespace xe; -using namespace xe::cpu; -using namespace xe::cpu::codegen; -using namespace xe::cpu::sdb; -using namespace xe::kernel; - - -ModuleGenerator::ModuleGenerator( - xe_memory_ref memory, ExportResolver* export_resolver, - const char* module_name, const char* module_path, SymbolDatabase* sdb, - LLVMContext* context, Module* gen_module, ExecutionEngine* engine) { - memory_ = xe_memory_retain(memory); - export_resolver_ = export_resolver; - module_name_ = xestrdupa(module_name); - module_path_ = xestrdupa(module_path); - sdb_ = sdb; - context_ = context; - gen_module_ = gen_module; - engine_ = engine; - di_builder_ = NULL; -} - -ModuleGenerator::~ModuleGenerator() { - for (std::map::iterator it = - functions_.begin(); it != functions_.end(); ++it) { - delete it->second; - } - - delete di_builder_; - xe_free(module_path_); - xe_free(module_name_); - xe_memory_release(memory_); -} - -int ModuleGenerator::Generate() { - std::string error_message; - - // Setup a debug info builder. - // This is used when creating any debug info. We may want to go more - // fine grained than this, but for now it's something. - char dir[XE_MAX_PATH]; - XEIGNORE(xestrcpya(dir, XECOUNT(dir), module_path_)); - char* slash = xestrrchra(dir, '/'); - if (slash) { - *(slash + 1) = 0; - } - di_builder_ = new DIBuilder(*gen_module_); - di_builder_->createCompileUnit( - dwarf::DW_LANG_C99, //0x8010, - StringRef(module_name_), - StringRef(dir), - StringRef("xenia"), - true, - StringRef(""), - 0); - cu_ = (MDNode*)di_builder_->getCU(); - - // Add export wrappers. - // - - // Add all functions. - // We do two passes - the first creates the function signature and global - // value (so that we can call it), the second actually builds the function. - std::vector functions; - if (!sdb_->GetAllFunctions(functions)) { - XELOGI("Beginning prep of %ld functions...", functions.size()); - for (std::vector::iterator it = functions.begin(); - it != functions.end(); ++it) { - FunctionSymbol* fn = *it; - switch (fn->type) { - case FunctionSymbol::User: - PrepareFunction(fn); - break; - case FunctionSymbol::Kernel: - if (fn->kernel_export && fn->kernel_export->is_implemented) { - AddPresentImport(fn); - } else { - AddMissingImport(fn); - } - break; - default: - XEASSERTALWAYS(); - break; - } - } - XELOGI("Function prep complete"); - } - // Build out all the user functions. size_t n = 0; XELOGI("Beginning generation of %ld functions...", functions.size()); @@ -143,55 +53,6 @@ void ModuleGenerator::AddFunctionsToMap( } } -ModuleGenerator::CodegenFunction* ModuleGenerator::GetCodegenFunction( - uint32_t address) { - std::map::iterator it = functions_.find(address); - if (it != functions_.end()) { - return it->second; - } - return NULL; -} - -Function* ModuleGenerator::CreateFunctionDefinition(const char* name) { - Module* m = gen_module_; - LLVMContext& context = m->getContext(); - - std::vector args; - args.push_back(PointerType::getUnqual(Type::getInt8Ty(context))); - args.push_back(Type::getInt64Ty(context)); - Type* return_type = Type::getVoidTy(context); - - FunctionType* ft = FunctionType::get(return_type, - ArrayRef(args), false); - Function* f = cast(m->getOrInsertFunction( - StringRef(name), ft)); - f->setVisibility(GlobalValue::DefaultVisibility); - - // Indicate that the function will never be unwound with an exception. - // If we ever support native exception handling we may need to remove this. - f->doesNotThrow(); - - // May be worth trying the X86_FastCall, as we only need state in a register. - //f->setCallingConv(CallingConv::Fast); - f->setCallingConv(CallingConv::C); - - Function::arg_iterator fn_args = f->arg_begin(); - // 'state' - Value* fn_arg = fn_args++; - fn_arg->setName("state"); - f->setDoesNotAlias(1); - f->setDoesNotCapture(1); - // 'state' should try to be in a register, if possible. - // TODO(benvanik): verify that's a good idea. - // f->getArgumentList().begin()->addAttr( - // Attribute::get(context, AttrBuilder().addAttribute(Attribute::InReg))); - - // 'lr' - fn_arg = fn_args++; - fn_arg->setName("lr"); - - return f; -}; void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) { Module *m = gen_module_; @@ -288,48 +149,3 @@ void ModuleGenerator::AddPresentImport(FunctionSymbol* fn) { OptimizeFunction(m, f); } - -void ModuleGenerator::PrepareFunction(FunctionSymbol* fn) { - // Create the function (and setup args/attributes/etc). - Function* f = CreateFunctionDefinition(fn->name()); - - // Setup our codegen wrapper to keep all the pointers together. - CodegenFunction* cgf = new CodegenFunction(); - cgf->symbol = fn; - cgf->function_type = f->getFunctionType(); - cgf->function = f; - functions_.insert(std::pair( - fn->start_address, cgf)); -} - -void ModuleGenerator::BuildFunction(CodegenFunction* cgf) { - FunctionSymbol* fn = cgf->symbol; - - // Setup the generation context. - FunctionGenerator fgen( - memory_, sdb_, fn, context_, gen_module_, cgf->function); - - // Run through and generate each basic block. - fgen.GenerateBasicBlocks(); - - // Run the optimizer on the function. - // Doing this here keeps the size of the IR small and speeds up the later - // passes. - OptimizeFunction(gen_module_, cgf->function); -} - -void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) { - FunctionPassManager pm(m); - //fn->dump(); - if (FLAGS_optimize_ir_functions) { - PassManagerBuilder pmb; - pmb.OptLevel = 3; - pmb.SizeLevel = 0; - pmb.Inliner = createFunctionInliningPass(); - pmb.Vectorize = true; - pmb.LoopVectorize = true; - pmb.populateFunctionPassManager(pm); - } - pm.add(createVerifierPass()); - pm.run(*fn); -} diff --git a/src/xenia/cpu/codegen/recompiler.cc b/src/xenia/cpu/codegen/recompiler.cc new file mode 100644 index 000000000..f73505cd0 --- /dev/null +++ b/src/xenia/cpu/codegen/recompiler.cc @@ -0,0 +1,122 @@ +/** + ****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +using namespace llvm; +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::codegen; +using namespace xe::cpu::sdb; +using namespace xe::kernel; + + +Recompiler::Recompiler( + xe_memory_ref memory, shared_ptr export_resolver, + shared_ptr sdb, const char* module_name) { + memory_ = xe_memory_retain(memory); + export_resolver_ = export_resolver; + sdb_ = sdb; +} + +Recompiler::~Recompiler() { + xe_memory_release(memory_); +} + +int Recompiler::Process() { + // Check to see if a cached result exists on disk - if so, use it. + if (!LoadLibrary(library_path)) { + // Succeeded - done! + return 0; + } + + // Generate all the code and dump it to code units. + // This happens in multiple threads. + if (GenerateCodeUnits()) { + XELOGCPU("Failed to generate code units for module"); + return 1; + } + + // Link all of the generated code units. This runs any link-time optimizations + // and other per-library operations. + if (LinkCodeUnits()) { + XELOGCPU("Failed to link code units"); + return 1; + } + + // Load the built library now. + if (LoadLibrary(library_path)) { + XELOGCPU("Failed to load the generated library"); + return 1; + } + + return 0; +} + +int Recompiler::GenerateCodeUnits() { + xe_system_info sys_info; + XEEXPECTZERO(xe_pal_get_system_info(&sys_info)); + // sys_info.processors.physical_count; + // sys_info.processors.logical_count; + + // Queue up all functions to process. + + // Spawn worker threads to process the queue. + + // Wait until all threads complete. + + return 0; + +XECLEANUP: + return 1; +} + +int Recompiler::LinkCodeUnits() { + // Invoke linker. + + return 0; +} + +int Recompiler::LoadLibrary(const char* path) { + // Check file exists. + + // TODO(benvanik): version check somehow? + + // Load library. + + return 0; +} diff --git a/src/xenia/cpu/codegen/recompiler.h b/src/xenia/cpu/codegen/recompiler.h new file mode 100644 index 000000000..1c5977a98 --- /dev/null +++ b/src/xenia/cpu/codegen/recompiler.h @@ -0,0 +1,47 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_CPU_CODEGEN_RECOMPILER_H_ +#define XENIA_CPU_CODEGEN_RECOMPILER_H_ + +#include + +#include + + +namespace xe { +namespace cpu { +namespace codegen { + + +class Recompiler { +public: + Recompiler( + xe_memory_ref memory, shared_ptr export_resolver, + shared_ptr sdb, const char* module_name); + ~Recompiler(); + + int Process(); + +private: + int GenerateCodeUnits(); + int LinkCodeUnits(); + int LoadLibrary(const char* path); + + xechar_t* library_path_; +}; + + + +} // namespace codegen +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_CODEGEN_RECOMPILER_H_ diff --git a/src/xenia/cpu/codegen/sources.gypi b/src/xenia/cpu/codegen/sources.gypi deleted file mode 100644 index 476008df4..000000000 --- a/src/xenia/cpu/codegen/sources.gypi +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2013 Ben Vanik. All Rights Reserved. -{ - 'sources': [ - 'emit.h', - 'emit_alu.cc', - 'emit_control.cc', - 'emit_fpu.cc', - 'emit_memory.cc', - 'function_generator.cc', - 'function_generator.h', - 'module_generator.cc', - 'module_generator.h', - ], -} diff --git a/src/xenia/cpu/cpu.h b/src/xenia/cpu/cpu.h index 61014a386..c0c3724d4 100644 --- a/src/xenia/cpu/cpu.h +++ b/src/xenia/cpu/cpu.h @@ -12,4 +12,7 @@ #include +// TODO(benvanik): conditionally include? +#include + #endif // XENIA_CPU_CPU_H_ diff --git a/src/xenia/cpu/exec_module.cc b/src/xenia/cpu/exec_module.cc index 7fe5c397a..5f49d6ff3 100644 --- a/src/xenia/cpu/exec_module.cc +++ b/src/xenia/cpu/exec_module.cc @@ -9,67 +9,49 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include #include -#include -#include -#include -#include -using namespace llvm; using namespace xe; using namespace xe::cpu; -using namespace xe::cpu::codegen; using namespace xe::cpu::sdb; using namespace xe::kernel; ExecModule::ExecModule( xe_memory_ref memory, shared_ptr export_resolver, - const char* module_name, const char* module_path, - shared_ptr& engine) { + FunctionTable* fn_table, + const char* module_name, const char* module_path) { memory_ = xe_memory_retain(memory); export_resolver_ = export_resolver; + fn_table_ = fn_table; module_name_ = xestrdupa(module_name); module_path_ = xestrdupa(module_path); - engine_ = engine; - - context_ = shared_ptr(new LLVMContext()); } ExecModule::~ExecModule() { - if (gen_module_) { - Uninit(); - engine_->removeModule(gen_module_.get()); - } - xe_free(module_path_); xe_free(module_name_); xe_memory_release(memory_); } -int ExecModule::PrepareXex(xe_xex2_ref xex) { +SymbolDatabase* ExecModule::sdb() { + return sdb_.get(); +} + +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)); + + code_addr_low_ = start_address; + code_addr_high_ = end_address; + + return Prepare(); +} + +int ExecModule::PrepareXexModule(xe_xex2_ref xex) { sdb_ = shared_ptr( new sdb::XexSymbolDatabase(memory_, export_resolver_.get(), xex)); @@ -94,196 +76,45 @@ int ExecModule::PrepareXex(xe_xex2_ref xex) { return result_code; } - // Import variables. - // TODO?? - return 0; } -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)); - - code_addr_low_ = start_address; - code_addr_high_ = end_address; - - return Prepare(); -} - int ExecModule::Prepare() { int result_code = 1; - std::string error_message; - char file_name[XE_MAX_PATH]; - OwningPtr shared_module_buffer; - auto_ptr shared_module; - auto_ptr outs; + // Analyze the module and add its symbols to the symbol database. + // This always happens, even if we have a cached copy of the library, as + // we may end up needing this information later. + // TODO(benvanik): see how much memory this is using - it may be worth + // dropping and keeping around a smaller structure for future lookups + // instead. + XEEXPECTZERO(sdb_->Analyze()); - PassManager pm; - PassManagerBuilder pmb; - - // TODO(benvanik): embed the bc file into the emulator. - const char *thunk_path = "src/xenia/cpu/xethunk/xethunk.bc"; - - // Calculate a cache path based on the module, the CPU version, and other - // bits. - // TODO(benvanik): cache path calculation. - //const char *cache_path = "build/generated.bc"; - - // Check the cache to see if the bitcode exists. - // If it does, load that module directly. In the future we could also cache - // on linked binaries but that requires more safety around versioning. - // TODO(benvanik): check cache for module bitcode and load. - // if (path_exists(cache_key)) { - // exec_module = load_bitcode(cache_key); - // sdb = load_symbol_table(cache_key); - // } - - // If not found in cache, generate a new module. - if (!gen_module_.get()) { - // Load shared bitcode files. - // These contain globals and common thunk code that are used by the - // generated code. - XEEXPECTZERO(MemoryBuffer::getFile(thunk_path, shared_module_buffer)); - shared_module = auto_ptr(ParseBitcodeFile( - &*shared_module_buffer, *context_, &error_message)); - XEEXPECTNOTNULL(shared_module.get()); - - // Analyze the module and add its symbols to the symbol database. - XEEXPECTZERO(sdb_->Analyze()); - - // Load a specified module map and diff. - if (FLAGS_load_module_map.size()) { - sdb_->ReadMap(FLAGS_load_module_map.c_str()); - } - - // Dump the symbol database. - if (FLAGS_dump_module_map) { - xesnprintfa(file_name, XECOUNT(file_name), - "%s%s.map", FLAGS_dump_path.c_str(), module_name_); - sdb_->WriteMap(file_name); - } - - // Initialize the module. - gen_module_ = shared_ptr( - new Module(module_name_, *context_.get())); - // TODO(benavnik): addModuleFlag? - - // Inject globals. - // This should be done ASAP to ensure that JITed functions can use the - // constant addresses. - XEEXPECTZERO(InjectGlobals()); - - // Link shared module into generated module. - // This gives us a single module that we can optimize and prevents the need - // for foreward declarations. - Linker::LinkModules(gen_module_.get(), shared_module.get(), 0, - &error_message); - - // Build the module from the source code. - codegen_ = auto_ptr(new ModuleGenerator( - memory_, export_resolver_.get(), module_name_, module_path_, - sdb_.get(), context_.get(), gen_module_.get(), - engine_.get())); - XEEXPECTZERO(codegen_->Generate()); - - // Write to cache. - // TODO(benvanik): cache stuff - - // Dump pre-optimized module to disk. - if (FLAGS_dump_module_bitcode) { - xesnprintfa(file_name, XECOUNT(file_name), - "%s%s-preopt.bc", FLAGS_dump_path.c_str(), module_name_); - outs = auto_ptr(new raw_fd_ostream( - file_name, error_message, raw_fd_ostream::F_Binary)); - XEEXPECTTRUE(error_message.empty()); - WriteBitcodeToFile(gen_module_.get(), *outs); - } + // Load a specified module map and diff. + if (FLAGS_load_module_map.size()) { + sdb_->ReadMap(FLAGS_load_module_map.c_str()); } - // Link optimizations. - XEEXPECTZERO(gen_module_->MaterializeAllPermanently(&error_message)); - - // Reset target triple (ignore what's in xethunk). - gen_module_->setTargetTriple(llvm::sys::getDefaultTargetTriple()); - - // Run full module optimizations. - pm.add(new DataLayout(gen_module_.get())); - if (FLAGS_optimize_ir_modules) { - pm.add(createVerifierPass()); - pmb.OptLevel = 3; - pmb.SizeLevel = 0; - pmb.Inliner = createFunctionInliningPass(); - pmb.Vectorize = true; - pmb.LoopVectorize = true; - pmb.populateModulePassManager(pm); - pmb.populateLTOPassManager(pm, false, true); - } - pm.add(createVerifierPass()); - pm.run(*gen_module_); - - // Dump post-optimized module to disk. - if (FLAGS_optimize_ir_modules && FLAGS_dump_module_bitcode) { + // Dump the symbol database. + if (FLAGS_dump_module_map) { xesnprintfa(file_name, XECOUNT(file_name), - "%s%s.bc", FLAGS_dump_path.c_str(), module_name_); - outs = auto_ptr(new raw_fd_ostream( - file_name, error_message, raw_fd_ostream::F_Binary)); - XEEXPECTTRUE(error_message.empty()); - WriteBitcodeToFile(gen_module_.get(), *outs); + "%s%s.map", FLAGS_dump_path.c_str(), module_name_); + sdb_->WriteMap(file_name); } - // TODO(benvanik): experiment with LLD to see if we can write out a dll. + // If recompiling, setup a recompiler and run. + // Note that this will just load the library if it's present and valid. + // TODO(benvanik): recompiler logic. // Initialize the module. XEEXPECTZERO(Init()); - // Force JIT of all functions. - // for (Module::iterator it = gen_module_->begin(); it != gen_module_->end(); - // ++it) { - // Function* fn = it; - // if (!fn->isDeclaration()) { - // engine_->getPointerToFunction(fn); - // } - // } - result_code = 0; XECLEANUP: return result_code; } -void ExecModule::AddFunctionsToMap(FunctionMap& map) { - codegen_->AddFunctionsToMap(map); -} - -int ExecModule::InjectGlobals() { - LLVMContext& context = *context_.get(); - 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( - *gen_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)); - - SetupLlvmExports(gen_module_.get(), dl, engine_.get()); - - return 0; -} - int ExecModule::Init() { // Setup all kernel variables. std::vector variables; @@ -317,27 +148,11 @@ int ExecModule::Init() { } } - // Run static initializers. I'm not sure we'll have any, but who knows. - engine_->runStaticConstructorsDestructors(gen_module_.get(), false); - - // Grab the init function and call it. - Function* xe_module_init = gen_module_->getFunction("xe_module_init"); - std::vector args; - GenericValue ret = engine_->runFunction(xe_module_init, args); - - return static_cast(ret.IntVal.getSExtValue()); + return 0; } -int ExecModule::Uninit() { - // Grab function and call it. - Function* xe_module_uninit = gen_module_->getFunction("xe_module_uninit"); - std::vector args; - engine_->runFunction(xe_module_uninit, args); - - // Run static destructors. - engine_->runStaticConstructorsDestructors(gen_module_.get(), true); - - return 0; +FunctionSymbol* ExecModule::FindFunctionSymbol(uint32_t address) { + return sdb_->GetFunction(address); } void ExecModule::Dump() { diff --git a/src/xenia/cpu/exec_module.h b/src/xenia/cpu/exec_module.h index 40023485c..509da2374 100644 --- a/src/xenia/cpu/exec_module.h +++ b/src/xenia/cpu/exec_module.h @@ -13,68 +13,46 @@ #include #include +#include #include #include #include -namespace llvm { - class ExecutionEngine; - class Function; - class LLVMContext; - class Module; -} - namespace xe { namespace cpu { -namespace codegen { - class ModuleGenerator; -} -} -} - - -namespace xe { -namespace cpu { - - -typedef std::tr1::unordered_map FunctionMap; class ExecModule { public: ExecModule( xe_memory_ref memory, shared_ptr export_resolver, - const char* module_name, const char* module_path, - shared_ptr& engine); + FunctionTable* fn_table, + const char* module_name, const char* module_path); ~ExecModule(); - int PrepareXex(xe_xex2_ref xex); - int PrepareRawBinary(uint32_t start_address, uint32_t end_address); + sdb::SymbolDatabase* sdb(); - void AddFunctionsToMap(FunctionMap& map); + int PrepareRawBinary(uint32_t start_address, uint32_t end_address); + int PrepareXexModule(xe_xex2_ref xex); + + sdb::FunctionSymbol* FindFunctionSymbol(uint32_t address); void Dump(); private: int Prepare(); - int InjectGlobals(); int Init(); - int Uninit(); xe_memory_ref memory_; shared_ptr export_resolver_; + FunctionTable* fn_table_; char* module_name_; char* module_path_; - shared_ptr engine_; - shared_ptr sdb_; - shared_ptr context_; - shared_ptr gen_module_; - auto_ptr codegen_; + shared_ptr sdb_; uint32_t code_addr_low_; uint32_t code_addr_high_; - FunctionMap fns_; }; diff --git a/src/xenia/cpu/function_table.cc b/src/xenia/cpu/function_table.cc new file mode 100644 index 000000000..1077d67cd --- /dev/null +++ b/src/xenia/cpu/function_table.cc @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * 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; +} diff --git a/src/xenia/cpu/function_table.h b/src/xenia/cpu/function_table.h new file mode 100644 index 000000000..db0f56f2f --- /dev/null +++ b/src/xenia/cpu/function_table.h @@ -0,0 +1,45 @@ +/** + ****************************************************************************** + * 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_ diff --git a/src/xenia/cpu/global_exports.cc b/src/xenia/cpu/global_exports.cc new file mode 100644 index 000000000..cb49b088c --- /dev/null +++ b/src/xenia/cpu/global_exports.cc @@ -0,0 +1,105 @@ +/** + ****************************************************************************** + * 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 +#include + + +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::sdb; +using namespace xe::kernel; + + +namespace { + + +void XeTrap(xe_ppc_state_t* state, uint32_t cia) { + XELOGE("TRAP"); + XEASSERTALWAYS(); +} + +void XeIndirectBranch(xe_ppc_state_t* state, uint64_t target, uint64_t br_ia) { + 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) { + ppc::InstrData i; + i.address = cia; + i.code = data; + i.type = ppc::GetInstrType(i.code); + + if (!i.type) { + XELOGCPU("INVALID INSTRUCTION %.8X: %.8X ???", + i.address, i.code); + } else if (i.type->disassemble) { + ppc::InstrDisasm d; + i.type->disassemble(i, d); + std::string disasm; + d.Dump(disasm); + XELOGCPU("INVALID INSTRUCTION %.8X: %.8X %s", + i.address, i.code, disasm.c_str()); + } else { + XELOGCPU("INVALID INSTRUCTION %.8X: %.8X %s", + i.address, i.code, i.type->name); + } +} + +void XeAccessViolation(xe_ppc_state_t* state, uint32_t cia, uint64_t ea) { + 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) { + 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) { + 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) { + ppc::InstrType* type = ppc::GetInstrType(data); + XELOGCPU("TRACE: %.8X %.8X %s %s", + cia, data, + type && type->emit ? " " : "X", + type ? type->name : ""); + + // if (cia == 0x82014468) { + // printf("BREAKBREAKBREAK\n"); + // } + + // TODO(benvanik): better disassembly, printing of current register values/etc +} + + +} + + +void xe::cpu::GetGlobalExports(GlobalExports* global_exports) { + global_exports->XeTrap = XeTrap; + global_exports->XeIndirectBranch = XeIndirectBranch; + global_exports->XeInvalidInstruction = XeInvalidInstruction; + global_exports->XeAccessViolation = XeAccessViolation; + global_exports->XeTraceKernelCall = XeTraceKernelCall; + global_exports->XeTraceUserCall = XeTraceUserCall; + global_exports->XeTraceInstruction = XeTraceInstruction; +} diff --git a/src/xenia/cpu/global_exports.h b/src/xenia/cpu/global_exports.h new file mode 100644 index 000000000..a8f19c05e --- /dev/null +++ b/src/xenia/cpu/global_exports.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * 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_GLOBAL_EXPORTS_H_ +#define XENIA_CPU_GLOBAL_EXPORTS_H_ + +#include +#include + +#include +#include +#include + + +namespace xe { +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)( + xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, + kernel::KernelExport* kernel_export); + void (*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); +} GlobalExports; + + +void GetGlobalExports(GlobalExports* global_exports); + + +} // cpu +} // xe + + +#endif // XENIA_CPU_GLOBAL_EXPORTS_H_ diff --git a/src/xenia/cpu/jit.h b/src/xenia/cpu/jit.h new file mode 100644 index 000000000..2102210d9 --- /dev/null +++ b/src/xenia/cpu/jit.h @@ -0,0 +1,55 @@ +/** + ****************************************************************************** + * 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_JIT_H_ +#define XENIA_CPU_JIT_H_ + +#include + +#include +#include +#include + + +namespace xe { +namespace cpu { + + +class ExecModule; + + +class JIT { +public: + virtual ~JIT() { + xe_memory_release(memory_); + } + + virtual int Setup() = 0; + + virtual int InitModule(ExecModule* module) = 0; + virtual int UninitModule(ExecModule* module) = 0; + + virtual FunctionPointer GenerateFunction(sdb::FunctionSymbol* symbol) = 0; + +protected: + JIT(xe_memory_ref memory, FunctionTable* fn_table) { + memory_ = xe_memory_retain(memory); + fn_table_ = fn_table; + } + + xe_memory_ref memory_; + FunctionTable* fn_table_; +}; + + +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_JIT_H_ diff --git a/src/xenia/cpu/library_linker.h b/src/xenia/cpu/library_linker.h new file mode 100644 index 000000000..3c3b171f6 --- /dev/null +++ b/src/xenia/cpu/library_linker.h @@ -0,0 +1,46 @@ +/** + ****************************************************************************** + * 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_LIBRARY_LINKER_H_ +#define XENIA_CPU_LIBRARY_LINKER_H_ + +#include +#include + +#include +#include + + +namespace xe { +namespace cpu { + + +class LibraryLinker { +public: + virtual ~LibraryLinker() { + xe_memory_release(memory_); + } + +protected: + LibraryLinker(xe_memory_ref memory, + kernel::ExportResolver* export_resolver) { + memory_ = xe_memory_retain(memory); + export_resolver_ = export_resolver; + } + + xe_memory_ref memory_; + kernel::ExportResolver* export_resolver_; +}; + + +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LIBRARY_LINKER_H_ diff --git a/src/xenia/cpu/library_loader.h b/src/xenia/cpu/library_loader.h new file mode 100644 index 000000000..b25ff631c --- /dev/null +++ b/src/xenia/cpu/library_loader.h @@ -0,0 +1,46 @@ +/** + ****************************************************************************** + * 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_LIBRARY_LOADER_H_ +#define XENIA_CPU_LIBRARY_LOADER_H_ + +#include +#include + +#include +#include + + +namespace xe { +namespace cpu { + + +class LibraryLoader { +public: + virtual ~LibraryLoader() { + xe_memory_release(memory_); + } + +protected: + LibraryLoader(xe_memory_ref memory, + kernel::ExportResolver* export_resolver) { + memory_ = xe_memory_retain(memory); + export_resolver_ = export_resolver; + } + + xe_memory_ref memory_; + kernel::ExportResolver* export_resolver_; +}; + + +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LIBRARY_LOADER_H_ diff --git a/src/xenia/cpu/codegen/emit.h b/src/xenia/cpu/llvmbe/emit.h similarity index 86% rename from src/xenia/cpu/codegen/emit.h rename to src/xenia/cpu/llvmbe/emit.h index 6f489dee4..f1b8a322e 100644 --- a/src/xenia/cpu/codegen/emit.h +++ b/src/xenia/cpu/llvmbe/emit.h @@ -7,15 +7,15 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_CODEGEN_EMIT_H_ -#define XENIA_CPU_CODEGEN_EMIT_H_ +#ifndef XENIA_CPU_LLVMBE_EMIT_H_ +#define XENIA_CPU_LLVMBE_EMIT_H_ #include namespace xe { namespace cpu { -namespace codegen { +namespace llvmbe { void RegisterEmitCategoryALU(); @@ -33,9 +33,9 @@ void RegisterEmitCategoryMemory(); //#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS -} // namespace codegen +} // namespace llvmbe } // namespace cpu } // namespace xe -#endif // XENIA_CPU_CODEGEN_EMIT_H_ +#endif // XENIA_CPU_LLVMBE_EMIT_H_ diff --git a/src/xenia/cpu/codegen/emit_alu.cc b/src/xenia/cpu/llvmbe/emit_alu.cc similarity index 55% rename from src/xenia/cpu/codegen/emit_alu.cc rename to src/xenia/cpu/llvmbe/emit_alu.cc index 74f91cdce..a6fb39293 100644 --- a/src/xenia/cpu/codegen/emit_alu.cc +++ b/src/xenia/cpu/llvmbe/emit_alu.cc @@ -7,26 +7,26 @@ ****************************************************************************** */ -#include +#include #include -#include +#include using namespace llvm; -using namespace xe::cpu::codegen; +using namespace xe::cpu; using namespace xe::cpu::ppc; namespace xe { namespace cpu { -namespace codegen { +namespace llvmbe { // Integer arithmetic (A-3) -XEEMITTER(addx, 0x7C000214, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(addx, 0x7C000214, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RD <- (RA) + (RB) if (i.XO.OE) { @@ -34,44 +34,44 @@ XEEMITTER(addx, 0x7C000214, XO )(FunctionGenerator& g, IRBuilder<>& b, I // This is a different codepath as we need to use llvm.sadd.with.overflow. Function* sadd_with_overflow = Intrinsic::getDeclaration( - g.gen_module(), Intrinsic::sadd_with_overflow, b.getInt64Ty()); + e.gen_module(), Intrinsic::sadd_with_overflow, b.getInt64Ty()); Value* v = b.CreateCall2(sadd_with_overflow, - g.gpr_value(i.XO.RA), g.gpr_value(i.XO.RB)); + e.gpr_value(i.XO.RA), e.gpr_value(i.XO.RB)); Value* v0 = b.CreateExtractValue(v, 0); - g.update_gpr_value(i.XO.RT, v0); - g.update_xer_with_overflow(b.CreateExtractValue(v, 1)); + e.update_gpr_value(i.XO.RT, v0); + e.update_xer_with_overflow(b.CreateExtractValue(v, 1)); if (i.XO.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v0, b.getInt64(0), true); + e.update_cr_with_cond(0, v0, b.getInt64(0), true); } return 0; } else { // No OE bit setting. - Value* v = b.CreateAdd(g.gpr_value(i.XO.RA), g.gpr_value(i.XO.RB)); - g.update_gpr_value(i.XO.RT, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } } -XEEMITTER(addcx, 0x7C000014, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(addcx, 0x7C000014, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addex, 0x7C000114, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(addex, 0x7C000114, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addi, 0x38000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(addi, 0x38000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if RA = 0 then // RT <- EXTS(SI) // else @@ -79,32 +79,32 @@ XEEMITTER(addi, 0x38000000, D )(FunctionGenerator& g, IRBuilder<>& b, I Value* v = b.getInt64(XEEXTS16(i.D.DS)); if (i.D.RA) { - v = b.CreateAdd(g.gpr_value(i.D.RA), v); + v = b.CreateAdd(e.gpr_value(i.D.RA), v); } - g.update_gpr_value(i.D.RT, v); + e.update_gpr_value(i.D.RT, v); return 0; } -XEEMITTER(addic, 0x30000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(addic, 0x30000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RT <- (RA) + EXTS(SI) Function* sadd_with_overflow = Intrinsic::getDeclaration( - g.gen_module(), Intrinsic::sadd_with_overflow, b.getInt64Ty()); + e.gen_module(), Intrinsic::sadd_with_overflow, b.getInt64Ty()); Value* v = b.CreateCall2(sadd_with_overflow, - g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); - g.update_gpr_value(i.D.RT, b.CreateExtractValue(v, 0)); - g.update_xer_with_carry(b.CreateExtractValue(v, 1)); + 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 )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(addicx, 0x34000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addis, 0x3C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(addis, 0x3C000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if RA = 0 then // RT <- EXTS(SI) || i16.0 // else @@ -112,55 +112,55 @@ XEEMITTER(addis, 0x3C000000, D )(FunctionGenerator& g, IRBuilder<>& b, I Value* v = b.getInt64(XEEXTS16(i.D.DS) << 16); if (i.D.RA) { - v = b.CreateAdd(g.gpr_value(i.D.RA), v); + v = b.CreateAdd(e.gpr_value(i.D.RA), v); } - g.update_gpr_value(i.D.RT, v); + e.update_gpr_value(i.D.RT, v); return 0; } -XEEMITTER(addmex, 0x7C0001D4, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(addmex, 0x7C0001D4, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addzex, 0x7C000194, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(addzex, 0x7C000194, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RT <- (RA) + CA Function* sadd_with_overflow = Intrinsic::getDeclaration( - g.gen_module(), Intrinsic::sadd_with_overflow, b.getInt64Ty()); - Value* ca = b.CreateAnd(b.CreateLShr(g.xer_value(), 29), 0x1); + 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, - g.gpr_value(i.XO.RA), ca); + e.gpr_value(i.XO.RA), ca); Value* add_value = b.CreateExtractValue(v, 0); - g.update_gpr_value(i.XO.RT, add_value); + e.update_gpr_value(i.XO.RT, add_value); if (i.XO.OE) { // With XER[SO] update too. - g.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); } else { // Just CA update. - g.update_xer_with_carry(b.CreateExtractValue(v, 1)); + e.update_xer_with_carry(b.CreateExtractValue(v, 1)); } if (i.XO.Rc) { // With cr0 update. - g.update_cr_with_cond(0, add_value, b.getInt64(0), true); + e.update_cr_with_cond(0, add_value, b.getInt64(0), true); } return 0; } -XEEMITTER(divdx, 0x7C0003D2, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(divdx, 0x7C0003D2, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(divdux, 0x7C000392, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(divdux, 0x7C000392, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(divwx, 0x7C0003D6, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(divwx, 0x7C0003D6, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // dividend[0:31] <- (RA)[32:63] // divisor[0:31] <- (RB)[32:63] // if divisor = 0 then @@ -170,22 +170,22 @@ XEEMITTER(divwx, 0x7C0003D6, XO )(FunctionGenerator& g, IRBuilder<>& b, I // RT[32:63] <- dividend ÷ divisor // RT[0:31] <- undefined - Value* dividend = b.CreateTrunc(g.gpr_value(i.XO.RA), b.getInt32Ty()); - Value* divisor = b.CreateTrunc(g.gpr_value(i.XO.RB), b.getInt32Ty()); + 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(*g.context(), "", g.gen_fn()) : NULL; - BasicBlock* nonzero_bb = BasicBlock::Create(*g.context(), "", g.gen_fn()); - BasicBlock* after_bb = BasicBlock::Create(*g.context(), "", g.gen_fn()); + 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); - g.update_xer_with_overflow(b.getInt1(1)); + e.update_xer_with_overflow(b.getInt1(1)); b.CreateBr(after_bb); } @@ -193,16 +193,16 @@ XEEMITTER(divwx, 0x7C0003D6, XO )(FunctionGenerator& g, IRBuilder<>& b, I b.SetInsertPoint(nonzero_bb); Value* v = b.CreateSDiv(dividend, divisor); v = b.CreateSExt(v, b.getInt64Ty()); - g.update_gpr_value(i.XO.RT, v); + e.update_gpr_value(i.XO.RT, v); // If we are OE=1 we need to clear the overflow bit. if (i.XO.OE) { - g.update_xer_with_overflow(b.getInt1(0)); + e.update_xer_with_overflow(b.getInt1(0)); } if (i.XO.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } b.CreateBr(after_bb); @@ -213,7 +213,7 @@ XEEMITTER(divwx, 0x7C0003D6, XO )(FunctionGenerator& g, IRBuilder<>& b, I return 0; } -XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(divwux, 0x7C000396, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // dividend[0:31] <- (RA)[32:63] // divisor[0:31] <- (RB)[32:63] // if divisor = 0 then @@ -223,22 +223,22 @@ XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, IRBuilder<>& b, I // RT[32:63] <- dividend ÷ divisor // RT[0:31] <- undefined - Value* dividend = b.CreateTrunc(g.gpr_value(i.XO.RA), b.getInt32Ty()); - Value* divisor = b.CreateTrunc(g.gpr_value(i.XO.RB), b.getInt32Ty()); + 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(*g.context(), "", g.gen_fn()) : NULL; - BasicBlock* nonzero_bb = BasicBlock::Create(*g.context(), "", g.gen_fn()); - BasicBlock* after_bb = BasicBlock::Create(*g.context(), "", g.gen_fn()); + 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); - g.update_xer_with_overflow(b.getInt1(1)); + e.update_xer_with_overflow(b.getInt1(1)); b.CreateBr(after_bb); } @@ -246,16 +246,16 @@ XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, IRBuilder<>& b, I b.SetInsertPoint(nonzero_bb); Value* v = b.CreateUDiv(dividend, divisor); v = b.CreateZExt(v, b.getInt64Ty()); - g.update_gpr_value(i.XO.RT, v); + e.update_gpr_value(i.XO.RT, v); // If we are OE=1 we need to clear the overflow bit. if (i.XO.OE) { - g.update_xer_with_overflow(b.getInt1(0)); + e.update_xer_with_overflow(b.getInt1(0)); } if (i.XO.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } b.CreateBr(after_bb); @@ -266,32 +266,32 @@ XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, IRBuilder<>& b, I return 0; } -XEEMITTER(mulhdx, 0x7C000092, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mulhdx, 0x7C000092, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulhdux, 0x7C000012, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mulhdux, 0x7C000012, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulhwx, 0x7C000096, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mulhwx, 0x7C000096, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulhwux, 0x7C000016, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mulhwux, 0x7C000016, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulldx, 0x7C0001D2, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mulldx, 0x7C0001D2, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulli, 0x1C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mulli, 0x1C000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // prod[0:127] <- (RA) × EXTS(SI) // RT <- prod[64:127] @@ -299,13 +299,13 @@ XEEMITTER(mulli, 0x1C000000, D )(FunctionGenerator& g, IRBuilder<>& b, I // overflows. It should be truncating the result, but I'm not sure what LLVM // does. - Value* v = b.CreateMul(g.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS))); - g.update_gpr_value(i.D.RT, b.CreateTrunc(v, b.getInt64Ty())); + 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 )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mullwx, 0x7C0001D6, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RT <- (RA)[32:63] × (RB)[32:63] if (i.XO.OE) { @@ -314,19 +314,19 @@ XEEMITTER(mullwx, 0x7C0001D6, XO )(FunctionGenerator& g, IRBuilder<>& b, I return 1; } - Value* v = b.CreateMul(b.CreateSExt(g.gpr_value(i.XO.RA), b.getInt64Ty()), - b.CreateSExt(g.gpr_value(i.XO.RB), b.getInt64Ty())); - g.update_gpr_value(i.XO.RT, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(negx, 0x7C0000D0, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(negx, 0x7C0000D0, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RT <- ¬(RA) + 1 if (i.XO.OE) { @@ -337,34 +337,34 @@ XEEMITTER(negx, 0x7C0000D0, XO )(FunctionGenerator& g, IRBuilder<>& b, I // This may just magically do that... Function* ssub_with_overflow = Intrinsic::getDeclaration( - g.gen_module(), Intrinsic::ssub_with_overflow, b.getInt64Ty()); + e.gen_module(), Intrinsic::ssub_with_overflow, b.getInt64Ty()); Value* v = b.CreateCall2(ssub_with_overflow, - b.getInt64(0), g.gpr_value(i.XO.RA)); + b.getInt64(0), e.gpr_value(i.XO.RA)); Value* v0 = b.CreateExtractValue(v, 0); - g.update_gpr_value(i.XO.RT, v0); - g.update_xer_with_overflow(b.CreateExtractValue(v, 1)); + e.update_gpr_value(i.XO.RT, v0); + e.update_xer_with_overflow(b.CreateExtractValue(v, 1)); if (i.XO.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v0, b.getInt64(0), true); + 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), g.gpr_value(i.XO.RA)); - g.update_gpr_value(i.XO.RT, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } } -XEEMITTER(subfx, 0x7C000050, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(subfx, 0x7C000050, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RT <- ¬(RA) + (RB) + 1 if (i.XO.OE) { @@ -372,87 +372,87 @@ XEEMITTER(subfx, 0x7C000050, XO )(FunctionGenerator& g, IRBuilder<>& b, I // This is a different codepath as we need to use llvm.ssub.with.overflow. Function* ssub_with_overflow = Intrinsic::getDeclaration( - g.gen_module(), Intrinsic::ssub_with_overflow, b.getInt64Ty()); + e.gen_module(), Intrinsic::ssub_with_overflow, b.getInt64Ty()); Value* v = b.CreateCall2(ssub_with_overflow, - g.gpr_value(i.XO.RB), g.gpr_value(i.XO.RA)); + e.gpr_value(i.XO.RB), e.gpr_value(i.XO.RA)); Value* v0 = b.CreateExtractValue(v, 0); - g.update_gpr_value(i.XO.RT, v0); - g.update_xer_with_overflow(b.CreateExtractValue(v, 1)); + e.update_gpr_value(i.XO.RT, v0); + e.update_xer_with_overflow(b.CreateExtractValue(v, 1)); if (i.XO.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v0, b.getInt64(0), true); + e.update_cr_with_cond(0, v0, b.getInt64(0), true); } return 0; } else { // No OE bit setting. - Value* v = b.CreateSub(g.gpr_value(i.XO.RB), g.gpr_value(i.XO.RA)); - g.update_gpr_value(i.XO.RT, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } } -XEEMITTER(subfcx, 0x7C000010, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(subfcx, 0x7C000010, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(subficx, 0x20000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(subficx, 0x20000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RT <- ¬(RA) + EXTS(SI) + 1 Function* ssub_with_overflow = Intrinsic::getDeclaration( - g.gen_module(), Intrinsic::ssub_with_overflow, b.getInt64Ty()); + e.gen_module(), Intrinsic::ssub_with_overflow, b.getInt64Ty()); Value* v = b.CreateCall2(ssub_with_overflow, - b.getInt64(XEEXTS16(i.D.DS)), g.gpr_value(i.D.RA)); - g.update_gpr_value(i.D.RT, b.CreateExtractValue(v, 0)); - g.update_xer_with_carry(b.CreateExtractValue(v, 1)); + 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 )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(subfex, 0x7C000110, XO )(EmitterContext& e, IRBuilder<>& b, 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(g.xer_value(), 29), 0x1); + Value* ca = b.CreateAnd(b.CreateLShr(e.xer_value(), 29), 0x1); Function* uadd_with_overflow = Intrinsic::getDeclaration( - g.gen_module(), Intrinsic::uadd_with_overflow, b.getInt64Ty()); + e.gen_module(), Intrinsic::uadd_with_overflow, b.getInt64Ty()); Value* v = b.CreateCall2(uadd_with_overflow, - b.CreateNeg(g.gpr_value(i.XO.RA)), - b.CreateAdd(g.gpr_value(i.XO.RB), ca)); + b.CreateNeg(e.gpr_value(i.XO.RA)), + b.CreateAdd(e.gpr_value(i.XO.RB), ca)); Value* v0 = b.CreateExtractValue(v, 0); - g.update_gpr_value(i.XO.RT, v0); + e.update_gpr_value(i.XO.RT, v0); if (i.XO.OE) { // With XER update. - g.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); } else { - g.update_xer_with_carry(b.CreateExtractValue(v, 1)); + e.update_xer_with_carry(b.CreateExtractValue(v, 1)); } if (i.XO.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v0, b.getInt64(0), true); + e.update_cr_with_cond(0, v0, b.getInt64(0), true); } return 0; } -XEEMITTER(subfmex, 0x7C0001D0, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(subfmex, 0x7C0001D0, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(subfzex, 0x7C000190, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(subfzex, 0x7C000190, XO )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -460,7 +460,7 @@ XEEMITTER(subfzex, 0x7C000190, XO )(FunctionGenerator& g, IRBuilder<>& b, I // Integer compare (A-4) -XEEMITTER(cmp, 0x7C000000, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(cmp, 0x7C000000, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if L = 0 then // a <- EXTS((RA)[32:63]) // b <- EXTS((RB)[32:63]) @@ -478,8 +478,8 @@ XEEMITTER(cmp, 0x7C000000, X )(FunctionGenerator& g, IRBuilder<>& b, I uint32_t BF = i.X.RT >> 2; uint32_t L = i.X.RT & 1; - Value* lhs = g.gpr_value(i.X.RA); - Value* rhs = g.gpr_value(i.X.RB); + 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()); @@ -488,12 +488,12 @@ XEEMITTER(cmp, 0x7C000000, X )(FunctionGenerator& g, IRBuilder<>& b, I rhs = b.CreateSExt(rhs, b.getInt64Ty()); } - g.update_cr_with_cond(BF, lhs, rhs, true); + e.update_cr_with_cond(BF, lhs, rhs, true); return 0; } -XEEMITTER(cmpi, 0x2C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(cmpi, 0x2C000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if L = 0 then // a <- EXTS((RA)[32:63]) // else @@ -509,7 +509,7 @@ XEEMITTER(cmpi, 0x2C000000, D )(FunctionGenerator& g, IRBuilder<>& b, I uint32_t BF = i.D.RT >> 2; uint32_t L = i.D.RT & 1; - Value* lhs = g.gpr_value(i.D.RA); + Value* lhs = e.gpr_value(i.D.RA); if (!L) { // 32-bit - truncate and sign extend. lhs = b.CreateTrunc(lhs, b.getInt32Ty()); @@ -517,12 +517,12 @@ XEEMITTER(cmpi, 0x2C000000, D )(FunctionGenerator& g, IRBuilder<>& b, I } Value* rhs = b.getInt64(XEEXTS16(i.D.DS)); - g.update_cr_with_cond(BF, lhs, rhs, true); + e.update_cr_with_cond(BF, lhs, rhs, true); return 0; } -XEEMITTER(cmpl, 0x7C000040, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(cmpl, 0x7C000040, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if L = 0 then // a <- i32.0 || (RA)[32:63] // b <- i32.0 || (RB)[32:63] @@ -540,8 +540,8 @@ XEEMITTER(cmpl, 0x7C000040, X )(FunctionGenerator& g, IRBuilder<>& b, I uint32_t BF = i.X.RT >> 2; uint32_t L = i.X.RT & 1; - Value* lhs = g.gpr_value(i.X.RA); - Value* rhs = g.gpr_value(i.X.RB); + 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()); @@ -550,12 +550,12 @@ XEEMITTER(cmpl, 0x7C000040, X )(FunctionGenerator& g, IRBuilder<>& b, I rhs = b.CreateZExt(rhs, b.getInt64Ty()); } - g.update_cr_with_cond(BF, lhs, rhs, false); + e.update_cr_with_cond(BF, lhs, rhs, false); return 0; } -XEEMITTER(cmpli, 0x28000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(cmpli, 0x28000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if L = 0 then // a <- i32.0 || (RA)[32:63] // else @@ -571,7 +571,7 @@ XEEMITTER(cmpli, 0x28000000, D )(FunctionGenerator& g, IRBuilder<>& b, I uint32_t BF = i.D.RT >> 2; uint32_t L = i.D.RT & 1; - Value* lhs = g.gpr_value(i.D.RA); + Value* lhs = e.gpr_value(i.D.RA); if (!L) { // 32-bit - truncate and zero extend. lhs = b.CreateTrunc(lhs, b.getInt32Ty()); @@ -579,7 +579,7 @@ XEEMITTER(cmpli, 0x28000000, D )(FunctionGenerator& g, IRBuilder<>& b, I } Value* rhs = b.getInt64(i.D.DS); - g.update_cr_with_cond(BF, lhs, rhs, false); + e.update_cr_with_cond(BF, lhs, rhs, false); return 0; } @@ -587,209 +587,209 @@ XEEMITTER(cmpli, 0x28000000, D )(FunctionGenerator& g, IRBuilder<>& b, I // Integer logical (A-5) -XEEMITTER(andx, 0x7C000038, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(andx, 0x7C000038, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) & (RB) - Value* v = b.CreateAnd(g.gpr_value(i.X.RT), g.gpr_value(i.X.RB)); - g.update_gpr_value(i.X.RA, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(andcx, 0x7C000078, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(andcx, 0x7C000078, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) & ¬(RB) - Value* v = b.CreateXor(g.gpr_value(i.X.RB), -1); - v = b.CreateAnd(g.gpr_value(i.X.RT), v); - g.update_gpr_value(i.X.RA, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(andix, 0x70000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(andix, 0x70000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) & (i48.0 || UI) - Value* v = b.CreateAnd(g.gpr_value(i.D.RT), (uint64_t)i.D.DS); - g.update_gpr_value(i.D.RA, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); return 0; } -XEEMITTER(andisx, 0x74000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(andisx, 0x74000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) & (i32.0 || UI || i16.0) - Value* v = b.CreateAnd(g.gpr_value(i.D.RT), ((uint64_t)i.D.DS) << 16); - g.update_gpr_value(i.D.RA, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); return 1; } -XEEMITTER(cntlzdx, 0x7C000074, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(cntlzdx, 0x7C000074, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(cntlzwx, 0x7C000034, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(cntlzwx, 0x7C000034, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // n <- 32 // do while n < 64 // if (RS) = 1 then leave n // n <- n + 1 // RA <- n - 32 - Value* v = g.gpr_value(i.X.RT); + 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( - g.gen_fn()->getParent(), Intrinsic::ctlz, arg_types); + e.gen_fn()->getParent(), Intrinsic::ctlz, arg_types); Value* count = b.CreateCall2(ctlz, v, b.getInt1(1)); count = b.CreateZExt(count, b.getInt64Ty()); - g.update_gpr_value(i.X.RA, count); + e.update_gpr_value(i.X.RA, count); if (i.X.Rc) { // With cr0 update. - g.update_cr_with_cond(0, count, b.getInt64(0), true); + e.update_cr_with_cond(0, count, b.getInt64(0), true); } return 0; } -XEEMITTER(eqvx, 0x7C000238, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(eqvx, 0x7C000238, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(extsbx, 0x7C000774, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(extsbx, 0x7C000774, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // s <- (RS)[56] // RA[56:63] <- (RS)[56:63] // RA[0:55] <- i56.s - Value* v = g.gpr_value(i.X.RT); + Value* v = e.gpr_value(i.X.RT); v = b.CreateTrunc(v, b.getInt8Ty()); v = b.CreateSExt(v, b.getInt64Ty()); - g.update_gpr_value(i.X.RA, v); + e.update_gpr_value(i.X.RA, v); if (i.X.Rc) { // Update cr0. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(extshx, 0x7C000734, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(extshx, 0x7C000734, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(extswx, 0x7C0007B4, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(extswx, 0x7C0007B4, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(nandx, 0x7C0003B8, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(nandx, 0x7C0003B8, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(norx, 0x7C0000F8, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(norx, 0x7C0000F8, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- ¬((RS) | (RB)) - Value* v = b.CreateOr(g.gpr_value(i.X.RT), g.gpr_value(i.X.RB)); + Value* v = b.CreateOr(e.gpr_value(i.X.RT), e.gpr_value(i.X.RB)); v = b.CreateXor(v, -1); - g.update_gpr_value(i.X.RA, v); + e.update_gpr_value(i.X.RA, v); if (i.X.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(orx, 0x7C000378, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(orx, 0x7C000378, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) | (RB) - Value* v = b.CreateOr(g.gpr_value(i.X.RT), g.gpr_value(i.X.RB)); - g.update_gpr_value(i.X.RA, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(orcx, 0x7C000338, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(orcx, 0x7C000338, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(ori, 0x60000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(ori, 0x60000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) | (i48.0 || UI) - Value* v = b.CreateOr(g.gpr_value(i.D.RT), (uint64_t)i.D.DS); - g.update_gpr_value(i.D.RA, v); + 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 )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(oris, 0x64000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) | (i32.0 || UI || i16.0) - Value* v = b.CreateOr(g.gpr_value(i.D.RT), ((uint64_t)i.D.DS) << 16); - g.update_gpr_value(i.D.RA, v); + 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 )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(xorx, 0x7C000278, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) XOR (RB) - Value* v = b.CreateXor(g.gpr_value(i.X.RT), g.gpr_value(i.X.RB)); - g.update_gpr_value(i.X.RA, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(xori, 0x68000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(xori, 0x68000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) XOR (i48.0 || UI) - Value* v = b.CreateXor(g.gpr_value(i.D.RT), (uint64_t)i.D.DS); - g.update_gpr_value(i.D.RA, v); + 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 )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(xoris, 0x6C000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // RA <- (RS) XOR (i32.0 || UI || i16.0) - Value* v = b.CreateXor(g.gpr_value(i.D.RT), ((uint64_t)i.D.DS) << 16); - g.update_gpr_value(i.D.RA, v); + 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; } @@ -797,22 +797,22 @@ XEEMITTER(xoris, 0x6C000000, D )(FunctionGenerator& g, IRBuilder<>& b, I // Integer rotate (A-6) -XEEMITTER(rldclx, 0x78000010, MDS)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(rldclx, 0x78000010, MDS)(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldcrx, 0x78000012, MDS)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(rldcrx, 0x78000012, MDS)(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldicx, 0x78000008, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(rldicx, 0x78000008, MD )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldiclx, 0x78000000, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(rldiclx, 0x78000000, MD )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // n <- sh[5] || sh[0:4] // r <- ROTL64((RS), n) // b <- mb[5] || mb[0:4] @@ -822,59 +822,59 @@ XEEMITTER(rldiclx, 0x78000000, MD )(FunctionGenerator& g, IRBuilder<>& b, I // uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; // uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; - // Value* v = g.gpr_value(i.MD.RS); + // Value* v = e.gpr_value(i.MD.RS); // if (sh) { // v = // rotate by sh // } // if (mb) { // v = // mask b mb->63 // } - // g.update_gpr_value(i.MD.RA, v); + // e.update_gpr_value(i.MD.RA, v); // if (i.MD.Rc) { // // With cr0 update. - // g.update_cr_with_cond(0, v, b.getInt64(0), true); + // e.update_cr_with_cond(0, v, b.getInt64(0), true); // } XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldicrx, 0x78000004, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(rldicrx, 0x78000004, MD )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldimix, 0x7800000C, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(rldimix, 0x7800000C, MD )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rlwimix, 0x50000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(rlwimix, 0x50000000, M )(EmitterContext& e, IRBuilder<>& b, 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(g.gpr_value(i.M.RT), UINT32_MAX); + 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(g.gpr_value(i.M.RA), ~m)); - g.update_gpr_value(i.M.RA, v); + 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. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(rlwinmx, 0x54000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(rlwinmx, 0x54000000, M )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // n <- SH // r <- ROTL32((RS)[32:63], n) // m <- MASK(MB+32, ME+32) @@ -885,34 +885,34 @@ XEEMITTER(rlwinmx, 0x54000000, M )(FunctionGenerator& g, IRBuilder<>& b, I // We can detect this and do less work. if (!i.M.SH) { Value* v = b.CreateAnd( - b.CreateTrunc(g.gpr_value(i.M.RT), b.getInt32Ty()), + 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()); - g.update_gpr_value(i.M.RA, v); + e.update_gpr_value(i.M.RA, v); if (i.M.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + 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(g.gpr_value(i.M.RT), UINT32_MAX); + 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)); - g.update_gpr_value(i.M.RA, v); + e.update_gpr_value(i.M.RA, v); if (i.M.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(rlwnmx, 0x5C000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(rlwnmx, 0x5C000000, M )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -920,12 +920,12 @@ XEEMITTER(rlwnmx, 0x5C000000, M )(FunctionGenerator& g, IRBuilder<>& b, I // Integer shift (A-7) -XEEMITTER(sldx, 0x7C000036, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(sldx, 0x7C000036, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(slwx, 0x7C000030, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(slwx, 0x7C000030, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // n <- (RB)[59:63] // r <- ROTL32((RS)[32:63], n) // if (RB)[58] = 0 then @@ -934,34 +934,34 @@ XEEMITTER(slwx, 0x7C000030, X )(FunctionGenerator& g, IRBuilder<>& b, I // m <- i64.0 // RA <- r & m - Value* v = b.CreateShl(g.gpr_value(i.X.RT), g.gpr_value(i.X.RB)); + Value* v = b.CreateShl(e.gpr_value(i.X.RT), e.gpr_value(i.X.RB)); v = b.CreateAnd(v, UINT32_MAX); - g.update_gpr_value(i.X.RA, v); + e.update_gpr_value(i.X.RA, v); if (i.X.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(sradx, 0x7C000634, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(sradx, 0x7C000634, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(sradix, 0x7C000674, XS )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(sradix, 0x7C000674, XS )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(srawx, 0x7C000630, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(srawx, 0x7C000630, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(srawix, 0x7C000670, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(srawix, 0x7C000670, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // n <- SH // r <- ROTL32((RS)[32:63], 64-n) // m <- MASK(n+32, 63) @@ -969,7 +969,7 @@ XEEMITTER(srawix, 0x7C000670, X )(FunctionGenerator& g, IRBuilder<>& b, I // RA <- r&m | (i64.s)&¬m // CA <- s & ((r&¬m)[32:63]≠0) - Value* rs64 = g.gpr_value(i.X.RT); + Value* rs64 = e.gpr_value(i.X.RT); Value* rs32 = b.CreateTrunc(rs64, b.getInt32Ty()); Value* v; @@ -987,23 +987,23 @@ XEEMITTER(srawix, 0x7C000670, X )(FunctionGenerator& g, IRBuilder<>& b, I b.CreateICmpSLT(rs64, b.getInt64(0))); } v = b.CreateSExt(v, b.getInt64Ty()); - g.update_gpr_value(i.X.RA, v); - g.update_xer_with_carry(ca); + e.update_gpr_value(i.X.RA, v); + e.update_xer_with_carry(ca); if (i.X.Rc) { // With cr0 update. - g.update_cr_with_cond(0, v, b.getInt64(0), true); + e.update_cr_with_cond(0, v, b.getInt64(0), true); } return 0; } -XEEMITTER(srdx, 0x7C000436, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(srdx, 0x7C000436, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(srwx, 0x7C000430, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(srwx, 0x7C000430, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -1080,6 +1080,6 @@ void RegisterEmitCategoryALU() { } -} // namespace codegen +} // namespace llvmbe } // namespace cpu } // namespace xe diff --git a/src/xenia/cpu/codegen/emit_control.cc b/src/xenia/cpu/llvmbe/emit_control.cc similarity index 71% rename from src/xenia/cpu/codegen/emit_control.cc rename to src/xenia/cpu/llvmbe/emit_control.cc index 5b62de531..b26575430 100644 --- a/src/xenia/cpu/codegen/emit_control.cc +++ b/src/xenia/cpu/llvmbe/emit_control.cc @@ -7,25 +7,25 @@ ****************************************************************************** */ -#include +#include -#include +#include #include using namespace llvm; -using namespace xe::cpu::codegen; +using namespace xe::cpu; using namespace xe::cpu::ppc; using namespace xe::cpu::sdb; namespace xe { namespace cpu { -namespace codegen { +namespace llvmbe { int XeEmitIndirectBranchTo( - FunctionGenerator& g, IRBuilder<>& b, const char* src, uint32_t cia, + EmitterContext& e, IRBuilder<>& b, 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 @@ -37,10 +37,10 @@ int XeEmitIndirectBranchTo( Value* target; switch (reg) { case kXEPPCRegLR: - target = g.lr_value(); + target = e.lr_value(); break; case kXEPPCRegCTR: - target = g.ctr_value(); + target = e.ctr_value(); break; default: XEASSERTALWAYS(); @@ -52,29 +52,29 @@ int XeEmitIndirectBranchTo( // 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 = g.GetNextBasicBlock(); - BasicBlock* mismatch_bb = BasicBlock::Create(*g.context(), "lr_mismatch", - g.gen_fn(), next_block); - Value* lr_cmp = b.CreateICmpEQ(target, ++(g.gen_fn()->arg_begin())); + 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, g.GetReturnBasicBlock(), mismatch_bb); + 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 g.GenerateIndirectionBranch(cia, target, lk, likely_local); + return e.GenerateIndirectionBranch(cia, target, lk, likely_local); } int XeEmitBranchTo( - FunctionGenerator& g, IRBuilder<>& b, const char* src, uint32_t cia, + EmitterContext& e, IRBuilder<>& b, const char* src, uint32_t cia, bool lk) { // Get the basic block and switch behavior based on outgoing type. - FunctionBlock* fn_block = g.fn_block(); + FunctionBlock* fn_block = e.fn_block(); switch (fn_block->outgoing_type) { case FunctionBlock::kTargetBlock: { - BasicBlock* target_bb = g.GetBasicBlock(fn_block->outgoing_address); + BasicBlock* target_bb = e.GetBasicBlock(fn_block->outgoing_address); XEASSERTNOTNULL(target_bb); b.CreateBr(target_bb); break; @@ -85,13 +85,13 @@ int XeEmitBranchTo( // TODO(benvanik): only spill ones used by the target function? Use // calling convention flags on the function to not spill temp // registers? - g.SpillRegisters(); + e.SpillRegisters(); XEASSERTNOTNULL(fn_block->outgoing_function); - Function* target_fn = g.GetFunction(fn_block->outgoing_function); - Function::arg_iterator args = g.gen_fn()->arg_begin(); + 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 = g.GetNextBasicBlock(); + 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 @@ -103,7 +103,7 @@ int XeEmitBranchTo( // Will return here eventually. // Refill registers from state. b.CreateCall2(target_fn, state_ptr, b.getInt64(cia + 4)); - g.FillRegisters(); + e.FillRegisters(); b.CreateBr(next_bb); } break; @@ -112,13 +112,13 @@ int XeEmitBranchTo( { // An indirect jump. printf("INDIRECT JUMP VIA LR: %.8X\n", cia); - return XeEmitIndirectBranchTo(g, b, src, cia, lk, kXEPPCRegLR); + return XeEmitIndirectBranchTo(e, b, src, cia, lk, kXEPPCRegLR); } case FunctionBlock::kTargetCTR: { // An indirect jump. printf("INDIRECT JUMP VIA CTR: %.8X\n", cia); - return XeEmitIndirectBranchTo(g, b, src, cia, lk, kXEPPCRegCTR); + return XeEmitIndirectBranchTo(e, b, src, cia, lk, kXEPPCRegCTR); } default: case FunctionBlock::kTargetNone: @@ -129,7 +129,7 @@ int XeEmitBranchTo( } -XEEMITTER(bx, 0x48000000, I )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(bx, 0x48000000, I )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if AA then // NIA <- EXTS(LI || 0b00) // else @@ -144,13 +144,13 @@ XEEMITTER(bx, 0x48000000, I )(FunctionGenerator& g, IRBuilder<>& b, I nia = i.address + XEEXTS26(i.I.LI << 2); } if (i.I.LK) { - g.update_lr_value(b.getInt32(i.address + 4)); + e.update_lr_value(b.getInt32(i.address + 4)); } - return XeEmitBranchTo(g, b, "bx", i.address, i.I.LK); + return XeEmitBranchTo(e, b, "bx", i.address, i.I.LK); } -XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(bcx, 0x40000000, B )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if ¬BO[2] then // CTR <- CTR - 1 // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3]) @@ -170,7 +170,7 @@ XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, I // TODO(benvanik): this may be wrong and overwrite LRs when not desired! // The docs say always, though... if (i.B.LK) { - g.update_lr_value(b.getInt32(i.address + 4)); + e.update_lr_value(b.getInt32(i.address + 4)); } Value* ctr_ok = NULL; @@ -178,9 +178,9 @@ XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, I // Ignore ctr. } else { // Decrement counter. - Value* ctr = g.ctr_value(); + Value* ctr = e.ctr_value(); ctr = b.CreateSub(ctr, b.getInt64(1)); - g.update_ctr_value(ctr); + e.update_ctr_value(ctr); // Ctr check. if (XESELECTBITS(i.B.BO, 1, 1)) { @@ -194,7 +194,7 @@ XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, I if (XESELECTBITS(i.B.BO, 4, 4)) { // Ignore cond. } else { - Value* cr = g.cr_value(i.B.BI >> 2); + 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)); @@ -218,8 +218,8 @@ XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, I if (ok) { char name[32]; xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address); - BasicBlock* next_block = g.GetNextBasicBlock(); - BasicBlock* branch_bb = BasicBlock::Create(*g.context(), name, g.gen_fn(), + 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); @@ -233,7 +233,7 @@ XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, I } else { nia = i.address + XEEXTS26(i.B.BD << 2); } - if (XeEmitBranchTo(g, b, "bcx", i.address, i.B.LK)) { + if (XeEmitBranchTo(e, b, "bcx", i.address, i.B.LK)) { return 1; } @@ -242,7 +242,7 @@ XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, I return 0; } -XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(bcctrx, 0x4C000420, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) // if cond_ok then // NIA <- CTR[0:61] || 0b00 @@ -256,14 +256,14 @@ XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, IRBuilder<>& b, I // TODO(benvanik): this may be wrong and overwrite LRs when not desired! // The docs say always, though... if (i.XL.LK) { - g.update_lr_value(b.getInt32(i.address + 4)); + 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 = g.cr_value(i.XL.BI >> 2); + 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)); @@ -283,9 +283,9 @@ XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, IRBuilder<>& b, I if (ok) { char name[32]; xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcctrx", i.address); - BasicBlock* next_block = g.GetNextBasicBlock(); + BasicBlock* next_block = e.GetNextBasicBlock(); XEASSERTNOTNULL(next_block); - BasicBlock* branch_bb = BasicBlock::Create(*g.context(), name, g.gen_fn(), + BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(), next_block); b.CreateCondBr(ok, branch_bb, next_block); @@ -293,7 +293,7 @@ XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, IRBuilder<>& b, I } // Note that this occurs entirely within the branch true block. - if (XeEmitBranchTo(g, b, "bcctrx", i.address, i.XL.LK)) { + if (XeEmitBranchTo(e, b, "bcctrx", i.address, i.XL.LK)) { return 1; } @@ -302,7 +302,7 @@ XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, IRBuilder<>& b, I return 0; } -XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(bclrx, 0x4C000020, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if ¬BO[2] then // CTR <- CTR - 1 // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3] @@ -319,7 +319,7 @@ XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, I // TODO(benvanik): this may be wrong and overwrite LRs when not desired! // The docs say always, though... if (i.XL.LK) { - g.update_lr_value(b.getInt32(i.address + 4)); + e.update_lr_value(b.getInt32(i.address + 4)); } Value* ctr_ok = NULL; @@ -327,7 +327,7 @@ XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, I // Ignore ctr. } else { // Decrement counter. - Value* ctr = g.ctr_value(); + Value* ctr = e.ctr_value(); ctr = b.CreateSub(ctr, b.getInt64(1)); // Ctr check. @@ -342,7 +342,7 @@ XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, I if (XESELECTBITS(i.XL.BO, 4, 4)) { // Ignore cond. } else { - Value* cr = g.cr_value(i.XL.BI >> 2); + 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)); @@ -366,9 +366,9 @@ XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, I if (ok) { char name[32]; xesnprintfa(name, XECOUNT(name), "loc_%.8X_bclrx", i.address); - BasicBlock* next_block = g.GetNextBasicBlock(); + BasicBlock* next_block = e.GetNextBasicBlock(); XEASSERTNOTNULL(next_block); - BasicBlock* branch_bb = BasicBlock::Create(*g.context(), name, g.gen_fn(), + BasicBlock* branch_bb = BasicBlock::Create(*e.context(), name, e.gen_fn(), next_block); b.CreateCondBr(ok, branch_bb, next_block); @@ -376,7 +376,7 @@ XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, I } // Note that this occurs entirely within the branch true block. - if (XeEmitBranchTo(g, b, "bclrx", i.address, i.XL.LK)) { + if (XeEmitBranchTo(e, b, "bclrx", i.address, i.XL.LK)) { return 1; } @@ -388,47 +388,47 @@ XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, I // Condition register logical (A-23) -XEEMITTER(crand, 0x4C000202, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(crand, 0x4C000202, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crandc, 0x4C000102, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(crandc, 0x4C000102, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(creqv, 0x4C000242, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(creqv, 0x4C000242, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crnand, 0x4C0001C2, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(crnand, 0x4C0001C2, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crnor, 0x4C000042, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(crnor, 0x4C000042, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(cror, 0x4C000382, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(cror, 0x4C000382, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crorc, 0x4C000342, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(crorc, 0x4C000342, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crxor, 0x4C000182, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(crxor, 0x4C000182, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mcrf, 0x4C000000, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mcrf, 0x4C000000, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -436,7 +436,7 @@ XEEMITTER(mcrf, 0x4C000000, XL )(FunctionGenerator& g, IRBuilder<>& b, I // System linkage (A-24) -XEEMITTER(sc, 0x44000002, SC )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(sc, 0x44000002, SC )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -444,7 +444,7 @@ XEEMITTER(sc, 0x44000002, SC )(FunctionGenerator& g, IRBuilder<>& b, I // Trap (A-25) -int XeEmitTrap(FunctionGenerator& g, IRBuilder<>& b, InstrData& i, +int XeEmitTrap(EmitterContext& e, IRBuilder<>& b, InstrData& i, Value* va, Value* vb, uint32_t TO) { // if (a < b) & TO[0] then TRAP // if (a > b) & TO[1] then TRAP @@ -459,27 +459,27 @@ int XeEmitTrap(FunctionGenerator& g, IRBuilder<>& b, InstrData& i, return 0; } - BasicBlock* after_bb = BasicBlock::Create(*g.context(), "", g.gen_fn(), - g.GetNextBasicBlock()); - BasicBlock* trap_bb = BasicBlock::Create(*g.context(), "", g.gen_fn(), + 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(*g.context(), "", g.gen_fn(), trap_bb)); + bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); } if (TO & (1 << 3)) { - bbs.push_back(BasicBlock::Create(*g.context(), "", g.gen_fn(), trap_bb)); + bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); } if (TO & (1 << 2)) { - bbs.push_back(BasicBlock::Create(*g.context(), "", g.gen_fn(), trap_bb)); + bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); } if (TO & (1 << 1)) { - bbs.push_back(BasicBlock::Create(*g.context(), "", g.gen_fn(), trap_bb)); + bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); } if (TO & (1 << 0)) { - bbs.push_back(BasicBlock::Create(*g.context(), "", g.gen_fn(), trap_bb)); + bbs.push_back(BasicBlock::Create(*e.context(), "", e.gen_fn(), trap_bb)); } bbs.push_back(after_bb); @@ -526,10 +526,10 @@ int XeEmitTrap(FunctionGenerator& g, IRBuilder<>& b, InstrData& i, // Create trap BB. b.SetInsertPoint(trap_bb); - g.SpillRegisters(); + e.SpillRegisters(); // TODO(benvanik): use @llvm.debugtrap? could make debugging better - b.CreateCall2(g.gen_module()->getFunction("XeTrap"), - g.gen_fn()->arg_begin(), + b.CreateCall2(e.gen_module()->getFunction("XeTrap"), + e.gen_fn()->arg_begin(), b.getInt32(i.address)); b.CreateBr(after_bb); @@ -539,7 +539,7 @@ int XeEmitTrap(FunctionGenerator& g, IRBuilder<>& b, InstrData& i, return 0; } -XEEMITTER(td, 0x7C000088, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(td, 0x7C000088, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // a <- (RA) // b <- (RB) // if (a < b) & TO[0] then TRAP @@ -547,26 +547,26 @@ XEEMITTER(td, 0x7C000088, X )(FunctionGenerator& g, IRBuilder<>& b, I // if (a = b) & TO[2] then TRAP // if (a u b) & TO[4] then TRAP - return XeEmitTrap(g, b, i, - g.gpr_value(i.X.RA), - g.gpr_value(i.X.RB), + return XeEmitTrap(e, b, i, + e.gpr_value(i.X.RA), + e.gpr_value(i.X.RB), i.X.RT); } -XEEMITTER(tdi, 0x08000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(tdi, 0x08000000, D )(EmitterContext& e, IRBuilder<>& b, 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(g, b, i, - g.gpr_value(i.D.RA), + return XeEmitTrap(e, b, i, + e.gpr_value(i.D.RA), b.getInt64(XEEXTS16(i.D.DS)), i.D.RT); } -XEEMITTER(tw, 0x7C000008, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(tw, 0x7C000008, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // a <- EXTS((RA)[32:63]) // b <- EXTS((RB)[32:63]) // if (a < b) & TO[0] then TRAP @@ -574,25 +574,25 @@ XEEMITTER(tw, 0x7C000008, X )(FunctionGenerator& g, IRBuilder<>& b, I // if (a = b) & TO[2] then TRAP // if (a u b) & TO[4] then TRAP - return XeEmitTrap(g, b, i, - b.CreateSExt(b.CreateTrunc(g.gpr_value(i.X.RA), + return XeEmitTrap(e, b, i, + b.CreateSExt(b.CreateTrunc(e.gpr_value(i.X.RA), b.getInt32Ty()), b.getInt64Ty()), - b.CreateSExt(b.CreateTrunc(g.gpr_value(i.X.RB), + b.CreateSExt(b.CreateTrunc(e.gpr_value(i.X.RB), b.getInt32Ty()), b.getInt64Ty()), i.X.RT); } -XEEMITTER(twi, 0x0C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(twi, 0x0C000000, D )(EmitterContext& e, IRBuilder<>& b, 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(g, b, i, - b.CreateSExt(b.CreateTrunc(g.gpr_value(i.D.RA), + 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)), @@ -602,12 +602,12 @@ XEEMITTER(twi, 0x0C000000, D )(FunctionGenerator& g, IRBuilder<>& b, I // Processor control (A-26) -XEEMITTER(mfcr, 0x7C000026, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mfcr, 0x7C000026, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mfspr, 0x7C0002A6, XFX)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mfspr, 0x7C0002A6, XFX)(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // n <- spr[5:9] || spr[0:4] // if length(SPR(n)) = 64 then // RT <- SPR(n) @@ -619,58 +619,58 @@ XEEMITTER(mfspr, 0x7C0002A6, XFX)(FunctionGenerator& g, IRBuilder<>& b, I switch (n) { case 1: // XER - v = g.xer_value(); + v = e.xer_value(); break; case 8: // LR - v = g.lr_value(); + v = e.lr_value(); break; case 9: // CTR - v = g.ctr_value(); + v = e.ctr_value(); break; default: XEINSTRNOTIMPLEMENTED(); return 1; } - g.update_gpr_value(i.XFX.RT, v); + e.update_gpr_value(i.XFX.RT, v); return 0; } -XEEMITTER(mftb, 0x7C0002E6, XFX)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mftb, 0x7C0002E6, XFX)(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtcrf, 0x7C000120, XFX)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mtcrf, 0x7C000120, XFX)(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtspr, 0x7C0003A6, XFX)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mtspr, 0x7C0003A6, XFX)(EmitterContext& e, IRBuilder<>& b, 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 = g.gpr_value(i.XFX.RT); + 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 - g.update_xer_value(v); + e.update_xer_value(v); break; case 8: // LR - g.update_lr_value(v); + e.update_lr_value(v); break; case 9: // CTR - g.update_ctr_value(v); + e.update_ctr_value(v); break; default: XEINSTRNOTIMPLEMENTED(); @@ -708,6 +708,6 @@ void RegisterEmitCategoryControl() { } -} // namespace codegen +} // namespace llvmbe } // namespace cpu } // namespace xe diff --git a/src/xenia/cpu/codegen/emit_fpu.cc b/src/xenia/cpu/llvmbe/emit_fpu.cc similarity index 54% rename from src/xenia/cpu/codegen/emit_fpu.cc rename to src/xenia/cpu/llvmbe/emit_fpu.cc index 060999eb0..3c0afd1e6 100644 --- a/src/xenia/cpu/codegen/emit_fpu.cc +++ b/src/xenia/cpu/llvmbe/emit_fpu.cc @@ -7,84 +7,84 @@ ****************************************************************************** */ -#include +#include -#include +#include using namespace llvm; -using namespace xe::cpu::codegen; +using namespace xe::cpu; using namespace xe::cpu::ppc; namespace xe { namespace cpu { -namespace codegen { +namespace llvmbe { // Floating-point arithmetic (A-8) -XEEMITTER(faddx, 0xFC00002A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(faddx, 0xFC00002A, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(faddsx, 0xEC00002A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(faddsx, 0xEC00002A, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fdivx, 0xFC000024, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fdivx, 0xFC000024, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fdivsx, 0xEC000024, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fdivsx, 0xEC000024, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmulx, 0xFC000032, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fmulx, 0xFC000032, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmulsx, 0xEC000032, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fmulsx, 0xEC000032, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fresx, 0xEC000030, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fresx, 0xEC000030, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(frsqrtex, 0xFC000034, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(frsqrtex, 0xFC000034, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fsubx, 0xFC000028, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fsubx, 0xFC000028, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fsubsx, 0xEC000028, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fsubsx, 0xEC000028, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fselx, 0xFC00002E, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fselx, 0xFC00002E, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fsqrtx, 0xFC00002C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fsqrtx, 0xFC00002C, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fsqrtsx, 0xEC00002C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fsqrtsx, 0xEC00002C, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -92,42 +92,42 @@ XEEMITTER(fsqrtsx, 0xEC00002C, A )(FunctionGenerator& g, IRBuilder<>& b, I // Floating-point multiply-add (A-9) -XEEMITTER(fmaddx, 0xFC00003A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fmaddx, 0xFC00003A, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmaddsx, 0xEC00003A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fmaddsx, 0xEC00003A, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmsubx, 0xFC000038, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fmsubx, 0xFC000038, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmsubsx, 0xEC000038, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fmsubsx, 0xEC000038, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnmaddx, 0xFC00003E, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fnmaddx, 0xFC00003E, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnmaddsx, 0xEC00003E, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fnmaddsx, 0xEC00003E, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnmsubx, 0xFC00003C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fnmsubx, 0xFC00003C, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnmsubsx, 0xEC00003C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fnmsubsx, 0xEC00003C, A )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -135,32 +135,32 @@ XEEMITTER(fnmsubsx, 0xEC00003C, A )(FunctionGenerator& g, IRBuilder<>& b, I // Floating-point rounding and conversion (A-10) -XEEMITTER(fcfidx, 0xFC00069C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fcfidx, 0xFC00069C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fctidx, 0xFC00065C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fctidx, 0xFC00065C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fctidzx, 0xFC00065E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fctidzx, 0xFC00065E, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fctiwx, 0xFC00001C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fctiwx, 0xFC00001C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fctiwzx, 0xFC00001E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fctiwzx, 0xFC00001E, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(frspx, 0xFC000018, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(frspx, 0xFC000018, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -168,12 +168,12 @@ XEEMITTER(frspx, 0xFC000018, X )(FunctionGenerator& g, IRBuilder<>& b, I // Floating-point compare (A-11) -XEEMITTER(fcmpo, 0xFC000040, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fcmpo, 0xFC000040, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fcmpu, 0xFC000000, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fcmpu, 0xFC000000, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { // if (FRA) is a NaN or (FRB) is a NaN then // c <- 0b0001 // else if (FRA) < (FRB) then @@ -194,32 +194,32 @@ XEEMITTER(fcmpu, 0xFC000000, X )(FunctionGenerator& g, IRBuilder<>& b, I // Floating-point status and control register (A -XEEMITTER(mcrfs, 0xFC000080, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mcrfs, 0xFC000080, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mffsx, 0xFC00048E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mffsx, 0xFC00048E, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtfsb0x, 0xFC00008C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mtfsb0x, 0xFC00008C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtfsb1x, 0xFC00004C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mtfsb1x, 0xFC00004C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtfsfx, 0xFC00058E, XFL)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mtfsfx, 0xFC00058E, XFL)(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtfsfix, 0xFC00010C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(mtfsfix, 0xFC00010C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -227,22 +227,22 @@ XEEMITTER(mtfsfix, 0xFC00010C, X )(FunctionGenerator& g, IRBuilder<>& b, I // Floating-point move (A-21) -XEEMITTER(fabsx, 0xFC000210, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fabsx, 0xFC000210, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmrx, 0xFC000090, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fmrx, 0xFC000090, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnabsx, 0xFC000110, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fnabsx, 0xFC000110, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnegx, 0xFC000050, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { +XEEMITTER(fnegx, 0xFC000050, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -291,6 +291,6 @@ void RegisterEmitCategoryFPU() { } -} // namespace codegen +} // namespace llvmbe } // namespace cpu } // namespace xe diff --git a/src/xenia/cpu/llvmbe/emit_memory.cc b/src/xenia/cpu/llvmbe/emit_memory.cc new file mode 100644 index 000000000..0d7e0170b --- /dev/null +++ b/src/xenia/cpu/llvmbe/emit_memory.cc @@ -0,0 +1,1170 @@ +/* + ****************************************************************************** + * 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 + + +using namespace llvm; +using namespace xe::cpu; +using namespace xe::cpu::ppc; + + +namespace xe { +namespace cpu { +namespace llvmbe { + + +// Integer load (A-13) + +XEEMITTER(lbz, 0x88000000, D )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(ldx, 0x7C00002A, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lha, 0xA8000000, D )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lhaux, 0x7C0002EE, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lhax, 0x7C0002AE, X )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lwbrx, 0x7C00042C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(ldbrx, 0x7C000428, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(sthbrx, 0x7C00072C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stwbrx, 0x7C00052C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stdbrx, 0x7C000528, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Integer load and store multiple (A-16) + +XEEMITTER(lmw, 0xB8000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stmw, 0xBC000000, D )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Integer load and store string (A-17) + +XEEMITTER(lswi, 0x7C0004AA, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lswx, 0x7C00042A, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stswi, 0x7C0005AA, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stswx, 0x7C00052A, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Memory synchronization (A-18) + +XEEMITTER(eieio, 0x7C0006AC, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(isync, 0x4C00012C, XL )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(ldarx, 0x7C0000A8, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lwarx, 0x7C000028, X )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stwcx, 0x7C00012D, X )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Floating-point load (A-19) + +XEEMITTER(lfd, 0xC8000000, D )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, 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 )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(dcbst, 0x7C00006C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(dcbt, 0x7C00022C, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + // No-op for now. + // TODO(benvanik): use @llvm.prefetch + return 0; +} + +XEEMITTER(dcbtst, 0x7C0001EC, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + // No-op for now. + // TODO(benvanik): use @llvm.prefetch + return 0; +} + +XEEMITTER(dcbz, 0x7C0007EC, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + // or dcbz128 0x7C2007EC + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(icbi, 0x7C0007AC, X )(EmitterContext& e, IRBuilder<>& b, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +void RegisterEmitCategoryMemory() { + 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 llvmbe +} // namespace cpu +} // namespace xe diff --git a/src/xenia/cpu/codegen/function_generator.cc b/src/xenia/cpu/llvmbe/emitter_context.cc similarity index 86% rename from src/xenia/cpu/codegen/function_generator.cc rename to src/xenia/cpu/llvmbe/emitter_context.cc index 28c50026f..52f11470e 100644 --- a/src/xenia/cpu/codegen/function_generator.cc +++ b/src/xenia/cpu/llvmbe/emitter_context.cc @@ -7,7 +7,7 @@ ****************************************************************************** */ -#include +#include #include @@ -16,7 +16,7 @@ using namespace llvm; -using namespace xe::cpu::codegen; +using namespace xe::cpu::llvmbe; using namespace xe::cpu::ppc; using namespace xe::cpu::sdb; @@ -29,8 +29,9 @@ DEFINE_bool(log_codegen, false, /** * This generates function code. - * One context is created for each function to generate. Each basic block in - * the function is created and stashed in one pass, then filled in the next. + * 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 @@ -46,22 +47,44 @@ DEFINE_bool(log_codegen, false, */ -FunctionGenerator::FunctionGenerator( - xe_memory_ref memory, SymbolDatabase* sdb, FunctionSymbol* fn, - LLVMContext* context, Module* gen_module, Function* gen_fn) { +EmitterContext::EmitterContext( + xe_memory_ref memory, + LLVMContext* context, Module* gen_module) { memory_ = memory; - sdb_ = sdb; - fn_ = fn; context_ = context; gen_module_ = gen_module; - gen_fn_ = gen_fn; builder_ = new IRBuilder<>(*context_); + + // Function type for all functions. + std::vector args; + args.push_back(PointerType::getUnqual(Type::getInt8Ty(*context))); + args.push_back(Type::getInt64Ty(*context)); + Type* return_type = Type::getVoidTy(*context); + fn_type_ = FunctionType::get( + return_type, ArrayRef(args), false); +} + +EmitterContext::~EmitterContext() { + delete builder_; +} + +int EmitterContext::Init(FunctionSymbol* fn, Function* gen_fn) { + builder_->ClearInsertionPoint(); + + fn_ = fn; + 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; @@ -80,53 +103,49 @@ FunctionGenerator::FunctionGenerator( locals_.fpr[n] = NULL; } - if (FLAGS_log_codegen) { - printf("%s:\n", fn->name()); + if (fn) { + if (FLAGS_log_codegen) { + printf("%s:\n", fn->name()); + } } + + return 0; } -FunctionGenerator::~FunctionGenerator() { - delete builder_; -} - -SymbolDatabase* FunctionGenerator::sdb() { - return sdb_; -} - -FunctionSymbol* FunctionGenerator::fn() { - return fn_; -} - -llvm::LLVMContext* FunctionGenerator::context() { +llvm::LLVMContext* EmitterContext::context() { return context_; } -llvm::Module* FunctionGenerator::gen_module() { +llvm::Module* EmitterContext::gen_module() { return gen_module_; } -llvm::Function* FunctionGenerator::gen_fn() { +FunctionSymbol* EmitterContext::fn() { + return fn_; +} + +llvm::Function* EmitterContext::gen_fn() { return gen_fn_; } -FunctionBlock* FunctionGenerator::fn_block() { +FunctionBlock* EmitterContext::fn_block() { return fn_block_; } -void FunctionGenerator::PushInsertPoint() { +void EmitterContext::PushInsertPoint() { IRBuilder<>& b = *builder_; insert_points_.push_back(std::pair( b.GetInsertBlock(), b.GetInsertPoint())); } -void FunctionGenerator::PopInsertPoint() { +void EmitterContext::PopInsertPoint() { IRBuilder<>& b = *builder_; std::pair back = insert_points_.back(); b.SetInsertPoint(back.first, back.second); insert_points_.pop_back(); } -void FunctionGenerator::GenerateBasicBlocks() { +void EmitterContext::GenerateBasicBlocks() { IRBuilder<>& b = *builder_; // Always add an entry block. @@ -178,7 +197,7 @@ void FunctionGenerator::GenerateBasicBlocks() { GenerateSharedBlocks(); } -void FunctionGenerator::GenerateSharedBlocks() { +void EmitterContext::GenerateSharedBlocks() { IRBuilder<>& b = *builder_; Value* indirect_branch = gen_module_->getFunction("XeIndirectBranch"); @@ -225,7 +244,7 @@ void FunctionGenerator::GenerateSharedBlocks() { } } -int FunctionGenerator::PrepareBasicBlock(FunctionBlock* block) { +int EmitterContext::PrepareBasicBlock(FunctionBlock* block) { // Create the basic block that will end up getting filled during // generation. char name[32]; @@ -271,7 +290,7 @@ int FunctionGenerator::PrepareBasicBlock(FunctionBlock* block) { return 0; } -void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block) { +void EmitterContext::GenerateBasicBlock(FunctionBlock* block) { IRBuilder<>& b = *builder_; BasicBlock* bb = GetBasicBlock(block->start_address); @@ -337,7 +356,7 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block) { // builder_>SetCurrentDebugLocation(DebugLoc::get( // ia >> 8, ia & 0xFF, ctx->cu)); - typedef int (*InstrEmitter)(FunctionGenerator& g, IRBuilder<>& b, + typedef int (*InstrEmitter)(EmitterContext& g, IRBuilder<>& b, InstrData& i); InstrEmitter emit = (InstrEmitter)i.type->emit; if (!i.type->emit || emit(*this, *builder_, i)) { @@ -371,7 +390,7 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block) { // TODO(benvanik): finish up BB } -BasicBlock* FunctionGenerator::GetBasicBlock(uint32_t address) { +BasicBlock* EmitterContext::GetBasicBlock(uint32_t address) { std::map::iterator it = bbs_.find(address); if (it != bbs_.end()) { return it->second; @@ -379,7 +398,7 @@ BasicBlock* FunctionGenerator::GetBasicBlock(uint32_t address) { return NULL; } -BasicBlock* FunctionGenerator::GetNextBasicBlock() { +BasicBlock* EmitterContext::GetNextBasicBlock() { std::map::iterator it = bbs_.find( fn_block_->start_address); ++it; @@ -389,22 +408,49 @@ BasicBlock* FunctionGenerator::GetNextBasicBlock() { return NULL; } -BasicBlock* FunctionGenerator::GetReturnBasicBlock() { +BasicBlock* EmitterContext::GetReturnBasicBlock() { return return_block_; } -Function* FunctionGenerator::GetFunction(FunctionSymbol* fn) { - Function* result = gen_module_->getFunction(StringRef(fn->name())); - if (!result) { - XELOGE("Static function not found: %.8X %s", - fn->start_address, fn->name()); +Function* EmitterContext::GetFunction(FunctionSymbol* symbol) { + StringRef fn_name(symbol->name()); + Function* fn = gen_module_->getFunction(fn_name); + if (fn) { + return fn; } - XEASSERTNOTNULL(result); - return result; + + fn = cast(gen_module_->getOrInsertFunction(fn_name, fn_type_)); + fn->setVisibility(GlobalValue::DefaultVisibility); + + // Indicate that the function will never be unwound with an exception. + // If we ever support native exception handling we may need to remove this. + fn->doesNotThrow(); + + // May be worth trying the X86_FastCall, as we only need state in a register. + //f->setCallingConv(CallingConv::Fast); + fn->setCallingConv(CallingConv::C); + + Function::arg_iterator fn_args = fn->arg_begin(); + + // 'state' + Value* fn_arg = fn_args++; + fn_arg->setName("state"); + fn->setDoesNotAlias(1); + fn->setDoesNotCapture(1); + // 'state' should try to be in a register, if possible. + // TODO(benvanik): verify that's a good idea. + // fn->getArgumentList().begin()->addAttr( + // Attribute::get(context, AttrBuilder().addAttribute(Attribute::InReg))); + + // 'lr' + fn_arg = fn_args++; + fn_arg->setName("lr"); + + return fn; } -int FunctionGenerator::GenerateIndirectionBranch(uint32_t cia, Value* target, - bool lk, bool likely_local) { +int EmitterContext::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 @@ -489,8 +535,8 @@ int FunctionGenerator::GenerateIndirectionBranch(uint32_t cia, Value* target, return 0; } -Value* FunctionGenerator::LoadStateValue(uint32_t offset, Type* type, - const char* name) { +Value* EmitterContext::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(); @@ -500,8 +546,8 @@ Value* FunctionGenerator::LoadStateValue(uint32_t offset, Type* type, return b.CreateLoad(ptr, name); } -void FunctionGenerator::StoreStateValue(uint32_t offset, Type* type, - Value* value) { +void EmitterContext::StoreStateValue(uint32_t offset, Type* type, + Value* value) { IRBuilder<>& b = *builder_; PointerType* pointerTy = PointerType::getUnqual(type); Function::arg_iterator args = gen_fn_->arg_begin(); @@ -511,7 +557,7 @@ void FunctionGenerator::StoreStateValue(uint32_t offset, Type* type, b.CreateStore(value, ptr); } -void FunctionGenerator::SetupLocals() { +void EmitterContext::SetupLocals() { IRBuilder<>& b = *builder_; uint64_t spr_t = access_bits_.spr; @@ -559,7 +605,7 @@ void FunctionGenerator::SetupLocals() { } } -Value* FunctionGenerator::SetupLocal(llvm::Type* type, const char* name) { +Value* EmitterContext::SetupLocal(llvm::Type* type, const char* name) { IRBuilder<>& b = *builder_; // Insert into the entry block. PushInsertPoint(); @@ -569,11 +615,11 @@ Value* FunctionGenerator::SetupLocal(llvm::Type* type, const char* name) { return v; } -Value* FunctionGenerator::cia_value() { +Value* EmitterContext::cia_value() { return builder_->getInt32(cia_); } -void FunctionGenerator::FillRegisters() { +void EmitterContext::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. @@ -637,7 +683,7 @@ void FunctionGenerator::FillRegisters() { } } -void FunctionGenerator::SpillRegisters() { +void EmitterContext::SpillRegisters() { // This flushes all local registers (if written) to the register bank and // resets their values. // @@ -709,13 +755,13 @@ void FunctionGenerator::SpillRegisters() { } } -Value* FunctionGenerator::xer_value() { +Value* EmitterContext::xer_value() { XEASSERTNOTNULL(locals_.xer); IRBuilder<>& b = *builder_; return b.CreateLoad(locals_.xer); } -void FunctionGenerator::update_xer_value(Value* value) { +void EmitterContext::update_xer_value(Value* value) { XEASSERTNOTNULL(locals_.xer); IRBuilder<>& b = *builder_; @@ -726,7 +772,7 @@ void FunctionGenerator::update_xer_value(Value* value) { b.CreateStore(value, locals_.xer); } -void FunctionGenerator::update_xer_with_overflow(Value* value) { +void EmitterContext::update_xer_with_overflow(Value* value) { XEASSERTNOTNULL(locals_.xer); IRBuilder<>& b = *builder_; @@ -743,7 +789,7 @@ void FunctionGenerator::update_xer_with_overflow(Value* value) { b.CreateStore(xer, locals_.xer); } -void FunctionGenerator::update_xer_with_carry(Value* value) { +void EmitterContext::update_xer_with_carry(Value* value) { XEASSERTNOTNULL(locals_.xer); IRBuilder<>& b = *builder_; @@ -759,7 +805,7 @@ void FunctionGenerator::update_xer_with_carry(Value* value) { b.CreateStore(xer, locals_.xer); } -void FunctionGenerator::update_xer_with_overflow_and_carry(Value* value) { +void EmitterContext::update_xer_with_overflow_and_carry(Value* value) { XEASSERTNOTNULL(locals_.xer); IRBuilder<>& b = *builder_; @@ -779,13 +825,13 @@ void FunctionGenerator::update_xer_with_overflow_and_carry(Value* value) { b.CreateStore(xer, locals_.xer); } -Value* FunctionGenerator::lr_value() { +Value* EmitterContext::lr_value() { XEASSERTNOTNULL(locals_.lr); IRBuilder<>& b = *builder_; return b.CreateLoad(locals_.lr); } -void FunctionGenerator::update_lr_value(Value* value) { +void EmitterContext::update_lr_value(Value* value) { XEASSERTNOTNULL(locals_.lr); IRBuilder<>& b = *builder_; @@ -796,14 +842,14 @@ void FunctionGenerator::update_lr_value(Value* value) { b.CreateStore(value, locals_.lr); } -Value* FunctionGenerator::ctr_value() { +Value* EmitterContext::ctr_value() { XEASSERTNOTNULL(locals_.ctr); IRBuilder<>& b = *builder_; return b.CreateLoad(locals_.ctr); } -void FunctionGenerator::update_ctr_value(Value* value) { +void EmitterContext::update_ctr_value(Value* value) { XEASSERTNOTNULL(locals_.ctr); IRBuilder<>& b = *builder_; @@ -814,7 +860,7 @@ void FunctionGenerator::update_ctr_value(Value* value) { b.CreateStore(value, locals_.ctr); } -Value* FunctionGenerator::cr_value(uint32_t n) { +Value* EmitterContext::cr_value(uint32_t n) { XEASSERT(n >= 0 && n < 8); XEASSERTNOTNULL(locals_.cr[n]); IRBuilder<>& b = *builder_; @@ -824,7 +870,7 @@ Value* FunctionGenerator::cr_value(uint32_t n) { return v; } -void FunctionGenerator::update_cr_value(uint32_t n, Value* value) { +void EmitterContext::update_cr_value(uint32_t n, Value* value) { XEASSERT(n >= 0 && n < 8); XEASSERTNOTNULL(locals_.cr[n]); IRBuilder<>& b = *builder_; @@ -838,7 +884,7 @@ void FunctionGenerator::update_cr_value(uint32_t n, Value* value) { b.CreateStore(value, locals_.cr[n]); } -void FunctionGenerator::update_cr_with_cond( +void EmitterContext::update_cr_with_cond( uint32_t n, Value* lhs, Value* rhs, bool is_signed) { IRBuilder<>& b = *builder_; @@ -870,7 +916,7 @@ void FunctionGenerator::update_cr_with_cond( update_cr_value(n, c); } -Value* FunctionGenerator::gpr_value(uint32_t n) { +Value* EmitterContext::gpr_value(uint32_t n) { XEASSERT(n >= 0 && n < 32); XEASSERTNOTNULL(locals_.gpr[n]); IRBuilder<>& b = *builder_; @@ -885,7 +931,7 @@ Value* FunctionGenerator::gpr_value(uint32_t n) { return b.CreateLoad(locals_.gpr[n]); } -void FunctionGenerator::update_gpr_value(uint32_t n, Value* value) { +void EmitterContext::update_gpr_value(uint32_t n, Value* value) { XEASSERT(n >= 0 && n < 32); XEASSERTNOTNULL(locals_.gpr[n]); IRBuilder<>& b = *builder_; @@ -904,14 +950,14 @@ void FunctionGenerator::update_gpr_value(uint32_t n, Value* value) { b.CreateStore(value, locals_.gpr[n]); } -Value* FunctionGenerator::fpr_value(uint32_t n) { +Value* EmitterContext::fpr_value(uint32_t n) { XEASSERT(n >= 0 && n < 32); XEASSERTNOTNULL(locals_.fpr[n]); IRBuilder<>& b = *builder_; return b.CreateLoad(locals_.fpr[n]); } -void FunctionGenerator::update_fpr_value(uint32_t n, Value* value) { +void EmitterContext::update_fpr_value(uint32_t n, Value* value) { XEASSERT(n >= 0 && n < 32); XEASSERTNOTNULL(locals_.fpr[n]); IRBuilder<>& b = *builder_; @@ -919,12 +965,12 @@ void FunctionGenerator::update_fpr_value(uint32_t n, Value* value) { b.CreateStore(value, locals_.fpr[n]); } -Value* FunctionGenerator::GetMembase() { +Value* EmitterContext::GetMembase() { Value* v = gen_module_->getGlobalVariable("xe_memory_base"); return builder_->CreateLoad(v); } -Value* FunctionGenerator::GetMemoryAddress(uint32_t cia, Value* addr) { +Value* EmitterContext::GetMemoryAddress(uint32_t cia, Value* addr) { IRBuilder<>& b = *builder_; // Input address is always in 32-bit space. @@ -955,7 +1001,7 @@ Value* FunctionGenerator::GetMemoryAddress(uint32_t cia, Value* addr) { return b.CreateInBoundsGEP(GetMembase(), addr); } -Value* FunctionGenerator::ReadMemory( +Value* EmitterContext::ReadMemory( uint32_t cia, Value* addr, uint32_t size, bool acquire) { IRBuilder<>& b = *builder_; @@ -1004,7 +1050,7 @@ Value* FunctionGenerator::ReadMemory( return value; } -void FunctionGenerator::WriteMemory( +void EmitterContext::WriteMemory( uint32_t cia, Value* addr, uint32_t size, Value* value, bool release) { IRBuilder<>& b = *builder_; diff --git a/src/xenia/cpu/codegen/function_generator.h b/src/xenia/cpu/llvmbe/emitter_context.h similarity index 87% rename from src/xenia/cpu/codegen/function_generator.h rename to src/xenia/cpu/llvmbe/emitter_context.h index 0b48a75c4..d8bf22e84 100644 --- a/src/xenia/cpu/codegen/function_generator.h +++ b/src/xenia/cpu/llvmbe/emitter_context.h @@ -7,8 +7,8 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_CODEGEN_FUNCTION_GENERATOR_H_ -#define XENIA_CPU_CODEGEN_FUNCTION_GENERATOR_H_ +#ifndef XENIA_CPU_LLVMBE_EMITTER_CONTEXT_H_ +#define XENIA_CPU_LLVMBE_EMITTER_CONTEXT_H_ #include #include @@ -23,21 +23,22 @@ namespace xe { namespace cpu { -namespace codegen { +namespace llvmbe { -class FunctionGenerator { +class EmitterContext { public: - FunctionGenerator( - xe_memory_ref memory, sdb::SymbolDatabase* sdb, sdb::FunctionSymbol* fn, - llvm::LLVMContext* context, llvm::Module* gen_module, - llvm::Function* gen_fn); - ~FunctionGenerator(); + EmitterContext( + xe_memory_ref memory, + llvm::LLVMContext* context, llvm::Module* gen_module); + ~EmitterContext(); + + int Init(sdb::FunctionSymbol* fn, llvm::Function* gen_fn); - sdb::SymbolDatabase* sdb(); - sdb::FunctionSymbol* fn(); llvm::LLVMContext* context(); llvm::Module* gen_module(); + + sdb::FunctionSymbol* fn(); llvm::Function* gen_fn(); sdb::FunctionBlock* fn_block(); @@ -49,7 +50,7 @@ public: llvm::BasicBlock* GetNextBasicBlock(); llvm::BasicBlock* GetReturnBasicBlock(); - llvm::Function* GetFunction(sdb::FunctionSymbol* fn); + llvm::Function* GetFunction(sdb::FunctionSymbol* symbol); int GenerateIndirectionBranch(uint32_t cia, llvm::Value* target, bool lk, bool likely_local); @@ -101,17 +102,18 @@ private: void SetupLocals(); xe_memory_ref memory_; - sdb::SymbolDatabase* sdb_; - sdb::FunctionSymbol* fn_; llvm::LLVMContext* context_; llvm::Module* gen_module_; + llvm::IRBuilder<>* builder_; + llvm::FunctionType* fn_type_; + + sdb::FunctionSymbol* fn_; llvm::Function* gen_fn_; sdb::FunctionBlock* fn_block_; llvm::BasicBlock* return_block_; llvm::BasicBlock* internal_indirection_block_; llvm::BasicBlock* external_indirection_block_; llvm::BasicBlock* bb_; - llvm::IRBuilder<>* builder_; std::vector > insert_points_; @@ -136,9 +138,9 @@ private: }; -} // namespace codegen +} // namespace llvmbe } // namespace cpu } // namespace xe -#endif // XENIA_CPU_CODEGEN_FUNCTION_GENERATOR_H_ +#endif // XENIA_CPU_LLVMBE_EMITTER_CONTEXT_H_ diff --git a/src/xenia/cpu/llvmbe/llvm_backend.cc b/src/xenia/cpu/llvmbe/llvm_backend.cc new file mode 100644 index 000000000..97799d87d --- /dev/null +++ b/src/xenia/cpu/llvmbe/llvm_backend.cc @@ -0,0 +1,82 @@ +/** + ****************************************************************************** + * 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 +#include +#include +#include + +#include +#include + + +using namespace llvm; +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::llvmbe; + + +namespace { + void InitializeIfNeeded(); + void CleanupOnShutdown(); + + void InitializeIfNeeded() { + static bool has_initialized = false; + if (has_initialized) { + return; + } + has_initialized = true; + + LLVMLinkInInterpreter(); + LLVMLinkInJIT(); + InitializeNativeTarget(); + + llvm_start_multithreaded(); + + llvmbe::RegisterEmitCategoryALU(); + llvmbe::RegisterEmitCategoryControl(); + llvmbe::RegisterEmitCategoryFPU(); + llvmbe::RegisterEmitCategoryMemory(); + + atexit(CleanupOnShutdown); + } + + void CleanupOnShutdown() { + llvm_shutdown(); + } +} + + +LLVMBackend::LLVMBackend() : + Backend() { + InitializeIfNeeded(); +} + +LLVMBackend::~LLVMBackend() { +} + +CodeUnitBuilder* LLVMBackend::CreateCodeUnitBuilder() { + return NULL; +} + +LibraryLinker* LLVMBackend::CreateLibraryLinker() { + return NULL; +} + +LibraryLoader* LLVMBackend::CreateLibraryLoader() { + return NULL; +} + +JIT* LLVMBackend::CreateJIT(xe_memory_ref memory, FunctionTable* fn_table) { + return new LLVMJIT(memory, fn_table); +} diff --git a/src/xenia/cpu/llvmbe/llvm_backend.h b/src/xenia/cpu/llvmbe/llvm_backend.h new file mode 100644 index 000000000..90c3f8269 --- /dev/null +++ b/src/xenia/cpu/llvmbe/llvm_backend.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_LLVMBE_LLVM_BACKEND_H_ +#define XENIA_CPU_LLVMBE_LLVM_BACKEND_H_ + +#include + +#include + + +namespace xe { +namespace cpu { +namespace llvmbe { + + +class LLVMBackend : public Backend { +public: + LLVMBackend(); + virtual ~LLVMBackend(); + + virtual CodeUnitBuilder* CreateCodeUnitBuilder(); + virtual LibraryLinker* CreateLibraryLinker(); + virtual LibraryLoader* CreateLibraryLoader(); + + virtual JIT* CreateJIT(xe_memory_ref memory, FunctionTable* fn_table); + +protected: +}; + + +} // namespace llvmbe +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LLVMBE_LLVM_BACKEND_H_ diff --git a/src/xenia/cpu/llvmbe/llvm_code_unit_builder.cc b/src/xenia/cpu/llvmbe/llvm_code_unit_builder.cc new file mode 100644 index 000000000..18e1db947 --- /dev/null +++ b/src/xenia/cpu/llvmbe/llvm_code_unit_builder.cc @@ -0,0 +1,264 @@ +/** + ****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +using namespace llvm; +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::llvmbe; +using namespace xe::cpu::sdb; + + +LLVMCodeUnitBuilder::LLVMCodeUnitBuilder( + xe_memory_ref memory, LLVMContext* context) : + CodeUnitBuilder(memory), + context_(context) { +} + +LLVMCodeUnitBuilder::~LLVMCodeUnitBuilder() { + Reset(); +} + +Module* LLVMCodeUnitBuilder::module() { + return module_; +} + +int LLVMCodeUnitBuilder::Init(const char* module_name, + const char* module_path) { + Reset(); + + // Create LLVM module. + module_ = new Module(module_name, *context_); + + // Create the emitter used to generate functions. + emitter_ = new EmitterContext(memory_, context_, module_); + + // Setup optimization pass. + fpm_ = new FunctionPassManager(module_); + if (FLAGS_optimize_ir_functions) { + PassManagerBuilder pmb; + pmb.OptLevel = 3; + pmb.SizeLevel = 0; + pmb.Inliner = createFunctionInliningPass(); + pmb.Vectorize = true; + pmb.LoopVectorize = true; + pmb.populateFunctionPassManager(*fpm_); + } + // TODO(benvanik): disable verifier in release builds? + fpm_->add(createVerifierPass()); + + // Setup a debug info builder. + // This is used when creating any debug info. We may want to go more + // fine grained than this, but for now it's something. + char dir[XE_MAX_PATH]; + XEIGNORE(xestrcpya(dir, XECOUNT(dir), module_path)); + char* slash = xestrrchra(dir, '/'); + if (slash) { + *(slash + 1) = 0; + } + di_builder_ = new DIBuilder(*module_); + di_builder_->createCompileUnit( + dwarf::DW_LANG_C99, //0x8010, + StringRef(module_name), + StringRef(dir), + StringRef("xenia"), + true, + StringRef(""), + 0); + cu_ = (MDNode*)di_builder_->getCU(); + + return 0; +} + +int LLVMCodeUnitBuilder::MakeFunction(FunctionSymbol* symbol) { + return MakeFunction(symbol, NULL); +} + +int LLVMCodeUnitBuilder::MakeFunction(FunctionSymbol* symbol, + Function** out_fn) { + int result_code = 0; + + // Create the function (and setup args/attributes/etc). + Function* fn = emitter_->GetFunction(symbol); + + // If already defined, ignore. + if (!fn->isDeclaration()) { + if (out_fn) { + *out_fn = fn; + } + return 0; + } + + switch (symbol->type) { + case FunctionSymbol::User: + result_code = MakeUserFunction(symbol, fn); + break; + case FunctionSymbol::Kernel: + if (symbol->kernel_export && symbol->kernel_export->is_implemented) { + result_code = MakePresentImportFunction(symbol, fn); + } else { + result_code = MakeMissingImportFunction(symbol, fn); + } + break; + default: + XEASSERTALWAYS(); + return 1; + } + if (result_code) { + return result_code; + } + + // Run the optimizer on the function. + // Doing this here keeps the size of the IR small and speeds up the later + // passes. + OptimizeFunction(fn); + + // Add to map for processing later. + functions_.insert(std::pair(symbol->start_address, fn)); + + if (out_fn) { + *out_fn = fn; + } + + return 0; +} + +int LLVMCodeUnitBuilder::MakeUserFunction(FunctionSymbol* symbol, + Function* fn) { + // Setup emitter. + emitter_->Init(symbol, fn); + + // Emit. + emitter_->GenerateBasicBlocks(); + + return 0; +} + +int LLVMCodeUnitBuilder::MakePresentImportFunction(FunctionSymbol* symbol, + Function* fn) { + LLVMContext& context = *context_; + + // 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) { + Value* traceKernelCall = module_->getFunction("XeTraceKernelCall"); + b.CreateCall4( + traceKernelCall, + fn->arg_begin(), + b.getInt64(symbol->start_address), + ++fn->arg_begin(), + b.getInt64((uint64_t)symbol->kernel_export)); + } + + b.CreateCall2( + shim, + fn->arg_begin(), + b.CreateLoad(shim_data)); + + b.CreateRetVoid(); + + return 0; +} + +int LLVMCodeUnitBuilder::MakeMissingImportFunction(FunctionSymbol* symbol, + Function* fn) { + BasicBlock* block = BasicBlock::Create(*context_, "entry", fn); + IRBuilder<> b(block); + + if (FLAGS_trace_kernel_calls) { + Value* traceKernelCall = module_->getFunction("XeTraceKernelCall"); + b.CreateCall4( + traceKernelCall, + fn->arg_begin(), + b.getInt64(symbol->start_address), + ++fn->arg_begin(), + b.getInt64((uint64_t)symbol->kernel_export)); + } + + b.CreateRetVoid(); + + return 0; +} + +void LLVMCodeUnitBuilder::OptimizeFunction(Function* fn) { + //fn->dump(); + fpm_->run(*fn); + fn->dump(); +} + +int LLVMCodeUnitBuilder::Finalize() { + // Finalize debug info. + di_builder_->finalize(); + + // TODO(benvanik): run module optimizations, if enabled. + + return 0; +} + +void LLVMCodeUnitBuilder::Reset() { + functions_.clear(); + + delete emitter_; + emitter_ = NULL; + delete di_builder_; + di_builder_ = NULL; + delete fpm_; + fpm_ = NULL; + delete module_; + module_ = NULL; +} diff --git a/src/xenia/cpu/llvmbe/llvm_code_unit_builder.h b/src/xenia/cpu/llvmbe/llvm_code_unit_builder.h new file mode 100644 index 000000000..4557cc4b1 --- /dev/null +++ b/src/xenia/cpu/llvmbe/llvm_code_unit_builder.h @@ -0,0 +1,77 @@ +/** + ****************************************************************************** + * 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_LLVMBE_LLVM_CODE_UNIT_BUILDER_H_ +#define XENIA_CPU_LLVMBE_LLVM_CODE_UNIT_BUILDER_H_ + +#include +#include + +#include +#include + + +namespace llvm { + class DIBuilder; + class Function; + class FunctionPassManager; + class LLVMContext; + class Module; + class MDNode; +} + + +namespace xe { +namespace cpu { +namespace llvmbe { + + +class EmitterContext; + + +class LLVMCodeUnitBuilder : public CodeUnitBuilder { +public: + LLVMCodeUnitBuilder(xe_memory_ref memory, llvm::LLVMContext* context); + virtual ~LLVMCodeUnitBuilder(); + + llvm::Module* module(); + + virtual int Init(const char* module_name, const char* module_path); + virtual int MakeFunction(sdb::FunctionSymbol* symbol); + int MakeFunction(sdb::FunctionSymbol* symbol, llvm::Function** out_fn); + virtual int Finalize(); + virtual void Reset(); + +private: + llvm::Function* CreateFunctionDeclaration(const char* name); + int MakeUserFunction(sdb::FunctionSymbol* symbol, + llvm::Function* f); + int MakePresentImportFunction(sdb::FunctionSymbol* symbol, + llvm::Function* f); + int MakeMissingImportFunction(sdb::FunctionSymbol* symbol, + llvm::Function* f); + void OptimizeFunction(llvm::Function* f); + + llvm::LLVMContext* context_; + llvm::Module* module_; + llvm::FunctionPassManager* fpm_; + llvm::DIBuilder* di_builder_; + llvm::MDNode* cu_; + EmitterContext* emitter_; + + std::map functions_; +}; + + +} // namespace llvmbe +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LLVMBE_LLVM_CODE_UNIT_BUILDER_H_ diff --git a/src/xenia/cpu/llvm_exports.cc b/src/xenia/cpu/llvmbe/llvm_exports.cc similarity index 56% rename from src/xenia/cpu/llvm_exports.cc rename to src/xenia/cpu/llvmbe/llvm_exports.cc index 8a5c97b33..389e424cf 100644 --- a/src/xenia/cpu/llvm_exports.cc +++ b/src/xenia/cpu/llvmbe/llvm_exports.cc @@ -7,7 +7,7 @@ ****************************************************************************** */ -#include +#include #include #include @@ -16,95 +16,15 @@ #include #include -#include -#include -#include -#include - using namespace llvm; using namespace xe; using namespace xe::cpu; -using namespace xe::cpu::sdb; -using namespace xe::kernel; -namespace { - - -void XeTrap(xe_ppc_state_t* state, uint32_t cia) { - XELOGE("TRAP"); - XEASSERTALWAYS(); -} - -void XeIndirectBranch(xe_ppc_state_t* state, uint64_t target, uint64_t br_ia) { - 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) { - ppc::InstrData i; - i.address = cia; - i.code = data; - i.type = ppc::GetInstrType(i.code); - - if (!i.type) { - XELOGCPU("INVALID INSTRUCTION %.8X: %.8X ???", - i.address, i.code); - } else if (i.type->disassemble) { - ppc::InstrDisasm d; - i.type->disassemble(i, d); - std::string disasm; - d.Dump(disasm); - XELOGCPU("INVALID INSTRUCTION %.8X: %.8X %s", - i.address, i.code, disasm.c_str()); - } else { - XELOGCPU("INVALID INSTRUCTION %.8X: %.8X %s", - i.address, i.code, i.type->name); - } -} - -void XeAccessViolation(xe_ppc_state_t* state, uint32_t cia, uint64_t ea) { - 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) { - 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) { - 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) { - ppc::InstrType* type = ppc::GetInstrType(data); - XELOGCPU("TRACE: %.8X %.8X %s %s", - cia, data, - type && type->emit ? " " : "X", - type ? type->name : ""); - - if (cia == 0x82014468) { - printf("BREAKBREAKBREAK\n"); - } - - // TODO(benvanik): better disassembly, printing of current register values/etc -} - - -} - - -void xe::cpu::SetupLlvmExports(llvm::Module* module, - const llvm::DataLayout* dl, - llvm::ExecutionEngine* engine) { +void xe::cpu::llvmbe::SetupLlvmExports( + GlobalExports* global_exports, + Module* module, const DataLayout* dl, ExecutionEngine* engine) { LLVMContext& context = module->getContext(); Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context)); @@ -116,7 +36,7 @@ void xe::cpu::SetupLlvmExports(llvm::Module* module, Type::getVoidTy(context), trapArgs, false); engine->addGlobalMapping(Function::Create( trapTy, Function::ExternalLinkage, "XeTrap", - module), (void*)&XeTrap); + module), (void*)(global_exports->XeTrap)); std::vector indirectBranchArgs; indirectBranchArgs.push_back(int8PtrTy); @@ -126,7 +46,7 @@ void xe::cpu::SetupLlvmExports(llvm::Module* module, Type::getVoidTy(context), indirectBranchArgs, false); engine->addGlobalMapping(Function::Create( indirectBranchTy, Function::ExternalLinkage, "XeIndirectBranch", - module), (void*)&XeIndirectBranch); + module), (void*)(global_exports->XeIndirectBranch)); // Debugging methods: std::vector invalidInstructionArgs; @@ -137,7 +57,7 @@ void xe::cpu::SetupLlvmExports(llvm::Module* module, Type::getVoidTy(context), invalidInstructionArgs, false); engine->addGlobalMapping(Function::Create( invalidInstructionTy, Function::ExternalLinkage, "XeInvalidInstruction", - module), (void*)&XeInvalidInstruction); + module), (void*)(global_exports->XeInvalidInstruction)); std::vector accessViolationArgs; accessViolationArgs.push_back(int8PtrTy); @@ -147,7 +67,7 @@ void xe::cpu::SetupLlvmExports(llvm::Module* module, Type::getVoidTy(context), accessViolationArgs, false); engine->addGlobalMapping(Function::Create( accessViolationTy, Function::ExternalLinkage, "XeAccessViolation", - module), (void*)&XeAccessViolation); + module), (void*)(global_exports->XeAccessViolation)); // Tracing methods: std::vector traceCallArgs; @@ -166,11 +86,11 @@ void xe::cpu::SetupLlvmExports(llvm::Module* module, engine->addGlobalMapping(Function::Create( traceCallTy, Function::ExternalLinkage, "XeTraceKernelCall", - module), (void*)&XeTraceKernelCall); + module), (void*)(global_exports->XeTraceKernelCall)); engine->addGlobalMapping(Function::Create( traceCallTy, Function::ExternalLinkage, "XeTraceUserCall", - module), (void*)&XeTraceUserCall); + module), (void*)(global_exports->XeTraceUserCall)); engine->addGlobalMapping(Function::Create( traceInstructionTy, Function::ExternalLinkage, "XeTraceInstruction", - module), (void*)&XeTraceInstruction); + module), (void*)(global_exports->XeTraceInstruction)); } diff --git a/src/xenia/cpu/llvm_exports.h b/src/xenia/cpu/llvmbe/llvm_exports.h similarity index 66% rename from src/xenia/cpu/llvm_exports.h rename to src/xenia/cpu/llvmbe/llvm_exports.h index 36c8ad1c0..48a6a28fa 100644 --- a/src/xenia/cpu/llvm_exports.h +++ b/src/xenia/cpu/llvmbe/llvm_exports.h @@ -7,16 +7,17 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_LLVM_EXPORTS_H_ -#define XENIA_CPU_LLVM_EXPORTS_H_ +#ifndef XENIA_CPU_LLVMBE_LLVM_EXPORTS_H_ +#define XENIA_CPU_LLVMBE_LLVM_EXPORTS_H_ #include #include +#include + namespace llvm { class ExecutionEngine; - class LLVMContext; class Module; class DataLayout; } @@ -24,15 +25,18 @@ namespace llvm { namespace xe { namespace cpu { +namespace llvmbe { -void SetupLlvmExports(llvm::Module* module, - const llvm::DataLayout* dl, - llvm::ExecutionEngine* engine); +void SetupLlvmExports( + GlobalExports* global_exports, + llvm::Module* module, const llvm::DataLayout* dl, + llvm::ExecutionEngine* engine); +} // llvmbe } // cpu } // xe -#endif // XENIA_CPU_LLVM_EXPORTS_H_ +#endif // XENIA_CPU_LLVMBE_LLVM_EXPORTS_H_ diff --git a/src/xenia/cpu/llvmbe/llvm_jit.cc b/src/xenia/cpu/llvmbe/llvm_jit.cc new file mode 100644 index 000000000..87c7f5102 --- /dev/null +++ b/src/xenia/cpu/llvmbe/llvm_jit.cc @@ -0,0 +1,211 @@ +/** + ****************************************************************************** + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +using namespace llvm; +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::llvmbe; +using namespace xe::cpu::sdb; + + +LLVMJIT::LLVMJIT(xe_memory_ref memory, FunctionTable* fn_table) : + JIT(memory, fn_table), + context_(NULL), engine_(NULL), module_(NULL), cub_(NULL) { +} + +LLVMJIT::~LLVMJIT() { + delete cub_; + if (engine_) { + engine_->removeModule(module_); + } + delete engine_; + delete context_; +} + +//namespace { +//void* LazyFunctionCreator(const std::string& name) { +// printf("lazy: %s", name.c_str()); +// return NULL; +//} +//} + +int LLVMJIT::Setup() { + int result_code = 1; + std::string error_message; + + context_ = new LLVMContext(); + + // Create a shared code unit builder used while JITing. + // Since there's only one we'll need to lock when generating code. + // In the future we could try to generate new code in separate CUBs and then + // link into the main module under the lock. + cub_ = new LLVMCodeUnitBuilder(memory_, context_); + result_code = cub_->Init("jit", ""); + if (result_code) { + return result_code; + } + module_ = cub_->module(); + + EngineBuilder builder(module_); + builder.setEngineKind(EngineKind::JIT); + builder.setErrorStr(&error_message); + builder.setOptLevel(CodeGenOpt::None); + //builder.setOptLevel(CodeGenOpt::Aggressive); + //builder.setJITMemoryManager(jmm); + //builder.setTargetOptions(); + builder.setAllocateGVsWithCode(false); + //builder.setUseMCJIT(true); + + engine_ = builder.create(); + XEEXPECTNOTNULL(engine_); + //engine_->DisableSymbolSearching(); + //engine_->InstallLazyFunctionCreator(LazyFunctionCreator); + + XEEXPECTZERO(InjectGlobals()); + + result_code = 0; +XECLEANUP: + return result_code; +} + +int LLVMJIT::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)); + + // Setup global exports (the Xe* functions called by generated code). + GlobalExports global_exports; + cpu::GetGlobalExports(&global_exports); + SetupLlvmExports(&global_exports, module_, dl, engine_); + + return 0; +} + +int LLVMJIT::InitModule(ExecModule* module) { + SymbolDatabase* sdb = module->sdb(); + Module* cub_module = cub_->module(); + + // Setup all imports (as needed). + std::vector functions; + if (sdb->GetAllFunctions(functions)) { + return 1; + } + int result_code = 0; + for (std::vector::iterator it = functions.begin(); + it != functions.end(); ++it) { + FunctionSymbol* symbol = *it; + if (symbol->type == FunctionSymbol::Kernel) { + // 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); + } + } + } + + return 0; +} + +int LLVMJIT::UninitModule(ExecModule* module) { + return 0; +} + +FunctionPointer LLVMJIT::GenerateFunction(FunctionSymbol* symbol) { + // In theory this is only called when required, so just assume we need to + // generate it. + + // Lock the function for adding. + // If this fails it means the function exists and we don't need to generate + // it. + FunctionPointer ptr = fn_table_->BeginAddFunction(symbol->start_address); + if (ptr) { + return ptr; + } + + printf("generating %s...\n", symbol->name()); + + Function* fn = NULL; + int result_code = cub_->MakeFunction(symbol, &fn); + if (result_code) { + XELOGE("Unable to generate function %s", symbol->name()); + return NULL; + } + + // LLVM requires all functions called to be defined at the time of + // getPointerToFunction, so this does a recursive depth-first walk + // to generate them. + for (std::vector::iterator it = symbol->outgoing_calls.begin(); + it != symbol->outgoing_calls.end(); ++it) { + FunctionSymbol* target = it->target; + printf("needs dep fn %s\n", target->name()); + GenerateFunction(target); + } + + // Generate the machine code. + ptr = (FunctionPointer)engine_->getPointerToFunction(fn); + + // Add to the function table. + fn_table_->AddFunction(symbol->start_address, ptr); + + return ptr; +} diff --git a/src/xenia/cpu/llvmbe/llvm_jit.h b/src/xenia/cpu/llvmbe/llvm_jit.h new file mode 100644 index 000000000..f88c5481e --- /dev/null +++ b/src/xenia/cpu/llvmbe/llvm_jit.h @@ -0,0 +1,64 @@ +/** + ****************************************************************************** + * 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_LLVMBE_LLVM_JIT_H_ +#define XENIA_CPU_LLVMBE_LLVM_JIT_H_ + +#include + +#include +#include +#include +#include + + +namespace llvm { + class ExecutionEngine; + class LLVMContext; + class Module; +} + + +namespace xe { +namespace cpu { +namespace llvmbe { + + +class LLVMCodeUnitBuilder; + + +class LLVMJIT : public JIT { +public: + LLVMJIT(xe_memory_ref memory, FunctionTable* fn_table); + virtual ~LLVMJIT(); + + virtual int Setup(); + + virtual int InitModule(ExecModule* module); + virtual int UninitModule(ExecModule* module); + + virtual FunctionPointer GenerateFunction(sdb::FunctionSymbol* symbol); + +protected: + int InjectGlobals(); + + llvm::LLVMContext* context_; + llvm::ExecutionEngine* engine_; + llvm::Module* module_; + + LLVMCodeUnitBuilder* cub_; +}; + + +} // namespace llvmbe +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LLVMBE_LLVM_JIT_H_ diff --git a/src/xenia/cpu/xethunk/xethunk.h b/src/xenia/cpu/llvmbe/llvm_library_linker.cc similarity index 60% rename from src/xenia/cpu/xethunk/xethunk.h rename to src/xenia/cpu/llvmbe/llvm_library_linker.cc index 3b51837aa..8b8d18d38 100644 --- a/src/xenia/cpu/xethunk/xethunk.h +++ b/src/xenia/cpu/llvmbe/llvm_library_linker.cc @@ -7,14 +7,18 @@ ****************************************************************************** */ -/** - * This file is shared between xethunk and the loader to pass structures - * between the two. Since this file is compiled with the LLVM clang it cannot - * include any other files. - */ - -#ifndef XENIA_CPU_XETHUNK_H_ -#define XENIA_CPU_XETHUNK_H_ +#include -#endif // XENIA_CPU_XETHUNK_H_ +using namespace xe; +using namespace xe::cpu; +using namespace xe::cpu::llvmbe; + + +LLVMLibraryLinker::LLVMLibraryLinker( + xe_memory_ref memory, kernel::ExportResolver* export_resolver) : + LibraryLinker(memory, export_resolver) { +} + +LLVMLibraryLinker::~LLVMLibraryLinker() { +} diff --git a/src/xenia/cpu/llvmbe/llvm_library_linker.h b/src/xenia/cpu/llvmbe/llvm_library_linker.h new file mode 100644 index 000000000..bf7beb0ab --- /dev/null +++ b/src/xenia/cpu/llvmbe/llvm_library_linker.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_LLVMBE_LLVM_LIBRARY_LINKER_H_ +#define XENIA_CPU_LLVMBE_LLVM_LIBRARY_LINKER_H_ + +#include +#include + +#include + + +namespace xe { +namespace cpu { +namespace llvmbe { + + +class LLVMLibraryLinker : public LibraryLinker { +public: + LLVMLibraryLinker(xe_memory_ref memory, + kernel::ExportResolver* export_resolver); + virtual ~LLVMLibraryLinker(); +}; + + +} // namespace llvmbe +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LLVMBE_LLVM_LIBRARY_LINKER_H_ diff --git a/src/xenia/cpu/llvmbe/llvm_library_loader.cc b/src/xenia/cpu/llvmbe/llvm_library_loader.cc new file mode 100644 index 000000000..07a0bc781 --- /dev/null +++ b/src/xenia/cpu/llvmbe/llvm_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::llvmbe; + + +LLVMLibraryLoader::LLVMLibraryLoader( + xe_memory_ref memory, kernel::ExportResolver* export_resolver) : + LibraryLoader(memory, export_resolver) { +} + +LLVMLibraryLoader::~LLVMLibraryLoader() { +} diff --git a/src/xenia/cpu/llvmbe/llvm_library_loader.h b/src/xenia/cpu/llvmbe/llvm_library_loader.h new file mode 100644 index 000000000..dc4fe5f2b --- /dev/null +++ b/src/xenia/cpu/llvmbe/llvm_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_LLVMBE_LLVM_LIBRARY_LOADER_H_ +#define XENIA_CPU_LLVMBE_LLVM_LIBRARY_LOADER_H_ + +#include +#include + +#include + + +namespace xe { +namespace cpu { +namespace llvmbe { + + +class LLVMLibraryLoader : public LibraryLoader { +public: + LLVMLibraryLoader(xe_memory_ref memory, + kernel::ExportResolver* export_resolver); + virtual ~LLVMLibraryLoader(); +}; + + +} // namespace llvmbe +} // namespace cpu +} // namespace xe + + +#endif // XENIA_CPU_LLVMBE_LLVM_LIBRARY_LOADER_H_ diff --git a/src/xenia/cpu/llvmbe/sources.gypi b/src/xenia/cpu/llvmbe/sources.gypi new file mode 100644 index 000000000..c45929b45 --- /dev/null +++ b/src/xenia/cpu/llvmbe/sources.gypi @@ -0,0 +1,24 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'emit.h', + 'emit_alu.cc', + 'emit_control.cc', + 'emit_fpu.cc', + 'emit_memory.cc', + 'emitter_context.cc', + 'emitter_context.h', + 'llvm_backend.cc', + 'llvm_backend.h', + 'llvm_code_unit_builder.cc', + 'llvm_code_unit_builder.h', + 'llvm_exports.cc', + 'llvm_exports.h', + 'llvm_jit.cc', + 'llvm_jit.h', + 'llvm_library_linker.cc', + 'llvm_library_linker.h', + 'llvm_library_loader.cc', + 'llvm_library_loader.h', + ], +} diff --git a/src/xenia/cpu/ppc/disasm_memory.cc b/src/xenia/cpu/ppc/disasm_memory.cc index e15ef8f3d..dd58bbf3c 100644 --- a/src/xenia/cpu/ppc/disasm_memory.cc +++ b/src/xenia/cpu/ppc/disasm_memory.cc @@ -717,22 +717,12 @@ XEDISASMR(dcbt, 0x7C00022C, X )(InstrData& i, InstrDisasm& d) { // TODO return d.Finish(); } -XEDISASMR(dcbt, 0x7C00022C, X )(InstrData& i, InstrDisasm& d) { - // No-op for now. - // TODO(benvanik): use @llvm.prefetch - return 0; -} XEDISASMR(dcbtst, 0x7C0001EC, X )(InstrData& i, InstrDisasm& d) { d.Init("dcbtst", "Data Cache Block Touch for Store", 0); // TODO return d.Finish(); } -XEDISASMR(dcbtst, 0x7C0001EC, X )(InstrData& i, InstrDisasm& d) { - // No-op for now. - // TODO(benvanik): use @llvm.prefetch - return 0; -} XEDISASMR(dcbz, 0x7C0007EC, X )(InstrData& i, InstrDisasm& d) { // or dcbz128 0x7C2007EC diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 01ed04460..178ece776 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -9,19 +9,10 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include -using namespace llvm; using namespace xe; using namespace xe::cpu; using namespace xe::kernel; @@ -38,36 +29,23 @@ namespace { } has_initialized = true; - // TODO(benvanik): only do this once - LLVMLinkInInterpreter(); - LLVMLinkInJIT(); - InitializeNativeTarget(); - - llvm_start_multithreaded(); - ppc::RegisterDisasmCategoryALU(); ppc::RegisterDisasmCategoryControl(); ppc::RegisterDisasmCategoryFPU(); ppc::RegisterDisasmCategoryMemory(); - // TODO(benvanik): only do this once - codegen::RegisterEmitCategoryALU(); - codegen::RegisterEmitCategoryControl(); - codegen::RegisterEmitCategoryFPU(); - codegen::RegisterEmitCategoryMemory(); - atexit(CleanupOnShutdown); } void CleanupOnShutdown() { - llvm_shutdown(); } } -Processor::Processor(xe_pal_ref pal, xe_memory_ref memory) { - pal_ = xe_pal_retain(pal); +Processor::Processor(xe_memory_ref memory, shared_ptr backend) : + fn_table_(NULL), jit_(NULL) { memory_ = xe_memory_retain(memory); + backend_ = backend; InitializeIfNeeded(); } @@ -76,55 +54,55 @@ Processor::~Processor() { // Cleanup all modules. for (std::vector::iterator it = modules_.begin(); it != modules_.end(); ++it) { - delete *it; + ExecModule* exec_module = *it; + if (jit_) { + jit_->UninitModule(exec_module); + } + delete exec_module; } + modules_.clear(); - engine_.reset(); + delete jit_; + delete fn_table_; + export_resolver_.reset(); + backend_.reset(); xe_memory_release(memory_); - xe_pal_release(pal_); -} - -xe_pal_ref Processor::pal() { - return xe_pal_retain(pal_); } xe_memory_ref Processor::memory() { return xe_memory_retain(memory_); } +shared_ptr Processor::export_resolver() { + return export_resolver_; +} + +void Processor::set_export_resolver( + shared_ptr export_resolver) { + export_resolver_ = export_resolver; +} + int Processor::Setup() { - XEASSERTNULL(engine_); + XEASSERTNULL(jit_); - dummy_context_ = auto_ptr(new LLVMContext()); - Module* dummy_module = new Module("dummy", *dummy_context_.get()); + fn_table_ = new FunctionTable(); - std::string error_message; - - EngineBuilder builder(dummy_module); - builder.setEngineKind(EngineKind::JIT); - builder.setErrorStr(&error_message); - builder.setOptLevel(CodeGenOpt::None); - //builder.setOptLevel(CodeGenOpt::Aggressive); - //builder.setTargetOptions(); - builder.setAllocateGVsWithCode(false); - //builder.setUseMCJIT(true); - - engine_ = shared_ptr(builder.create()); - if (!engine_) { + jit_ = backend_->CreateJIT(memory_, fn_table_); + if (jit_->Setup()) { + XELOGE("Unable to create JIT"); return 1; } return 0; } -int Processor::LoadBinary(const xechar_t* path, uint32_t start_address, - shared_ptr export_resolver) { +int Processor::LoadRawBinary(const xechar_t* path, uint32_t start_address) { ExecModule* exec_module = NULL; const xechar_t* name = xestrrchr(path, '/') + 1; - // TODO(benvanik): map file from filesystem - xe_mmap_ref mmap = xe_mmap_open(pal_, kXEFileModeRead, path, 0, 0); + // TODO(benvanik): map file from filesystem API, not via platform API. + xe_mmap_ref mmap = xe_mmap_open(kXEFileModeRead, path, 0, 0); if (!mmap) { return NULL; } @@ -133,30 +111,29 @@ int Processor::LoadBinary(const xechar_t* path, uint32_t start_address, int result_code = 1; + // Place the data into memory at the desired address. XEEXPECTZERO(xe_copy_memory(xe_memory_addr(memory_, start_address), xe_memory_get_length(memory_), addr, length)); - // Prepare the module. char name_a[XE_MAX_PATH]; XEEXPECTTRUE(xestrnarrow(name_a, XECOUNT(name_a), name)); char path_a[XE_MAX_PATH]; XEEXPECTTRUE(xestrnarrow(path_a, XECOUNT(path_a), path)); + // Prepare the module. + // This will analyze it, generate code (if needed), and adds methods to + // the function table. exec_module = new ExecModule( - memory_, export_resolver, name_a, path_a, engine_); + memory_, export_resolver_, fn_table_, name_a, path_a); + XEEXPECTZERO(exec_module->PrepareRawBinary( + start_address, start_address + (uint32_t)length)); - if (exec_module->PrepareRawBinary(start_address, - start_address + (uint32_t)length)) { - delete exec_module; - return 1; - } + // Initialize the module and prepare it for execution. + XEEXPECTZERO(jit_->InitModule(exec_module)); - exec_module->AddFunctionsToMap(all_fns_); modules_.push_back(exec_module); - exec_module->Dump(); - result_code = 0; XECLEANUP: if (result_code) { @@ -166,22 +143,28 @@ XECLEANUP: return result_code; } -int Processor::PrepareModule(const char* name, const char* path, - xe_xex2_ref xex, - shared_ptr export_resolver) { +int Processor::LoadXexModule(const char* name, const char* path, + xe_xex2_ref xex) { + int result_code = 1; + + // Prepare the module. + // This will analyze it, generate code (if needed), and adds methods to + // the function table. ExecModule* exec_module = new ExecModule( - memory_, export_resolver, name, path, - engine_); + memory_, export_resolver_, fn_table_, name, path); + XEEXPECTZERO(exec_module->PrepareXexModule(xex)); - if (exec_module->PrepareXex(xex)) { - delete exec_module; - return 1; - } + // Initialize the module and prepare it for execution. + XEEXPECTZERO(jit_->InitModule(exec_module)); - exec_module->AddFunctionsToMap(all_fns_); modules_.push_back(exec_module); - return 0; + result_code = 0; +XECLEANUP: + if (result_code) { + delete exec_module; + } + return result_code; } uint32_t Processor::CreateCallback(void (*callback)(void* data), void* data) { @@ -200,14 +183,34 @@ void Processor::DeallocThread(ThreadState* thread_state) { delete thread_state; } -int Processor::Execute(ThreadState* thread_state, uint32_t address) { - // Find the function to execute. - Function* f = GetFunction(address); - if (!f) { - XELOGCPU("Failed to find function %.8X to execute.", address); - return 1; +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; + } + } + 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 @@ -217,22 +220,23 @@ int Processor::Execute(ThreadState* thread_state, uint32_t address) { // Setup registers. ppc_state->lr = lr; - // Args: - // - i8* state - // - i64 lr - std::vector args; - args.push_back(PTOGV(ppc_state)); - GenericValue lr_arg; - lr_arg.IntVal = APInt(64, lr); - args.push_back(lr_arg); - GenericValue ret = engine_->runFunction(f, args); - // return (uint32_t)ret.IntVal.getSExtValue(); + // Find the function to execute. + FunctionPointer f = fn_table_->GetFunction(address); - // Faster, somewhat. + // 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. - // typedef void (*fnptr)(xe_ppc_state_t*, uint64_t); - // fnptr ptr = (fnptr)engine_->getPointerToFunction(f); - // ptr(ppc_state, lr); + f(ppc_state, lr); return 0; } @@ -246,11 +250,3 @@ uint64_t Processor::Execute(ThreadState* thread_state, uint32_t address, } return ppc_state->r[3]; } - -Function* Processor::GetFunction(uint32_t address) { - FunctionMap::iterator it = all_fns_.find(address); - if (it != all_fns_.end()) { - return it->second; - } - return NULL; -} diff --git a/src/xenia/cpu/processor.h b/src/xenia/cpu/processor.h index fee4b9032..c6bd7980e 100644 --- a/src/xenia/cpu/processor.h +++ b/src/xenia/cpu/processor.h @@ -14,36 +14,33 @@ #include +#include #include +#include #include #include #include -namespace llvm { - class ExecutionEngine; - class Function; -} - - namespace xe { namespace cpu { +class JIT; + class Processor { public: - Processor(xe_memory_ref memory); + Processor(xe_memory_ref memory, shared_ptr backend); ~Processor(); xe_memory_ref memory(); + shared_ptr export_resolver(); + void set_export_resolver(shared_ptr export_resolver); int Setup(); - int LoadBinary(const xechar_t* path, uint32_t start_address, - shared_ptr export_resolver); - - int PrepareModule(const char* name, const char* path, xe_xex2_ref xex, - shared_ptr export_resolver); + int LoadRawBinary(const xechar_t* path, uint32_t start_address); + int LoadXexModule(const char* name, const char* path, xe_xex2_ref xex); uint32_t CreateCallback(void (*callback)(void* data), void* data); @@ -53,16 +50,15 @@ public: uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t arg0); private: - llvm::Function* GetFunction(uint32_t address); + FunctionPointer GenerateFunction(uint32_t address); - xe_memory_ref memory_; - shared_ptr engine_; - - auto_ptr dummy_context_; + xe_memory_ref memory_; + shared_ptr backend_; + shared_ptr export_resolver_; + FunctionTable* fn_table_; + JIT* jit_; std::vector modules_; - - FunctionMap all_fns_; }; diff --git a/src/xenia/cpu/sdb/symbol.cc b/src/xenia/cpu/sdb/symbol.cc index c93972bd2..23e20886b 100644 --- a/src/xenia/cpu/sdb/symbol.cc +++ b/src/xenia/cpu/sdb/symbol.cc @@ -105,6 +105,11 @@ FunctionBlock* FunctionSymbol::SplitBlock(uint32_t address) { return NULL; } +void FunctionSymbol::AddCall(FunctionSymbol* source, FunctionSymbol* target) { + source->outgoing_calls.push_back(FunctionCall(0, source, target)); + target->incoming_calls.push_back(FunctionCall(0, source, target)); +} + VariableSymbol::VariableSymbol() : Symbol(Variable), diff --git a/src/xenia/cpu/sdb/symbol.h b/src/xenia/cpu/sdb/symbol.h index b132436d2..bfae74ca0 100644 --- a/src/xenia/cpu/sdb/symbol.h +++ b/src/xenia/cpu/sdb/symbol.h @@ -32,6 +32,10 @@ public: uint32_t address; FunctionSymbol* source; FunctionSymbol* target; + + FunctionCall(uint32_t address, FunctionSymbol* source, + FunctionSymbol* target) : + address(address), source(source), target(target) {} }; class VariableAccess { @@ -39,6 +43,10 @@ public: uint32_t address; FunctionSymbol* source; VariableSymbol* target; + + VariableAccess(uint32_t address, FunctionSymbol* source, + VariableSymbol* target) : + address(address), source(source), target(target) {} }; class Symbol { @@ -116,11 +124,13 @@ public: kernel::KernelExport* kernel_export; ExceptionEntrySymbol* ee; - std::vector incoming_calls; - std::vector outgoing_calls; - std::vector variable_accesses; + std::vector incoming_calls; + std::vector outgoing_calls; + std::vector variable_accesses; std::map blocks; + + static void AddCall(FunctionSymbol* source, FunctionSymbol* target); }; class VariableSymbol : public Symbol { diff --git a/src/xenia/cpu/sdb/symbol_database.cc b/src/xenia/cpu/sdb/symbol_database.cc index 6c889b20c..0ee569a84 100644 --- a/src/xenia/cpu/sdb/symbol_database.cc +++ b/src/xenia/cpu/sdb/symbol_database.cc @@ -103,9 +103,13 @@ ExceptionEntrySymbol* SymbolDatabase::GetOrInsertExceptionEntry( return ee; } -FunctionSymbol* SymbolDatabase::GetOrInsertFunction(uint32_t address) { +FunctionSymbol* SymbolDatabase::GetOrInsertFunction( + uint32_t address, FunctionSymbol* opt_call_source) { FunctionSymbol* fn = GetFunction(address); if (fn) { + if (opt_call_source) { + FunctionSymbol::AddCall(opt_call_source, fn); + } return fn; } @@ -120,6 +124,11 @@ FunctionSymbol* SymbolDatabase::GetOrInsertFunction(uint32_t address) { function_count_++; symbols_.insert(SymbolMap::value_type(address, fn)); scan_queue_.push_back(fn); + + if (opt_call_source) { + FunctionSymbol::AddCall(opt_call_source, fn); + } + return fn; } @@ -460,7 +469,9 @@ int SymbolDatabase::CompleteFunctionGraph(FunctionSymbol* fn) { // Function call. block->outgoing_type = FunctionBlock::kTargetFunction; block->outgoing_function = GetFunction(block->outgoing_address); - if (!block->outgoing_function) { + if (block->outgoing_function) { + FunctionSymbol::AddCall(fn, block->outgoing_function); + } else { XELOGE("call target not found: %.8X -> %.8X", block->end_address, block->outgoing_address); new_fns.push_back(block->outgoing_address); @@ -474,7 +485,7 @@ int SymbolDatabase::CompleteFunctionGraph(FunctionSymbol* fn) { (uint32_t)new_fns.size()); for (std::vector::iterator it = new_fns.begin(); it != new_fns.end(); ++it) { - GetOrInsertFunction(*it); + GetOrInsertFunction(*it, fn); } return 1; } diff --git a/src/xenia/cpu/sdb/symbol_database.h b/src/xenia/cpu/sdb/symbol_database.h index 1e3d49188..45bcb65ba 100644 --- a/src/xenia/cpu/sdb/symbol_database.h +++ b/src/xenia/cpu/sdb/symbol_database.h @@ -34,7 +34,8 @@ public: Symbol* GetSymbol(uint32_t address); ExceptionEntrySymbol* GetOrInsertExceptionEntry(uint32_t address); - FunctionSymbol* GetOrInsertFunction(uint32_t address); + FunctionSymbol* GetOrInsertFunction( + uint32_t address, FunctionSymbol* opt_call_source = NULL); VariableSymbol* GetOrInsertVariable(uint32_t address); FunctionSymbol* GetFunction(uint32_t address); VariableSymbol* GetVariable(uint32_t address); diff --git a/src/xenia/cpu/sources.gypi b/src/xenia/cpu/sources.gypi index d66cac04f..ea5eb5fb4 100644 --- a/src/xenia/cpu/sources.gypi +++ b/src/xenia/cpu/sources.gypi @@ -1,13 +1,20 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ + 'backend.h', + 'code_unit_builder.h', 'cpu-private.h', 'cpu.cc', 'cpu.h', 'exec_module.cc', 'exec_module.h', - 'llvm_exports.cc', - 'llvm_exports.h', + 'function_table.cc', + 'function_table.h', + 'global_exports.cc', + 'global_exports.h', + 'jit.h', + 'library_linker.h', + 'library_loader.h', 'ppc.h', 'processor.cc', 'processor.h', @@ -16,7 +23,7 @@ ], 'includes': [ - 'codegen/sources.gypi', + 'llvmbe/sources.gypi', 'ppc/sources.gypi', 'sdb/sources.gypi', ], diff --git a/src/xenia/cpu/xethunk/xethunk.bc b/src/xenia/cpu/xethunk/xethunk.bc deleted file mode 100644 index 0beeb02cc..000000000 Binary files a/src/xenia/cpu/xethunk/xethunk.bc and /dev/null differ diff --git a/src/xenia/cpu/xethunk/xethunk.c b/src/xenia/cpu/xethunk/xethunk.c deleted file mode 100644 index 0d974e244..000000000 --- a/src/xenia/cpu/xethunk/xethunk.c +++ /dev/null @@ -1,39 +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. * - ****************************************************************************** - */ - -/** - * This file is compiled with clang to produce LLVM bitcode. - * When the emulator goes to build a full module it then imports this code into - * the generated module to provide globals/other shared values. - * - * Changes to this file require building a new version and checking it into the - * repo on a machine that has clang. - * - * # rebuild the xethunk.bc/.ll files: - * xb xethunk - */ - -// NOTE: only headers in this directory should be included. -#include "xethunk.h" - - -// Global memory base. -// Dereference + PPC address to manipulate memory. Note that it's stored in -// big-endian! -extern char* xe_memory_base; - - -int xe_module_init() { - // TODO(benvanik): setup call table, etc? - - return 0; -} - -void xe_module_uninit() { -} diff --git a/src/xenia/cpu/xethunk/xethunk.ll b/src/xenia/cpu/xethunk/xethunk.ll deleted file mode 100644 index 0e1762784..000000000 --- a/src/xenia/cpu/xethunk/xethunk.ll +++ /dev/null @@ -1,11 +0,0 @@ -; ModuleID = 'src/cpu/xethunk/xethunk.bc' -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" -target triple = "x86_64-apple-macosx10.8.0" - -define i32 @xe_module_init() nounwind uwtable ssp { - ret i32 0 -} - -define void @xe_module_uninit() nounwind uwtable ssp { - ret void -} diff --git a/tools/xenia-run/xenia-run.cc b/tools/xenia-run/xenia-run.cc index a40408764..d4977046d 100644 --- a/tools/xenia-run/xenia-run.cc +++ b/tools/xenia-run/xenia-run.cc @@ -28,6 +28,7 @@ public: private: xe_memory_ref memory_; + shared_ptr backend_; shared_ptr processor_; shared_ptr runtime_; shared_ptr debugger_; @@ -45,6 +46,8 @@ 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()); + debugger_ = shared_ptr(new Debugger()); xe_memory_options_t memory_options; @@ -52,10 +55,11 @@ int Run::Setup() { memory_ = xe_memory_create(memory_options); XEEXPECTNOTNULL(memory_); - processor_ = shared_ptr(new Processor(memory_)); + processor_ = shared_ptr(new Processor(memory_, backend_)); XEEXPECTZERO(processor_->Setup()); runtime_ = shared_ptr(new Runtime(processor_, XT(""))); + processor_->set_export_resolver(runtime_->export_resolver()); return 0; XECLEANUP: