From 91f9e8b7bb5e9a09e565e16da065593927be172b Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Tue, 22 Jan 2013 00:22:27 -0800 Subject: [PATCH] Generating a lot of code! Still a few missing instructions/variants and other issues, but a big and valid LLVM module is being generated. --- include/xenia/config.h | 6 +- .../xenia/cpu/codegen/function_generator.h | 45 +- include/xenia/cpu/ppc/instr.h | 17 + include/xenia/cpu/ppc/state.h | 24 +- include/xenia/cpu/sdb.h | 7 +- src/cpu/codegen/emit.h | 3 +- src/cpu/codegen/emit_alu.cc | 529 +++++++++++++----- src/cpu/codegen/emit_control.cc | 412 ++++++++++++-- src/cpu/codegen/emit_fpu.cc | 78 +-- src/cpu/codegen/emit_memory.cc | 497 +++++++++++----- src/cpu/codegen/function_generator.cc | 325 ++++++++++- src/cpu/codegen/module_generator.cc | 27 +- src/cpu/exec_module.cc | 23 +- src/cpu/processor.cc | 2 +- src/cpu/sdb.cc | 22 +- src/cpu/xethunk/xethunk.c | 9 +- src/cpu/xethunk/xethunk.h | 6 +- xenia-build.py | 4 +- 18 files changed, 1613 insertions(+), 423 deletions(-) diff --git a/include/xenia/config.h b/include/xenia/config.h index 7478a3325..10d26feb0 100644 --- a/include/xenia/config.h +++ b/include/xenia/config.h @@ -23,10 +23,14 @@ #define XE_OPTION_LOG_INFO 1 #define XE_OPTION_LOG_DEBUG 1 #define XE_OPTION_LOG_CPU 1 -#define XE_OPTION_LOG_SDB 0 +#define XE_OPTION_LOG_SDB 1 #define XE_OPTION_LOG_GPU 1 #define XE_OPTION_LOG_KERNEL 1 +// TODO(benvanik): make this a runtime option +#define XE_OPTION_OPTIMIZED 0 + + #endif // XENIA_CONFIG_H_ diff --git a/include/xenia/cpu/codegen/function_generator.h b/include/xenia/cpu/codegen/function_generator.h index e2ea64a55..5ca7d192a 100644 --- a/include/xenia/cpu/codegen/function_generator.h +++ b/include/xenia/cpu/codegen/function_generator.h @@ -28,20 +28,28 @@ namespace codegen { class FunctionGenerator { public: - FunctionGenerator(xe_memory_ref memory, sdb::FunctionSymbol* fn, - llvm::LLVMContext* context, llvm::Module* gen_module, - llvm::Function* gen_fn); + FunctionGenerator( + xe_memory_ref memory, sdb::SymbolDatabase* sdb, sdb::FunctionSymbol* fn, + llvm::LLVMContext* context, llvm::Module* gen_module, + llvm::Function* gen_fn); ~FunctionGenerator(); + sdb::SymbolDatabase* sdb(); sdb::FunctionSymbol* fn(); llvm::LLVMContext* context(); llvm::Module* gen_module(); llvm::Function* gen_fn(); + sdb::FunctionBlock* fn_block(); void GenerateBasicBlocks(); llvm::BasicBlock* GetBasicBlock(uint32_t address); + llvm::BasicBlock* GetNextBasicBlock(); - llvm::Function* GetFunction(uint32_t addr); + llvm::Function* GetFunction(sdb::FunctionSymbol* fn); + + llvm::Value* LoadStateValue(uint32_t offset, llvm::Type* type, + const char* name = ""); + void StoreStateValue(uint32_t offset, llvm::Type* type, llvm::Value* value); llvm::Value* cia_value(); @@ -54,24 +62,28 @@ public: llvm::Value* ctr_value(); void update_ctr_value(llvm::Value* value); - llvm::Value* cr_value(uint32_t n); - void update_cr_value(uint32_t n, llvm::Value* value); + llvm::Value* cr_value(); + void update_cr_value(llvm::Value* value); llvm::Value* gpr_value(uint32_t n); void update_gpr_value(uint32_t n, llvm::Value* value); + llvm::Value* GetMembase(); llvm::Value* memory_addr(uint32_t addr); - llvm::Value* read_memory(llvm::Value* addr, uint32_t size, bool extend); - void write_memory(llvm::Value* addr, uint32_t size, llvm::Value* value); + llvm::Value* ReadMemory(llvm::Value* addr, uint32_t size, bool extend); + void WriteMemory(llvm::Value* addr, uint32_t size, llvm::Value* value); private: void GenerateBasicBlock(sdb::FunctionBlock* block, llvm::BasicBlock* bb); - xe_memory_ref memory_; - sdb::FunctionSymbol* fn_; - llvm::LLVMContext* context_; - llvm::Module* gen_module_; - llvm::Function* gen_fn_; + xe_memory_ref memory_; + sdb::SymbolDatabase* sdb_; + sdb::FunctionSymbol* fn_; + llvm::LLVMContext* context_; + llvm::Module* gen_module_; + llvm::Function* gen_fn_; + sdb::FunctionBlock* fn_block_; + llvm::BasicBlock* bb_; llvm::IRBuilder<>* builder_; std::map bbs_; @@ -81,12 +93,17 @@ private: struct { llvm::Value* xer; + bool xer_dirty; llvm::Value* lr; + bool lr_dirty; llvm::Value* ctr; + bool ctr_dirty; - llvm::Value* cr[4]; + llvm::Value* cr; + bool cr_dirty; llvm::Value* gpr[32]; + uint32_t gpr_dirty_bits; } values_; }; diff --git a/include/xenia/cpu/ppc/instr.h b/include/xenia/cpu/ppc/instr.h index 4bbf7221d..6557f9037 100644 --- a/include/xenia/cpu/ppc/instr.h +++ b/include/xenia/cpu/ppc/instr.h @@ -104,6 +104,14 @@ typedef struct { uint32_t OPCD : 6; } DS; // kXEPPCInstrFormatX + struct { + uint32_t Rc : 1; + uint32_t : 10; + uint32_t B : 5; + uint32_t A : 5; + uint32_t D : 5; + uint32_t OPCD : 6; + } X; // kXEPPCInstrFormatXL struct { uint32_t LK : 1; @@ -123,6 +131,15 @@ typedef struct { // kXEPPCInstrFormatXFL // kXEPPCInstrFormatXS // kXEPPCInstrFormatXO + struct { + uint32_t Rc : 1; + uint32_t : 8; + uint32_t OE : 1; + uint32_t B : 5; + uint32_t A : 5; + uint32_t D : 5; + uint32_t OPCD : 6; + } XO; // kXEPPCInstrFormatA // kXEPPCInstrFormatM // kXEPPCInstrFormatMD diff --git a/include/xenia/cpu/ppc/state.h b/include/xenia/cpu/ppc/state.h index 6ed27339c..eaceae2e7 100644 --- a/include/xenia/cpu/ppc/state.h +++ b/include/xenia/cpu/ppc/state.h @@ -19,6 +19,12 @@ #include +#ifdef XE_THUNK +#define XECACHEALIGN __attribute__ ((aligned(8))) +#define XECACHEALIGN64 __attribute__ ((aligned(64))) +#endif + + // namespace FPRF { // enum FPRF_e { // QUIET_NAN = 0x00088000, @@ -34,7 +40,7 @@ // } // FPRF -typedef struct XECACHEALIGN { +typedef struct XECACHEALIGN xe_float4 { union { struct { float x; @@ -51,17 +57,17 @@ typedef struct XECACHEALIGN { } xe_float4_t; -typedef struct XECACHEALIGN64 { - uint64_t r[32]; // General purpose registers - xe_float4_t v[128]; // VMX128 vector registers - double f[32]; // Floating-point registers - +typedef struct XECACHEALIGN64 xe_ppc_state { uint32_t cia; // Current PC (CIA) uint32_t nia; // Next PC (NIA) uint64_t xer; // XER register uint64_t lr; // Link register uint64_t ctr; // Count register + uint64_t r[32]; // General purpose registers + xe_float4_t v[128]; // VMX128 vector registers + double f[32]; // Floating-point registers + union { uint32_t value; struct { @@ -76,6 +82,12 @@ typedef struct XECACHEALIGN64 { uint8_t vx :1; // FP invalid operation exception summary - copy of FPSCR[VX] uint8_t ox :1; // FP overflow exception - copy of FPSCR[OX] } cr1; + uint8_t cr2 :4; + uint8_t cr3 :4; + uint8_t cr4 :4; + uint8_t cr5 :4; + uint8_t cr6 :4; + uint8_t cr7 :4; } cr; // Condition register union { diff --git a/include/xenia/cpu/sdb.h b/include/xenia/cpu/sdb.h index a82ae1c25..ffd9a088a 100644 --- a/include/xenia/cpu/sdb.h +++ b/include/xenia/cpu/sdb.h @@ -68,7 +68,8 @@ public: kTargetBlock = 1, kTargetFunction = 2, kTargetLR = 3, - kTargetNone = 4, + kTargetCTR = 4, + kTargetNone = 5, }; FunctionBlock(); @@ -106,7 +107,7 @@ public: uint32_t start_address; uint32_t end_address; - char *name; + char* name; FunctionType type; uint32_t flags; @@ -126,7 +127,7 @@ public: virtual ~VariableSymbol(); uint32_t address; - char *name; + char* name; }; class ExceptionEntrySymbol : public Symbol { diff --git a/src/cpu/codegen/emit.h b/src/cpu/codegen/emit.h index be6f1e0d1..d21a764ca 100644 --- a/src/cpu/codegen/emit.h +++ b/src/cpu/codegen/emit.h @@ -29,7 +29,8 @@ void RegisterEmitCategoryMemory(); #define XEREGISTEREMITTER(name, opcode) \ RegisterInstrEmit(opcode, (void*)InstrEmit_##name) -#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS +#define XEINSTRNOTIMPLEMENTED() +//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS } // namespace codegen diff --git a/src/cpu/codegen/emit_alu.cc b/src/cpu/codegen/emit_alu.cc index f7b4d38a0..2a5fa77bc 100644 --- a/src/cpu/codegen/emit_alu.cc +++ b/src/cpu/codegen/emit_alu.cc @@ -9,6 +9,8 @@ #include "cpu/codegen/emit.h" +#include + #include @@ -24,137 +26,168 @@ namespace codegen { // Integer arithmetic (A-3) -XEEMITTER(addx, 0x7C000214, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(addx, 0x7C000214, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RD <- (RA) + (RB) + + if (i.XO.Rc) { + // With cr0 update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + Value* v = b.CreateAdd(g.gpr_value(i.XO.A), g.gpr_value(i.XO.B)); + g.update_gpr_value(i.XO.D, v); + + return 0; +} + +XEEMITTER(addcx, 0X7C000014, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addcx, 0X7C000014, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(addex, 0x7C000114, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addex, 0x7C000114, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(addi, 0x38000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // if RA = 0 then RT <- EXTS(SI) + // else RT <- (RA) + EXTS(SI) + + Value* v = b.getInt64(XEEXTS16(i.D.SIMM)); + if (i.D.A) { + v = b.CreateAdd(g.gpr_value(i.D.A), v); + } + g.update_gpr_value(i.D.D, v); + + return 0; +} + +XEEMITTER(addic, 0x30000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addi, 0x38000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(addicx, 0x34000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addic, 0x30000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(addis, 0x3C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // if RA = 0 then RT <- EXTS(SI) || i16.0 + // else RT <- (RA) + EXTS(SI) || i16.0 + + Value* v = b.getInt64(XEEXTS16(i.D.SIMM) << 16); + if (i.D.A) { + v = b.CreateAdd(g.gpr_value(i.D.A), v); + } + g.update_gpr_value(i.D.D, v); + + return 0; +} + +XEEMITTER(addmex, 0x7C0001D4, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addicx, 0x34000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(addzex, 0x7C000194, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addis, 0x3C000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(divdx, 0x7C0003D2, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addmex, 0x7C0001D4, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(divdux, 0x7C000392, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(addzex, 0x7C000194, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(divwx, 0x7C0003D6, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(divdx, 0x7C0003D2, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(divdux, 0x7C000392, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mulhdx, 0x7C000092, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(divwx, 0x7C0003D6, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mulhdux, 0x7C000012, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mulhwx, 0x7C000096, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulhdx, 0x7C000092, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mulhwux, 0x7C000016, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulhdux, 0x7C000012, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mulldx, 0x7C0001D2, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulhwx, 0x7C000096, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mulli, 0x1C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulhwux, 0x7C000016, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mullwx, 0x7C0001D6, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulldx, 0x7C0001D2, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(negx, 0x7C0000D0, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mulli, 0x1C000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(subfx, 0x7C000050, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mullwx, 0x7C0001D6, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(subfcx, 0x7C000010, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(negx, 0x7C0000D0, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(subficx, 0x20000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(subfx, 0x7C000050, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(subfex, 0x7C000110, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(subfcx, 0x7C000010, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(subfmex, 0x7C0001D0, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(subficx, 0x20000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(subfex, 0x7C000110, XO )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(subfmex, 0x7C0001D0, XO )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(subfzex, 0x7C000190, XO )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(subfzex, 0x7C000190, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -162,168 +195,410 @@ XEEMITTER(subfzex, 0x7C000190, XO )(FunctionGenerator& g, InstrData& i) { // Integer compare (A-4) -XEEMITTER(cmp, 0x7C000000, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +void XeEmitCompareCore(FunctionGenerator& g, IRBuilder<>& b, + Value* lhs, Value* rhs, uint32_t BF, bool is_signed) { + Value* is_lt = is_signed ? + b.CreateICmpSLT(lhs, rhs) : b.CreateICmpULT(lhs, rhs); + Value* is_gt = is_signed ? + b.CreateICmpSGT(lhs, rhs) : b.CreateICmpUGT(lhs, rhs); + + Value* cp = b.CreateSelect(is_gt, b.getInt8(0x2), b.getInt8(0x1)); + Value* c = b.CreateSelect(is_lt, b.getInt8(0x4), cp); + c = b.CreateZExt(c, b.getInt64Ty()); + + // TODO(benvanik): set bit 4 to XER[SO] + + // Insert the 4 bits into their location in the CR. + Value* cr = g.cr_value(); + uint32_t mask = XEBITMASK((4 + BF) * 4, (4 + BF) * 4 + 4); + cr = b.CreateAnd(cr, mask); + cr = b.CreateOr(cr, b.CreateShl(c, (4 + BF) * 4)); + g.update_cr_value(cr); } -XEEMITTER(cmpi, 0x2C000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(cmp, 0x7C000000, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // if L = 0 then + // a <- EXTS((RA)[32:63]) + // b <- EXTS((RB)[32:63]) + // else + // a <- (RA) + // b <- (RB) + // if a < b then + // c <- 0b100 + // else if a > b then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + + uint32_t BF = i.X.D >> 2; + uint32_t L = i.X.D & 1; + + Value* lhs = g.gpr_value(i.X.A); + Value* rhs = g.gpr_value(i.X.B); + if (!L) { + // 32-bit - truncate and sign extend. + lhs = b.CreateTrunc(lhs, b.getInt32Ty()); + lhs = b.CreateSExt(lhs, b.getInt64Ty()); + rhs = b.CreateTrunc(rhs, b.getInt32Ty()); + rhs = b.CreateSExt(rhs, b.getInt64Ty()); + } + + XeEmitCompareCore(g, b, lhs, rhs, BF, true); + + return 0; } -XEEMITTER(cmpl, 0x7C000040, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(cmpi, 0x2C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // if L = 0 then + // a <- EXTS((RA)[32:63]) + // else + // a <- (RA) + // if a < EXTS(SI) then + // c <- 0b100 + // else if a > EXTS(SI) then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + + uint32_t BF = i.D.D >> 2; + uint32_t L = i.D.D & 1; + + Value* lhs = g.gpr_value(i.D.A); + if (!L) { + // 32-bit - truncate and sign extend. + lhs = b.CreateTrunc(lhs, b.getInt32Ty()); + lhs = b.CreateSExt(lhs, b.getInt64Ty()); + } + + Value* rhs = b.getInt64(XEEXTS16(i.D.SIMM)); + XeEmitCompareCore(g, b, lhs, rhs, BF, true); + + return 0; } -XEEMITTER(cmpli, 0x28000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(cmpl, 0x7C000040, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // if L = 0 then + // a <- i32.0 || (RA)[32:63] + // b <- i32.0 || (RB)[32:63] + // else + // a <- (RA) + // b <- (RB) + // if a u b then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + + uint32_t BF = i.X.D >> 2; + uint32_t L = i.X.D & 1; + + Value* lhs = g.gpr_value(i.X.A); + Value* rhs = g.gpr_value(i.X.B); + if (!L) { + // 32-bit - truncate and zero extend. + lhs = b.CreateTrunc(lhs, b.getInt32Ty()); + lhs = b.CreateZExt(lhs, b.getInt64Ty()); + rhs = b.CreateTrunc(rhs, b.getInt32Ty()); + rhs = b.CreateZExt(rhs, b.getInt64Ty()); + } + + XeEmitCompareCore(g, b, lhs, rhs, BF, false); + + return 0; +} + +XEEMITTER(cmpli, 0x28000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // if L = 0 then + // a <- i32.0 || (RA)[32:63] + // else + // a <- (RA) + // if a u i48.0 || SI then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + + uint32_t BF = i.D.D >> 2; + uint32_t L = i.D.D & 1; + + Value* lhs = g.gpr_value(i.D.A); + if (!L) { + // 32-bit - truncate and zero extend. + lhs = b.CreateTrunc(lhs, b.getInt32Ty()); + lhs = b.CreateZExt(lhs, b.getInt64Ty()); + } + + Value* rhs = b.getInt64(i.D.SIMM); + XeEmitCompareCore(g, b, lhs, rhs, BF, false); + + return 0; } // Integer logical (A-5) -XEEMITTER(andx, 0x7C000038, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(andx, 0x7C000038, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) & (RB) + + if (i.X.Rc) { + // With cr0 update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + Value* v = b.CreateAnd(g.gpr_value(i.X.D), g.gpr_value(i.X.B)); + g.update_gpr_value(i.X.A, v); + + return 0; +} + +XEEMITTER(andcx, 0x7C000078, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) & ¬(RB) + + if (i.X.Rc) { + // With cr0 update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + Value* v = b.CreateXor(g.gpr_value(i.X.B), -1); + v = b.CreateAnd(g.gpr_value(i.X.D), v); + g.update_gpr_value(i.X.A, v); + + return 0; +} + +XEEMITTER(andix, 0x70000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) & (i48.0 || UI) + + Value* v = b.CreateAnd(g.gpr_value(i.D.D), (uint64_t)i.D.SIMM); + g.update_gpr_value(i.D.A, v); + + // TODO(benvanik): update cr0 + XEINSTRNOTIMPLEMENTED(); + + return 1; +} + +XEEMITTER(andisx, 0x74000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) & (i32.0 || UI || i16.0) + + Value* v = b.CreateAnd(g.gpr_value(i.D.D), ((uint64_t)i.D.SIMM) << 16); + g.update_gpr_value(i.D.A, v); + + // TODO(benvanik): update cr0 + XEINSTRNOTIMPLEMENTED(); + + return 1; +} + +XEEMITTER(cntlzdx, 0x7C000074, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(andcx, 0x7C000078, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(cntlzwx, 0x7C000034, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // n <- 32 + // do while n < 64 + // if (RS) = 1 then leave n + // n <- n + 1 + // RA <- n - 32 + + if (i.X.Rc) { + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + Value* v = g.gpr_value(i.X.D); + 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); + Value* count = b.CreateCall2(ctlz, v, b.getInt1(1)); + + count = b.CreateZExt(count, b.getInt64Ty()); + g.update_gpr_value(i.X.A, count); + + return 0; +} + +XEEMITTER(eqvx, 0x7C000238, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(andix, 0x70000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(extsbx, 0x7C000774, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // s <- (RS)[56] + // RA[56:63] <- (RS)[56:63] + // RA[0:55] <- i56.s + + if (i.X.Rc) { + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + Value* v = g.gpr_value(i.X.D); + v = b.CreateTrunc(v, b.getInt8Ty()); + v = b.CreateSExt(v, b.getInt64Ty()); + g.update_gpr_value(i.X.A, v); + + return 0; +} + +XEEMITTER(extshx, 0x7C000734, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(andisx, 0x74000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(extswx, 0x7C0007B4, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(cntlzdx, 0x7C000074, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(nandx, 0x7C0003B8, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(cntlzwx, 0x7C000034, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(norx, 0x7C0000F8, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- ¬((RS) | (RB)) + + if (i.X.Rc) { + // With cr0 update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + Value* v = b.CreateOr(g.gpr_value(i.X.D), g.gpr_value(i.X.B)); + v = b.CreateXor(v, -1); + g.update_gpr_value(i.X.A, v); + + return 0; +} + +XEEMITTER(orx, 0x7C000378, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) | (RB) + + if (i.X.Rc) { + // With cr0 update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + Value* v = b.CreateOr(g.gpr_value(i.X.D), g.gpr_value(i.X.B)); + g.update_gpr_value(i.X.A, v); + + return 0; +} + +XEEMITTER(orcx, 0x7C000338, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(eqvx, 0x7C000238, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(ori, 0x60000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) | (i48.0 || UI) + + Value* v = b.CreateOr(g.gpr_value(i.D.D), (uint64_t)i.D.SIMM); + g.update_gpr_value(i.D.A, v); + + return 0; } -XEEMITTER(extsbx, 0x7C000774, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(oris, 0x64000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) | (i32.0 || UI || i16.0) + + Value* v = b.CreateOr(g.gpr_value(i.D.D), ((uint64_t)i.D.SIMM) << 16); + g.update_gpr_value(i.D.A, v); + + return 0; } -XEEMITTER(extshx, 0x7C000734, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(xorx, 0x7C000278, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) XOR (RB) + + if (i.X.Rc) { + // With cr0 update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + Value* v = b.CreateXor(g.gpr_value(i.X.D), g.gpr_value(i.X.B)); + g.update_gpr_value(i.X.A, v); + + return 0; } -XEEMITTER(extswx, 0x7C0007B4, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(xori, 0x68000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) XOR (i48.0 || UI) + + Value* v = b.CreateXor(g.gpr_value(i.D.D), (uint64_t)i.D.SIMM); + g.update_gpr_value(i.D.A, v); + + return 0; } -XEEMITTER(nandx, 0x7C0003B8, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} +XEEMITTER(xoris, 0x6C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // RA <- (RS) XOR (i32.0 || UI || i16.0) -XEEMITTER(norx, 0x7C0000F8, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} + Value* v = b.CreateXor(g.gpr_value(i.D.D), ((uint64_t)i.D.SIMM) << 16); + g.update_gpr_value(i.D.A, v); -XEEMITTER(orx, 0x7C000378, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(orcx, 0x7C000338, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(ori, 0x60000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(oris, 0x64000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(xorx, 0x7C000278, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(xori, 0x68000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(xoris, 0x6C000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + return 0; } // Integer rotate (A-6) -XEEMITTER(rldclx, 0x78000010, MDS)(FunctionGenerator& g, InstrData& i) { +XEEMITTER(rldclx, 0x78000010, MDS)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldcrx, 0x78000012, MDS)(FunctionGenerator& g, InstrData& i) { +XEEMITTER(rldcrx, 0x78000012, MDS)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldicx, 0x78000008, MD )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(rldicx, 0x78000008, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldiclx, 0x78000000, MD )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(rldiclx, 0x78000000, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldicrx, 0x78000004, MD )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(rldicrx, 0x78000004, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rldimix, 0x7800000C, MD )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(rldimix, 0x7800000C, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rlwimix, 0x50000000, M )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(rlwimix, 0x50000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rlwinmx, 0x54000000, M )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(rlwinmx, 0x54000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(rlwnmx, 0x5C000000, M )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(rlwnmx, 0x5C000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -331,42 +606,42 @@ XEEMITTER(rlwnmx, 0x5C000000, M )(FunctionGenerator& g, InstrData& i) { // Integer shift (A-7) -XEEMITTER(sldx, 0x7C000036, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(sldx, 0x7C000036, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(slwx, 0x7C000030, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(slwx, 0x7C000030, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(sradx, 0x7C000634, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(sradx, 0x7C000634, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(sradix, 0x7C000674, XS )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(sradix, 0x7C000674, XS )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(srawx, 0x7C000630, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(srawx, 0x7C000630, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(srawix, 0x7C000670, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(srawix, 0x7C000670, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(srdx, 0x7C000436, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(srdx, 0x7C000436, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(srwx, 0x7C000430, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(srwx, 0x7C000430, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } diff --git a/src/cpu/codegen/emit_control.cc b/src/cpu/codegen/emit_control.cc index 6ca4aa750..fa43f5438 100644 --- a/src/cpu/codegen/emit_control.cc +++ b/src/cpu/codegen/emit_control.cc @@ -15,6 +15,7 @@ using namespace llvm; using namespace xe::cpu::codegen; using namespace xe::cpu::ppc; +using namespace xe::cpu::sdb; namespace xe { @@ -22,70 +23,356 @@ namespace cpu { namespace codegen { -XEEMITTER(bx, 0x48000000, I )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +int XeEmitBranchTo(FunctionGenerator& g, 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(); + switch (fn_block->outgoing_type) { + case FunctionBlock::kTargetBlock: + { + BasicBlock* target_bb = g.GetBasicBlock(fn_block->outgoing_address); + XEASSERTNOTNULL(target_bb); + b.CreateBr(target_bb); + break; + } + case FunctionBlock::kTargetFunction: + { + Function* target_fn = g.GetFunction(fn_block->outgoing_function); + Function::arg_iterator args = g.gen_fn()->arg_begin(); + Value* statePtr = args; + b.CreateCall(target_fn, statePtr); + if (!lk) { + // Tail. + b.CreateRetVoid(); + } else { + BasicBlock* next_bb = g.GetNextBasicBlock(); + if (next_bb) { + b.CreateBr(next_bb); + } else { + // ? + b.CreateRetVoid(); + } + } + break; + } + case FunctionBlock::kTargetLR: + { + // An indirect jump. + printf("INDIRECT JUMP VIA LR: %.8X\n", cia); + b.CreateRetVoid(); + break; + } + case FunctionBlock::kTargetCTR: + { + // An indirect jump. + printf("INDIRECT JUMP VIA CTR: %.8X\n", cia); + b.CreateRetVoid(); + break; + } + default: + case FunctionBlock::kTargetNone: + XEASSERTALWAYS(); + return 1; + } + return 0; } -XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(bx, 0x48000000, I )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // if AA then + // NIA <- EXTS(LI || 0b00) + // else + // NIA <- CIA + EXTS(LI || 0b00) + // if LK then + // LR <- CIA + 4 + + uint32_t nia; + if (i.I.AA) { + nia = XEEXTS26(i.I.LI << 2); + } else { + nia = i.address + XEEXTS26(i.I.LI << 2); + } + if (i.I.LK) { + g.update_lr_value(b.getInt32(i.address + 4)); + } + + g.FlushRegisters(); + + return XeEmitBranchTo(g, b, "bx", i.address, i.I.LK); } -XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // if ¬BO[2] then + // CTR <- CTR - 1 + // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3]) + // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) + // if ctr_ok & cond_ok then + // if AA then + // NIA <- EXTS(BD || 0b00) + // else + // NIA <- CIA + EXTS(BD || 0b00) + // if LK then + // LR <- CIA + 4 + + // 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)); + } + + Value* ctr_ok = NULL; + if (XESELECTBITS(i.B.BO, 4, 4)) { + // Ignore ctr. + } else { + // Decrement counter. + Value* ctr = g.ctr_value(); + ctr = g.ctr_value(); + ctr = b.CreateSub(ctr, b.getInt64(1)); + + // Ctr check. + if (XESELECTBITS(i.B.BO, 3, 3)) { + ctr_ok = b.CreateICmpEQ(ctr, b.getInt64(0)); + } else { + ctr_ok = b.CreateICmpNE(ctr, b.getInt64(0)); + } + } + + Value* cond_ok = NULL; + if (XESELECTBITS(i.B.BO, 4, 4)) { + // Ignore cond. + } else { + Value* cr = g.cr_value(); + cr = b.CreateAnd(cr, XEBITMASK(i.B.BI, i.B.BI)); + if (XESELECTBITS(i.B.BO, 3, 3)) { + cond_ok = b.CreateICmpNE(cr, b.getInt64(0)); + } else { + cond_ok = b.CreateICmpEQ(cr, b.getInt64(0)); + } + } + + // We do a bit of optimization here to make the llvm assembly easier to read. + Value* ok = NULL; + if (ctr_ok && cond_ok) { + ok = b.CreateAnd(ctr_ok, cond_ok); + } else if (ctr_ok) { + ok = ctr_ok; + } else if (cond_ok) { + ok = cond_ok; + } + + g.FlushRegisters(); + // Handle unconditional branches without extra fluff. + BasicBlock* original_bb = b.GetInsertBlock(); + if (ok) { + char name[32]; + xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcx", i.address); + BasicBlock* next_block = g.GetNextBasicBlock(); + BasicBlock* branch_bb = BasicBlock::Create(*g.context(), name, g.gen_fn(), + next_block); + + b.CreateCondBr(ok, branch_bb, next_block); + b.SetInsertPoint(branch_bb); + } + + // Note that this occurs entirely within the branch true block. + uint32_t nia; + if (i.B.AA) { + nia = XEEXTS26(i.B.BD << 2); + } else { + nia = i.address + XEEXTS26(i.B.BD << 2); + } + if (XeEmitBranchTo(g, b, "bcx", i.address, i.B.LK)) { + return 1; + } + + b.SetInsertPoint(original_bb); + + return 0; } -XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; +XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) + // if cond_ok then + // NIA <- CTR[0:61] || 0b00 + // if LK then + // LR <- CIA + 4 + + // 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)); + } + + Value* cond_ok = NULL; + if (XESELECTBITS(i.XL.BO, 4, 4)) { + // Ignore cond. + } else { + Value* cr = g.cr_value(); + cr = b.CreateAnd(cr, XEBITMASK(i.XL.BI, i.XL.BI)); + if (XESELECTBITS(i.XL.BO, 3, 3)) { + cond_ok = b.CreateICmpNE(cr, b.getInt64(0)); + } else { + cond_ok = b.CreateICmpEQ(cr, b.getInt64(0)); + } + } + + // We do a bit of optimization here to make the llvm assembly easier to read. + Value* ok = NULL; + if (cond_ok) { + ok = cond_ok; + } + + g.FlushRegisters(); + + // Handle unconditional branches without extra fluff. + BasicBlock* original_bb = b.GetInsertBlock(); + if (ok) { + char name[32]; + xesnprintfa(name, XECOUNT(name), "loc_%.8X_bcctrx", i.address); + BasicBlock* next_block = g.GetNextBasicBlock(); + XEASSERTNOTNULL(next_block); + BasicBlock* branch_bb = BasicBlock::Create(*g.context(), name, g.gen_fn(), + next_block); + + b.CreateCondBr(ok, branch_bb, next_block); + b.SetInsertPoint(branch_bb); + } + + // Note that this occurs entirely within the branch true block. + if (XeEmitBranchTo(g, b, "bcctrx", i.address, i.XL.LK)) { + return 1; + } + + b.SetInsertPoint(original_bb); + + return 0; +} + +XEEMITTER(bclrx, 0x4C000020, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // if ¬BO[2] then + // CTR <- CTR - 1 + // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3] + // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) + // if ctr_ok & cond_ok then + // NIA <- LR[0:61] || 0b00 + // if LK then + // LR <- CIA + 4 + + // 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)); + } + + Value* ctr_ok = NULL; + if (XESELECTBITS(i.XL.BO, 4, 4)) { + // Ignore ctr. + } else { + // Decrement counter. + Value* ctr = g.ctr_value(); + ctr = g.ctr_value(); + ctr = b.CreateSub(ctr, b.getInt64(1)); + + // Ctr check. + if (XESELECTBITS(i.XL.BO, 3, 3)) { + ctr_ok = b.CreateICmpEQ(ctr, b.getInt64(0)); + } else { + ctr_ok = b.CreateICmpNE(ctr, b.getInt64(0)); + } + } + + Value* cond_ok = NULL; + if (XESELECTBITS(i.XL.BO, 4, 4)) { + // Ignore cond. + } else { + Value* cr = g.cr_value(); + cr = b.CreateAnd(cr, XEBITMASK(i.XL.BI, i.XL.BI)); + if (XESELECTBITS(i.XL.BO, 3, 3)) { + cond_ok = b.CreateICmpNE(cr, b.getInt64(0)); + } else { + cond_ok = b.CreateICmpEQ(cr, b.getInt64(0)); + } + } + + // We do a bit of optimization here to make the llvm assembly easier to read. + Value* ok = NULL; + if (ctr_ok && cond_ok) { + ok = b.CreateAnd(ctr_ok, cond_ok); + } else if (ctr_ok) { + ok = ctr_ok; + } else if (cond_ok) { + ok = cond_ok; + } + + g.FlushRegisters(); + + // Handle unconditional branches without extra fluff. + BasicBlock* original_bb = b.GetInsertBlock(); + if (ok) { + char name[32]; + xesnprintfa(name, XECOUNT(name), "loc_%.8X_bclrx", i.address); + BasicBlock* next_block = g.GetNextBasicBlock(); + XEASSERTNOTNULL(next_block); + BasicBlock* branch_bb = BasicBlock::Create(*g.context(), name, g.gen_fn(), + next_block); + + b.CreateCondBr(ok, branch_bb, next_block); + b.SetInsertPoint(branch_bb); + } + + // Note that this occurs entirely within the branch true block. + if (XeEmitBranchTo(g, b, "bclrx", i.address, i.XL.LK)) { + return 1; + } + + b.SetInsertPoint(original_bb); + + return 0; } // Condition register logical (A-23) -XEEMITTER(crand, 0x4C000202, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(crand, 0x4C000202, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crandc, 0x4C000102, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(crandc, 0x4C000102, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(creqv, 0x4C000242, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(creqv, 0x4C000242, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crnand, 0x4C0001C2, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(crnand, 0x4C0001C2, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crnor, 0x4C000042, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(crnor, 0x4C000042, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(cror, 0x4C000382, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(cror, 0x4C000382, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crorc, 0x4C000342, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(crorc, 0x4C000342, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(crxor, 0x4C000182, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(crxor, 0x4C000182, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mcrf, 0x4C000000, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mcrf, 0x4C000000, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -93,7 +380,7 @@ XEEMITTER(mcrf, 0x4C000000, XL )(FunctionGenerator& g, InstrData& i) { // System linkage (A-24) -XEEMITTER(sc, 0x44000002, SC )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(sc, 0x44000002, SC )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -101,22 +388,22 @@ XEEMITTER(sc, 0x44000002, SC )(FunctionGenerator& g, InstrData& i) { // Trap (A-25) -XEEMITTER(td, 0x7C000088, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(td, 0x7C000088, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(tdi, 0x08000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(tdi, 0x08000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(tw, 0x7C000008, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(tw, 0x7C000008, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(twi, 0x0C000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(twi, 0x0C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -124,29 +411,82 @@ XEEMITTER(twi, 0x0C000000, D )(FunctionGenerator& g, InstrData& i) { // Processor control (A-26) -XEEMITTER(mfcr, 0x7C000026, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mfcr, 0x7C000026, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mfspr, 0x7C0002A6, XFX)(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mfspr, 0x7C0002A6, XFX)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { + // n <- spr[5:9] || spr[0:4] + // if length(SPR(n)) = 64 then + // RT <- SPR(n) + // else + // RT <- i32.0 || SPR(n) + + const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F); + Value* v = NULL; + switch (n) { + case 1: + // XER + v = g.xer_value(); + break; + case 8: + // LR + v = g.lr_value(); + break; + case 9: + // CTR + v = g.ctr_value(); + break; + default: + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + g.update_gpr_value(i.XFX.D, v); + + return 0; +} + +XEEMITTER(mftb, 0x7C0002E6, XFX)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mftb, 0x7C0002E6, XFX)(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mtcrf, 0x7C000120, XFX)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtcrf, 0x7C000120, XFX)(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} +XEEMITTER(mtspr, 0x7C0003A6, XFX)(FunctionGenerator& g, 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] -XEEMITTER(mtspr, 0x7C0003A6, XFX)(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + Value* v = g.gpr_value(i.XFX.D); + + const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F); + switch (n) { + case 1: + // XER + g.update_xer_value(v); + break; + case 8: + // LR + g.update_lr_value(v); + break; + case 9: + // CTR + g.update_ctr_value(v); + break; + default: + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + return 0; } diff --git a/src/cpu/codegen/emit_fpu.cc b/src/cpu/codegen/emit_fpu.cc index fbd7e6966..ef977011c 100644 --- a/src/cpu/codegen/emit_fpu.cc +++ b/src/cpu/codegen/emit_fpu.cc @@ -24,67 +24,67 @@ namespace codegen { // Floating-point arithmetic (A-8) -XEEMITTER(faddx, 0xFC00002A, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(faddx, 0xFC00002A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(faddsx, 0xEC00002A, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(faddsx, 0xEC00002A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fdivx, 0xFC000024, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fdivx, 0xFC000024, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fdivsx, 0xEC000024, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fdivsx, 0xEC000024, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmulx, 0xFC000032, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fmulx, 0xFC000032, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmulsx, 0xEC000032, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fmulsx, 0xEC000032, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fresx, 0xEC000030, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fresx, 0xEC000030, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(frsqrtex, 0xFC000034, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(frsqrtex, 0xFC000034, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fsubx, 0xFC000028, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fsubx, 0xFC000028, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fsubsx, 0xEC000028, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fsubsx, 0xEC000028, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fselx, 0xFC00002E, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fselx, 0xFC00002E, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fsqrtx, 0xFC00002C, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fsqrtx, 0xFC00002C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fsqrtsx, 0xEC00002C, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fsqrtsx, 0xEC00002C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -92,42 +92,42 @@ XEEMITTER(fsqrtsx, 0xEC00002C, A )(FunctionGenerator& g, InstrData& i) { // Floating-point multiply-add (A-9) -XEEMITTER(fmaddx, 0xFC00003A, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fmaddx, 0xFC00003A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmaddsx, 0xEC00003A, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fmaddsx, 0xEC00003A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmsubx, 0xFC000038, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fmsubx, 0xFC000038, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmsubsx, 0xEC000038, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fmsubsx, 0xEC000038, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnmaddx, 0xFC00003E, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fnmaddx, 0xFC00003E, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnmaddsx, 0xEC00003E, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fnmaddsx, 0xEC00003E, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnmsubx, 0xFC00003C, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fnmsubx, 0xFC00003C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnmsubsx, 0xEC00003C, A )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fnmsubsx, 0xEC00003C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -135,32 +135,32 @@ XEEMITTER(fnmsubsx, 0xEC00003C, A )(FunctionGenerator& g, InstrData& i) { // Floating-point rounding and conversion (A-10) -XEEMITTER(fcfidx, 0xFC00069C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fcfidx, 0xFC00069C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fctidx, 0xFC00065C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fctidx, 0xFC00065C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fctidzx, 0xFC00065E, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fctidzx, 0xFC00065E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fctiwx, 0xFC00001C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fctiwx, 0xFC00001C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fctiwzx, 0xFC00001E, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fctiwzx, 0xFC00001E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(frspx, 0xFC000018, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(frspx, 0xFC000018, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -168,12 +168,12 @@ XEEMITTER(frspx, 0xFC000018, X )(FunctionGenerator& g, InstrData& i) { // Floating-point compare (A-11) -XEEMITTER(fcmpo, 0xFC000040, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fcmpo, 0xFC000040, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fcmpu, 0xFC000000, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fcmpu, 0xFC000000, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -181,32 +181,32 @@ XEEMITTER(fcmpu, 0xFC000000, X )(FunctionGenerator& g, InstrData& i) { // Floating-point status and control register (A -XEEMITTER(mcrfs, 0xFC000080, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mcrfs, 0xFC000080, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mffsx, 0xFC00048E, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mffsx, 0xFC00048E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtfsb0x, 0xFC00008C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mtfsb0x, 0xFC00008C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtfsb1x, 0xFC00004C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mtfsb1x, 0xFC00004C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtfsfx, 0xFC00058E, XFL)(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mtfsfx, 0xFC00058E, XFL)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(mtfsfix, 0xFC00010C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(mtfsfix, 0xFC00010C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -214,22 +214,22 @@ XEEMITTER(mtfsfix, 0xFC00010C, X )(FunctionGenerator& g, InstrData& i) { // Floating-point move (A-21) -XEEMITTER(fabsx, 0xFC000210, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fabsx, 0xFC000210, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fmrx, 0xFC000090, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fmrx, 0xFC000090, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnabsx, 0xFC000110, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fnabsx, 0xFC000110, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(fnegx, 0xFC000050, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(fnegx, 0xFC000050, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } diff --git a/src/cpu/codegen/emit_memory.cc b/src/cpu/codegen/emit_memory.cc index c938b9ff0..1fbf3e426 100644 --- a/src/cpu/codegen/emit_memory.cc +++ b/src/cpu/codegen/emit_memory.cc @@ -24,231 +24,441 @@ namespace codegen { // Integer load (A-13) -XEEMITTER(lbz, 0x88000000, D )(FunctionGenerator& g, InstrData& i) { +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.SIMM)); + if (i.D.A) { + ea = b.CreateAdd(g.gpr_value(i.D.A), ea); + } + Value* v = g.ReadMemory(ea, 1, false); + g.update_gpr_value(i.D.D, 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.A), b.getInt64(XEEXTS16(i.D.SIMM))); + Value* v = g.ReadMemory(ea, 1, false); + g.update_gpr_value(i.D.D, v); + g.update_gpr_value(i.D.A, 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.A), g.gpr_value(i.X.B)); + Value* v = g.ReadMemory(ea, 1, false); + g.update_gpr_value(i.X.D, v); + g.update_gpr_value(i.X.A, 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.B); + if (i.X.A) { + ea = b.CreateAdd(g.gpr_value(i.X.A), ea); + } + Value* v = g.ReadMemory(ea, 1, false); + g.update_gpr_value(i.X.D, 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.A) { + ea = b.CreateAdd(g.gpr_value(i.DS.A), ea); + } + Value* v = g.ReadMemory(ea, 8, false); + g.update_gpr_value(i.DS.S, 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.A), + b.getInt64(XEEXTS16(i.DS.ds << 2))); + Value* v = g.ReadMemory(ea, 8, false); + g.update_gpr_value(i.DS.S, v); + g.update_gpr_value(i.DS.A, ea); + + return 0; +} + +XEEMITTER(ldux, 0x7C00006A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lbzu, 0x8C000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(ldx, 0x7C00002A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lbzux, 0x7C0000EE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lha, 0xA8000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lbzx, 0x7C0000AE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lhau, 0xAC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(ld, 0xE8000000, DS )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lhaux, 0x7C0002EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(ldux, 0x7C00006A, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lhax, 0x7C0002AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(ldx, 0x7C00002A, X )(FunctionGenerator& g, InstrData& i) { +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.SIMM)); + if (i.D.A) { + ea = b.CreateAdd(g.gpr_value(i.D.A), ea); + } + Value* v = g.ReadMemory(ea, 2, false); + g.update_gpr_value(i.D.D, v); + + return 0; +} + +XEEMITTER(lhzu, 0xA4000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lha, 0xA8000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lhzux, 0x7C00026E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lhau, 0xAC000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lhzx, 0x7C00022E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lhaux, 0x7C0002EE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lwa, 0xE8000002, DS )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lhax, 0x7C0002AE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lwaux, 0x7C0002EA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lhz, 0xA0000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lwax, 0x7C0002AA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lhzu, 0xA4000000, D )(FunctionGenerator& g, InstrData& i) { +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.SIMM)); + if (i.D.A) { + ea = b.CreateAdd(g.gpr_value(i.D.A), ea); + } + Value* v = g.ReadMemory(ea, 4, false); + g.update_gpr_value(i.D.D, v); + + return 0; +} + +XEEMITTER(lwzu, 0x84000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lhzux, 0x7C00026E, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lwzux, 0x7C00006E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lhzx, 0x7C00022E, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} +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) -XEEMITTER(lwa, 0xE8000002, DS )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} + Value* ea = g.gpr_value(i.X.B); + if (i.X.A) { + ea = b.CreateAdd(g.gpr_value(i.X.A), ea); + } + Value* v = g.ReadMemory(ea, 4, false); + g.update_gpr_value(i.X.D, v); -XEEMITTER(lwaux, 0x7C0002EA, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lwax, 0x7C0002AA, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lwz, 0x80000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lwzu, 0x84000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lwzux, 0x7C00006E, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(lwzx, 0x7C00002E, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + return 0; } // Integer store (A-14) -XEEMITTER(stb, 0x98000000, D )(FunctionGenerator& g, InstrData& i) { +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.SIMM)); + if (i.D.A) { + ea = b.CreateAdd(g.gpr_value(i.D.A), ea); + } + Value* v = g.gpr_value(i.D.D); + g.WriteMemory(ea, 1, v); + + return 0; +} + +XEEMITTER(stbu, 0x9C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stbu, 0x9C000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stbux, 0x7C0001EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stbux, 0x7C0001EE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stbx, 0x7C0001AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stbx, 0x7C0001AE, X )(FunctionGenerator& g, InstrData& i) { +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.A) { + ea = b.CreateAdd(g.gpr_value(i.DS.A), ea); + } + Value* v = g.gpr_value(i.DS.S); + g.WriteMemory(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.A), + b.getInt64(XEEXTS16(i.DS.ds << 2))); + Value* v = g.gpr_value(i.DS.S); + g.WriteMemory(ea, 8, v); + g.update_gpr_value(i.DS.A, ea); + + return 0; +} + +XEEMITTER(stdux, 0x7C00016A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(std, 0xF8000000, DS )(FunctionGenerator& g, InstrData& i) { - //const uint64 b = r(instr.DS.A); - //const uint64 EA = b + EXTS16(instr.DS.ds << 2); - //MEMSET64(EA, instr.DS.S); +XEEMITTER(stdx, 0x7C00012A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stdu, 0xF8000001, DS )(FunctionGenerator& g, InstrData& i) { +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.SIMM)); + if (i.D.A) { + ea = b.CreateAdd(g.gpr_value(i.D.A), ea); + } + Value* v = g.gpr_value(i.D.D); + g.WriteMemory(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.A), + b.getInt64(XEEXTS16(i.D.SIMM))); + Value* v = g.gpr_value(i.D.D); + g.WriteMemory(ea, 2, v); + g.update_gpr_value(i.D.A, ea); + + return 0; +} + +XEEMITTER(sthux, 0x7C00036E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stdux, 0x7C00016A, X )(FunctionGenerator& g, InstrData& i) { +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.B); + if (i.D.A) { + ea = b.CreateAdd(g.gpr_value(i.X.A), ea); + } + Value* v = g.gpr_value(i.X.D); + g.WriteMemory(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.SIMM)); + if (i.D.A) { + ea = b.CreateAdd(g.gpr_value(i.D.A), ea); + } + Value* v = g.gpr_value(i.D.D); + g.WriteMemory(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.A), + b.getInt64(XEEXTS16(i.D.SIMM))); + Value* v = g.gpr_value(i.D.D); + g.WriteMemory(ea, 4, v); + g.update_gpr_value(i.D.A, ea); + + return 0; +} + +XEEMITTER(stwux, 0x7C00016E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stdx, 0x7C00012A, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} +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] -XEEMITTER(sth, 0xB0000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} + Value* ea = g.gpr_value(i.X.B); + if (i.X.A) { + ea = b.CreateAdd(g.gpr_value(i.X.A), ea); + } + Value* v = g.gpr_value(i.X.D); + g.WriteMemory(ea, 4, v); -XEEMITTER(sthu, 0xB4000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(sthux, 0x7C00036E, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(sthx, 0x7C00032E, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stw, 0x90000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stwu, 0x94000000, D )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stwux, 0x7C00016E, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} - -XEEMITTER(stwx, 0x7C00012E, X )(FunctionGenerator& g, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + return 0; } // Integer load and store with byte reverse (A-1 -XEEMITTER(lhbrx, 0x7C00062C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lhbrx, 0x7C00062C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lwbrx, 0x7C00042C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lwbrx, 0x7C00042C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(ldbrx, 0x7C000428, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(ldbrx, 0x7C000428, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(sthbrx, 0x7C00072C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(sthbrx, 0x7C00072C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stwbrx, 0x7C00052C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stwbrx, 0x7C00052C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stdbrx, 0x7C000528, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stdbrx, 0x7C000528, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -256,12 +466,12 @@ XEEMITTER(stdbrx, 0x7C000528, X )(FunctionGenerator& g, InstrData& i) { // Integer load and store multiple (A-16) -XEEMITTER(lmw, 0xB8000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lmw, 0xB8000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stmw, 0xBC000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stmw, 0xBC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -269,22 +479,22 @@ XEEMITTER(stmw, 0xBC000000, D )(FunctionGenerator& g, InstrData& i) { // Integer load and store string (A-17) -XEEMITTER(lswi, 0x7C0004AA, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lswi, 0x7C0004AA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lswx, 0x7C00042A, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lswx, 0x7C00042A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stswi, 0x7C0005AA, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stswi, 0x7C0005AA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stswx, 0x7C00052A, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stswx, 0x7C00052A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -292,37 +502,37 @@ XEEMITTER(stswx, 0x7C00052A, X )(FunctionGenerator& g, InstrData& i) { // Memory synchronization (A-18) -XEEMITTER(eieio, 0x7C0006AC, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(eieio, 0x7C0006AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(isync, 0x4C00012C, XL )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(isync, 0x4C00012C, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(ldarx, 0x7C0000A8, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(ldarx, 0x7C0000A8, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lwarx, 0x7C000028, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lwarx, 0x7C000028, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stdcx, 0x7C0001AD, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stdcx, 0x7C0001AD, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stwcx, 0x7C00012D, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stwcx, 0x7C00012D, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(sync, 0x7C0004AC, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(sync, 0x7C0004AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -330,42 +540,42 @@ XEEMITTER(sync, 0x7C0004AC, X )(FunctionGenerator& g, InstrData& i) { // Floating-point load (A-19) -XEEMITTER(lfd, 0xC8000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lfd, 0xC8000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lfdu, 0xCC000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lfdu, 0xCC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lfdux, 0x7C0004EE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lfdux, 0x7C0004EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lfdx, 0x7C0004AE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lfdx, 0x7C0004AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lfs, 0xC0000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lfs, 0xC0000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lfsu, 0xC4000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lfsu, 0xC4000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lfsux, 0x7C00046E, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lfsux, 0x7C00046E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(lfsx, 0x7C00042E, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(lfsx, 0x7C00042E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -373,47 +583,47 @@ XEEMITTER(lfsx, 0x7C00042E, X )(FunctionGenerator& g, InstrData& i) { // Floating-point store (A-20) -XEEMITTER(stfd, 0xD8000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stfd, 0xD8000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stfdu, 0xDC000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stfdu, 0xDC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stfdux, 0x7C0005EE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stfdux, 0x7C0005EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stfdx, 0x7C0005AE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stfdx, 0x7C0005AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stfiwx, 0x7C0007AE, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stfiwx, 0x7C0007AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stfs, 0xD0000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stfs, 0xD0000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stfsu, 0xD4000000, D )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stfsu, 0xD4000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stfsux, 0x7C00056E, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stfsux, 0x7C00056E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(stfsx, 0x7C00052E, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(stfsx, 0x7C00052E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -421,33 +631,33 @@ XEEMITTER(stfsx, 0x7C00052E, X )(FunctionGenerator& g, InstrData& i) { // Cache management (A-27) -XEEMITTER(dcbf, 0x7C0000AC, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(dcbf, 0x7C0000AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(dcbst, 0x7C00006C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(dcbst, 0x7C00006C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(dcbt, 0x7C00022C, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(dcbt, 0x7C00022C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(dcbtst, 0x7C0001EC, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(dcbtst, 0x7C0001EC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(dcbz, 0x7C0007EC, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(dcbz, 0x7C0007EC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { // or dcbz128 0x7C2007EC XEINSTRNOTIMPLEMENTED(); return 1; } -XEEMITTER(icbi, 0x7C0007AC, X )(FunctionGenerator& g, InstrData& i) { +XEEMITTER(icbi, 0x7C0007AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } @@ -459,6 +669,7 @@ void RegisterEmitCategoryMemory() { XEREGISTEREMITTER(lbzux, 0x7C0000EE); XEREGISTEREMITTER(lbzx, 0x7C0000AE); XEREGISTEREMITTER(ld, 0xE8000000); + XEREGISTEREMITTER(ldu, 0xE8000001); XEREGISTEREMITTER(ldux, 0x7C00006A); XEREGISTEREMITTER(ldx, 0x7C00002A); XEREGISTEREMITTER(lha, 0xA8000000); diff --git a/src/cpu/codegen/function_generator.cc b/src/cpu/codegen/function_generator.cc index 001aa2506..7ed409b08 100644 --- a/src/cpu/codegen/function_generator.cc +++ b/src/cpu/codegen/function_generator.cc @@ -9,6 +9,8 @@ #include +#include + using namespace llvm; using namespace xe::cpu::codegen; @@ -35,21 +37,28 @@ using namespace xe::cpu::sdb; */ -FunctionGenerator::FunctionGenerator(xe_memory_ref memory, FunctionSymbol* fn, - LLVMContext* context, Module* gen_module, - Function* gen_fn) { +FunctionGenerator::FunctionGenerator( + xe_memory_ref memory, SymbolDatabase* sdb, FunctionSymbol* fn, + LLVMContext* context, Module* gen_module, Function* gen_fn) { memory_ = memory; + sdb_ = sdb; fn_ = fn; context_ = context; gen_module_ = gen_module; gen_fn_ = gen_fn; builder_ = new IRBuilder<>(*context_); + + xe_zero_struct(&values_, sizeof(values_)); } FunctionGenerator::~FunctionGenerator() { delete builder_; } +SymbolDatabase* FunctionGenerator::sdb() { + return sdb_; +} + FunctionSymbol* FunctionGenerator::fn() { return fn_; } @@ -66,7 +75,21 @@ llvm::Function* FunctionGenerator::gen_fn() { return gen_fn_; } +FunctionBlock* FunctionGenerator::fn_block() { + return fn_block_; +} + void FunctionGenerator::GenerateBasicBlocks() { + // Always add an entry block. + BasicBlock* entry = BasicBlock::Create(*context_, "entry", gen_fn_); + + // If this function is empty, abort! + if (!fn_->blocks.size()) { + builder_->SetInsertPoint(entry); + builder_->CreateRetVoid(); + return; + } + // Pass 1 creates all of the blocks - this way we can branch to them. for (std::map::iterator it = fn_->blocks.begin(); it != fn_->blocks.end(); ++it) { @@ -78,6 +101,11 @@ void FunctionGenerator::GenerateBasicBlocks() { bbs_.insert(std::pair(block->start_address, bb)); } + // Entry always jumps to the first bb. + builder_->SetInsertPoint(entry); + builder_->CreateBr(bbs_.begin()->second); + + // Pass 2 fills in instructions. for (std::map::iterator it = fn_->blocks.begin(); it != fn_->blocks.end(); ++it) { FunctionBlock* block = it->second; @@ -89,6 +117,9 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block, BasicBlock* bb) { printf(" bb %.8X-%.8X:\n", block->start_address, block->end_address); + fn_block_ = block; + bb_ = bb; + // Move the builder to this block and setup. builder_->SetInsertPoint(bb); //i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname))); @@ -110,11 +141,32 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block, // builder_>SetCurrentDebugLocation(DebugLoc::get( // ia >> 8, ia & 0xFF, ctx->cu)); - //emit(this, i, builder); + typedef int (*InstrEmitter)(FunctionGenerator& g, IRBuilder<>& b, + InstrData& i); + InstrEmitter emit = (InstrEmitter)i.type->emit; + XEASSERTNOTNULL(emit); + int result = emit(*this, *builder_, i); + if (result) { + printf("---- error generating instruction: %.8X\n", ia); + } } - //Value* tmp = builder_->getInt32(0); - builder_->CreateRetVoid(); + // If we fall through, create the branch. + if (block->outgoing_type == FunctionBlock::kTargetNone) { + // Flush registers. + // TODO(benvanik): only do this before jumps out. + FlushRegisters(); + + BasicBlock* next_bb = GetNextBasicBlock(); + XEASSERTNOTNULL(next_bb); + builder_->CreateBr(next_bb); + } else if (block->outgoing_type == FunctionBlock::kTargetUnknown) { + // Hrm. + // TODO(benvanik): assert this doesn't occur - means a bad sdb run! + XELOGCPU("SDB function scan error in %.8X: bb %.8X has unknown exit\n", + fn_->start_address, block->start_address); + builder_->CreateRetVoid(); + } // TODO(benvanik): finish up BB } @@ -127,66 +179,299 @@ BasicBlock* FunctionGenerator::GetBasicBlock(uint32_t address) { return NULL; } -Function* FunctionGenerator::GetFunction(uint32_t addr) { +BasicBlock* FunctionGenerator::GetNextBasicBlock() { + std::map::iterator it = bbs_.find( + fn_block_->start_address); + ++it; + if (it != bbs_.end()) { + return it->second; + } return NULL; } +Function* FunctionGenerator::GetFunction(FunctionSymbol* fn) { + Function* result = gen_module_->getFunction(StringRef(fn->name)); + if (!result) { + XELOGE("Static function not found: %.8X %s\n", fn->start_address, fn->name); + } + XEASSERTNOTNULL(result); + return result; +} + +Value* FunctionGenerator::LoadStateValue(uint32_t offset, Type* type, + const char* name) { + PointerType* pointerTy = PointerType::getUnqual(type); + Function::arg_iterator args = gen_fn_->arg_begin(); + Value* statePtr = args; + Value* address = builder_->CreateConstInBoundsGEP1_32( + statePtr, offset); + Value* ptr = builder_->CreatePointerCast(address, pointerTy); + return builder_->CreateLoad(ptr, name); +} + +void FunctionGenerator::StoreStateValue(uint32_t offset, Type* type, + Value* value) { + PointerType* pointerTy = PointerType::getUnqual(type); + Function::arg_iterator args = gen_fn_->arg_begin(); + Value* statePtr = args; + Value* address = builder_->CreateConstInBoundsGEP1_32( + statePtr, offset); + Value* ptr = builder_->CreatePointerCast(address, pointerTy); + + // Widen to target type if needed. + if (!value->getType()->isIntegerTy(type->getIntegerBitWidth())) { + value = builder_->CreateZExt(value, type); + } + + builder_->CreateStore(value, ptr); +} + Value* FunctionGenerator::cia_value() { return builder_->getInt32(cia_); } void FunctionGenerator::FlushRegisters() { + // This flushes all local registers (if written) to the register bank and + // resets their values. + // + // TODO(benvanik): only flush if actually required, or selective flushes. + // xer + + if (values_.lr && values_.lr_dirty) { + StoreStateValue( + offsetof(xe_ppc_state_t, lr), + builder_->getInt64Ty(), + values_.lr); + values_.lr = NULL; + values_.lr_dirty = false; + } + + if (values_.ctr && values_.ctr_dirty) { + StoreStateValue( + offsetof(xe_ppc_state_t, ctr), + builder_->getInt64Ty(), + values_.ctr); + values_.ctr = NULL; + values_.ctr_dirty = false; + } + + // TODO(benvanik): don't flush across calls? + if (values_.cr && values_.cr_dirty) { + StoreStateValue( + offsetof(xe_ppc_state_t, cr), + builder_->getInt64Ty(), + values_.cr); + values_.cr = NULL; + values_.cr_dirty = false; + } + + for (uint32_t n = 0; n < XECOUNT(values_.gpr); n++) { + Value* v = values_.gpr[n]; + if (v && (values_.gpr_dirty_bits & (1 << n))) { + StoreStateValue( + offsetof(xe_ppc_state_t, r) + 8 * n, + builder_->getInt64Ty(), + values_.gpr[n]); + values_.gpr[n] = NULL; + } + } + values_.gpr_dirty_bits = 0; } Value* FunctionGenerator::xer_value() { - return NULL; + if (true) {//!values_.xer) { + // Fetch from register bank. + Value* v = LoadStateValue( + offsetof(xe_ppc_state_t, xer), + builder_->getInt64Ty(), + "xer_"); + values_.xer = v; + return v; + } else { + // Return local. + return values_.xer; + } } void FunctionGenerator::update_xer_value(Value* value) { + // Widen to 64bits if needed. + if (!value->getType()->isIntegerTy(64)) { + value = builder_->CreateZExt(value, builder_->getInt64Ty()); + } + values_.xer = value; + values_.xer_dirty = true; } Value* FunctionGenerator::lr_value() { - return NULL; + if (true) {//!values_.lr) { + // Fetch from register bank. + Value* v = LoadStateValue( + offsetof(xe_ppc_state_t, lr), + builder_->getInt64Ty(), + "lr_"); + values_.lr = v; + return v; + } else { + // Return local. + return values_.lr; + } } void FunctionGenerator::update_lr_value(Value* value) { + // Widen to 64bits if needed. + if (!value->getType()->isIntegerTy(64)) { + value = builder_->CreateZExt(value, builder_->getInt64Ty()); + } + values_.lr = value; + values_.lr_dirty = true; } Value* FunctionGenerator::ctr_value() { - return NULL; + if (true) {//!values_.ctr) { + // Fetch from register bank. + Value* v = LoadStateValue( + offsetof(xe_ppc_state_t, ctr), + builder_->getInt64Ty(), + "ctr_"); + values_.ctr = v; + return v; + } else { + // Return local. + return values_.ctr; + } } void FunctionGenerator::update_ctr_value(Value* value) { + // Widen to 64bits if needed. + if (!value->getType()->isIntegerTy(64)) { + value = builder_->CreateZExt(value, builder_->getInt64Ty()); + } + values_.ctr = value; + values_.ctr_dirty = true; } -Value* FunctionGenerator::cr_value(uint32_t n) { - return NULL; +Value* FunctionGenerator::cr_value() { + if (true) {//!values_.cr) { + // Fetch from register bank. + Value* v = LoadStateValue( + offsetof(xe_ppc_state_t, cr), + builder_->getInt64Ty(), + "cr_"); + values_.cr = v; + return v; + } else { + // Return local. + return values_.cr; + } } -void FunctionGenerator::update_cr_value(uint32_t n, Value* value) { - // +void FunctionGenerator::update_cr_value(Value* value) { + values_.cr = value; + values_.cr_dirty = true; } Value* FunctionGenerator::gpr_value(uint32_t n) { - return NULL; + if (n == 0) { + // Always force zero to a constant - this should help LLVM. + return builder_->getInt64(0); + } + if (true) {//!values_.gpr[n]) { + // Need to fetch from register bank. + char name[30]; + xesnprintfa(name, XECOUNT(name), "gpr_r%d_", n); + Value* v = LoadStateValue( + offsetof(xe_ppc_state_t, r) + 8 * n, + builder_->getInt64Ty(), + name); + values_.gpr[n] = v; + return v; + } else { + // Local value, reuse. + return values_.gpr[n]; + } } void FunctionGenerator::update_gpr_value(uint32_t n, Value* value) { - // + if (n == 0) { + // Ignore writes to zero. + return; + } + + // Widen to 64bits if needed. + if (!value->getType()->isIntegerTy(64)) { + value = builder_->CreateZExt(value, builder_->getInt64Ty()); + } + + values_.gpr[n] = value; + values_.gpr_dirty_bits |= 1 << n; +} + +Value* FunctionGenerator::GetMembase() { + Value* v = gen_module_->getGlobalVariable("xe_memory_base"); + return builder_->CreateLoad(v); } Value* FunctionGenerator::memory_addr(uint32_t addr) { return NULL; } -Value* FunctionGenerator::read_memory(Value* addr, uint32_t size, bool extend) { - return NULL; +Value* FunctionGenerator::ReadMemory(Value* addr, uint32_t size, bool extend) { + Type* dataTy = NULL; + switch (size) { + case 1: + dataTy = builder_->getInt8Ty(); + break; + case 2: + dataTy = builder_->getInt16Ty(); + break; + case 4: + dataTy = builder_->getInt32Ty(); + break; + case 8: + dataTy = builder_->getInt64Ty(); + break; + default: + XEASSERTALWAYS(); + return NULL; + } + PointerType* pointerTy = PointerType::getUnqual(dataTy); + + Value* address = builder_->CreateInBoundsGEP(GetMembase(), addr); + Value* ptr = builder_->CreatePointerCast(address, pointerTy); + return builder_->CreateLoad(ptr); } -void FunctionGenerator::write_memory(Value* addr, uint32_t size, Value* value) { - // +void FunctionGenerator::WriteMemory(Value* addr, uint32_t size, Value* value) { + Type* dataTy = NULL; + switch (size) { + case 1: + dataTy = builder_->getInt8Ty(); + break; + case 2: + dataTy = builder_->getInt16Ty(); + break; + case 4: + dataTy = builder_->getInt32Ty(); + break; + case 8: + dataTy = builder_->getInt64Ty(); + break; + default: + XEASSERTALWAYS(); + return; + } + PointerType* pointerTy = PointerType::getUnqual(dataTy); + + Value* address = builder_->CreateInBoundsGEP(GetMembase(), addr); + Value* ptr = builder_->CreatePointerCast(address, pointerTy); + + // Truncate, if required. + if (value->getType() != dataTy) { + value = builder_->CreateTrunc(value, dataTy); + } + builder_->CreateStore(value, ptr); } diff --git a/src/cpu/codegen/module_generator.cc b/src/cpu/codegen/module_generator.cc index fc4aef42c..c8f22ce84 100644 --- a/src/cpu/codegen/module_generator.cc +++ b/src/cpu/codegen/module_generator.cc @@ -104,6 +104,7 @@ int ModuleGenerator::Generate() { } break; default: + XEASSERTALWAYS(); break; } } @@ -139,6 +140,7 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) { AttributeSet attrs = AttributeSet::get(context, awi); std::vector args; + args.push_back(PointerType::getUnqual(Type::getInt8Ty(context))); Type* return_type = Type::getInt32Ty(context); FunctionType* ft = FunctionType::get(return_type, @@ -148,6 +150,10 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) { f->setCallingConv(CallingConv::C); f->setVisibility(GlobalValue::DefaultVisibility); + Function::arg_iterator fn_args = f->arg_begin(); + Value* fn_arg = fn_args++; + fn_arg->setName("state"); + // TODO(benvanik): log errors. BasicBlock* block = BasicBlock::Create(context, "entry", f); IRBuilder<> builder(block); @@ -185,23 +191,21 @@ void ModuleGenerator::PrepareFunction(FunctionSymbol* fn) { AttributeSet attrs = AttributeSet::get(context, awi); std::vector args; + args.push_back(PointerType::getUnqual(Type::getInt8Ty(context))); Type* return_type = Type::getVoidTy(context); - char name[64]; - char* pname = name; - if (fn->name) { - pname = fn->name; - } else { - xesnprintfa(name, XECOUNT(name), "sub_%.8X", fn->start_address); - } - FunctionType* ft = FunctionType::get(return_type, ArrayRef(args), false); + XEASSERTNOTNULL(fn->name); Function* f = cast( - m->getOrInsertFunction(StringRef(pname), ft, attrs)); + m->getOrInsertFunction(StringRef(fn->name), ft, attrs)); f->setCallingConv(CallingConv::C); f->setVisibility(GlobalValue::DefaultVisibility); + Function::arg_iterator fn_args = f->arg_begin(); + Value* fn_arg = fn_args++; + fn_arg->setName("state"); + CodegenFunction* cgf = new CodegenFunction(); cgf->symbol = fn; cgf->function_type = ft; @@ -216,7 +220,8 @@ void ModuleGenerator::BuildFunction(CodegenFunction* cgf) { printf("%s:\n", fn->name); // Setup the generation context. - FunctionGenerator fgen(memory_, fn, context_, gen_module_, cgf->function); + FunctionGenerator fgen( + memory_, sdb_, fn, context_, gen_module_, cgf->function); // Run through and generate each basic block. fgen.GenerateBasicBlocks(); @@ -229,6 +234,7 @@ void ModuleGenerator::BuildFunction(CodegenFunction* cgf) { void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) { FunctionPassManager pm(m); +#if XE_OPTION(OPTIMIZED) PassManagerBuilder pmb; pmb.OptLevel = 3; pmb.SizeLevel = 0; @@ -236,6 +242,7 @@ void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) { pmb.Vectorize = true; pmb.LoopVectorize = true; pmb.populateFunctionPassManager(pm); +#endif // XE_OPTION(OPTIMIZED) pm.add(createVerifierPass()); pm.run(*fn); } diff --git a/src/cpu/exec_module.cc b/src/cpu/exec_module.cc index 71dac38e6..2d19d3f4e 100644 --- a/src/cpu/exec_module.cc +++ b/src/cpu/exec_module.cc @@ -126,6 +126,8 @@ int ExecModule::Prepare() { context_.get(), gen_module_.get())); XEEXPECTZERO(codegen_->Generate()); + gen_module_->dump(); + // Write to cache. outs = auto_ptr(new raw_fd_ostream( cache_path, error_message, raw_fd_ostream::F_Binary)); @@ -141,6 +143,7 @@ int ExecModule::Prepare() { // Run full module optimizations. pm.add(new DataLayout(gen_module_.get())); +#if XE_OPTION(OPTIMIZED) pm.add(createVerifierPass()); pmb.OptLevel = 3; pmb.SizeLevel = 0; @@ -149,6 +152,7 @@ int ExecModule::Prepare() { pmb.LoopVectorize = true; pmb.populateModulePassManager(pm); pmb.populateLTOPassManager(pm, false, true); +#endif // XE_OPTION(OPTIMIZED) pm.add(createVerifierPass()); pm.run(*gen_module_); @@ -158,9 +162,9 @@ int ExecModule::Prepare() { XEEXPECTZERO(Init()); // Force JIT of all functions. - for (Module::iterator I = gen_module_->begin(), E = gen_module_->end(); - I != E; I++) { - Function* fn = &*I; + for (Module::iterator it = gen_module_->begin(); it != gen_module_->end(); + ++it) { + Function* fn = it; if (!fn->isDeclaration()) { engine_->getPointerToFunction(fn); } @@ -174,7 +178,7 @@ XECLEANUP: int ExecModule::InjectGlobals() { LLVMContext& context = *context_.get(); const DataLayout* dl = engine_->getDataLayout(); - Type* voidPtrTy = PointerType::getUnqual(Type::getVoidTy(context)); + Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context)); Type* intPtrTy = dl->getIntPtrType(context); GlobalVariable* gv; @@ -182,7 +186,7 @@ int ExecModule::InjectGlobals() { // This is the base void* pointer to the memory space. gv = new GlobalVariable( *gen_module_, - voidPtrTy, + int8PtrTy, true, GlobalValue::ExternalLinkage, 0, @@ -191,10 +195,7 @@ int ExecModule::InjectGlobals() { gv->setAlignment(64); gv->setInitializer(ConstantExpr::getIntToPtr( ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)), - voidPtrTy)); - - // xe_ppc_state - // ... + int8PtrTy)); return 0; } @@ -224,6 +225,6 @@ int ExecModule::Uninit() { } void ExecModule::Dump() { - sdb_->Dump(); - gen_module_->dump(); + // sdb_->Dump(); + // gen_module_->dump(); } diff --git a/src/cpu/processor.cc b/src/cpu/processor.cc index 9d66c07a4..c6144bda1 100644 --- a/src/cpu/processor.cc +++ b/src/cpu/processor.cc @@ -97,7 +97,7 @@ int Processor::PrepareModule(UserModule* user_module, modules_.push_back(exec_module); - user_module->Dump(export_resolver.get()); + //user_module->Dump(export_resolver.get()); exec_module->Dump(); return 0; diff --git a/src/cpu/sdb.cc b/src/cpu/sdb.cc index 8d0e9bd49..93fc778ee 100644 --- a/src/cpu/sdb.cc +++ b/src/cpu/sdb.cc @@ -149,6 +149,16 @@ int SymbolDatabase::Analyze() { FlushQueue(); } + // Run over all symbols and see if any slipped through, somehow. + for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) { + if (it->second->symbol_type == Symbol::Function) { + FunctionSymbol* fn = static_cast(it->second); + if (fn->type == FunctionSymbol::Unknown) { + printf("UNKNOWN FN %.8X\n", fn->start_address); + } + } + } + // Run a pass over all functions and link up their extended data. // This can only be performed after we have all functions and basic blocks. for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) { @@ -290,7 +300,10 @@ void SymbolDatabase::DumpFunctionBlocks(FunctionSymbol* fn) { printf(" call %.8X %s\n", block->outgoing_function->start_address, block->outgoing_function->name); break; case FunctionBlock::kTargetLR: - printf(" return\n"); + printf(" branch lr\n"); + break; + case FunctionBlock::kTargetCTR: + printf(" branch ctr\n"); break; case FunctionBlock::kTargetNone: printf("\n"); @@ -520,6 +533,11 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) { fn->name = xestrdup(name); } + // Set type, if needed. We assume user if not set. + if (fn->type == FunctionSymbol::Unknown) { + fn->type = FunctionSymbol::User; + } + InstrData i; FunctionBlock* block = NULL; uint32_t furthest_target = fn->start_address; @@ -615,6 +633,7 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) { ends_block = true; } else if (i.type->opcode == 0x4C000020) { // bclr/bclrl + block->outgoing_type = FunctionBlock::kTargetLR; if (i.XL.LK) { XELOGSDB("bclrl %.8X\n", addr); } else { @@ -623,6 +642,7 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) { ends_block = true; } else if (i.type->opcode == 0x4C000420) { // bcctr/bcctrl + block->outgoing_type = FunctionBlock::kTargetCTR; if (i.XL.LK) { XELOGSDB("bcctrl %.8X\n", addr); } else { diff --git a/src/cpu/xethunk/xethunk.c b/src/cpu/xethunk/xethunk.c index 773c2f4d2..0d974e244 100644 --- a/src/cpu/xethunk/xethunk.c +++ b/src/cpu/xethunk/xethunk.c @@ -21,13 +21,12 @@ // NOTE: only headers in this directory should be included. #include "xethunk.h" -#include -// Global CPU state. -// Instructions that dereference the state use this. -// TODO(benvanik): noalias/invariant/etc?s -static xe_ppc_state_t* xe_ppc_state; +// 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() { diff --git a/src/cpu/xethunk/xethunk.h b/src/cpu/xethunk/xethunk.h index 1548876d8..3b51837aa 100644 --- a/src/cpu/xethunk/xethunk.h +++ b/src/cpu/xethunk/xethunk.h @@ -13,8 +13,8 @@ * include any other files. */ -#ifndef XENIA_CPU_XELIB_H_ -#define XENIA_CPU_XELIB_H_ +#ifndef XENIA_CPU_XETHUNK_H_ +#define XENIA_CPU_XETHUNK_H_ -#endif // XENIA_CPU_XELIB_H_ +#endif // XENIA_CPU_XETHUNK_H_ diff --git a/xenia-build.py b/xenia-build.py index 9d56ab645..3d2e33a43 100755 --- a/xenia-build.py +++ b/xenia-build.py @@ -240,7 +240,7 @@ class SetupCommand(Command): '-G"%s"' % (generator), '-DCMAKE_INSTALL_PREFIX:STRING=../../../%s' % (path), '-DCMAKE_BUILD_TYPE:STRING=%s' % (mode), - '-DLLVM_TARGETS_TO_BUILD:STRING="X86;PowerPC"', + '-DLLVM_TARGETS_TO_BUILD:STRING="X86;PowerPC;CppBackend"', '-DLLVM_INCLUDE_EXAMPLES:BOOL=OFF', '-DLLVM_INCLUDE_TESTS:BOOL=OFF', '../../../third_party/llvm/', @@ -394,7 +394,7 @@ class XethunkCommand(Command): print '' path = 'src/cpu/xethunk/xethunk' - result = shell_call('clang -emit-llvm -O0 -Iinclude/ -c %s.c -o %s.bc' % (path, path), + result = shell_call('clang -emit-llvm -O0 -c %s.c -o %s.bc' % (path, path), throw_on_error=False) if result != 0: return result