Generating a lot of code!

Still a few missing instructions/variants and other issues, but a big and
valid LLVM module is being generated.
This commit is contained in:
Ben Vanik 2013-01-22 00:22:27 -08:00
parent 791f14182c
commit 91f9e8b7bb
18 changed files with 1613 additions and 423 deletions

View File

@ -23,10 +23,14 @@
#define XE_OPTION_LOG_INFO 1 #define XE_OPTION_LOG_INFO 1
#define XE_OPTION_LOG_DEBUG 1 #define XE_OPTION_LOG_DEBUG 1
#define XE_OPTION_LOG_CPU 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_GPU 1
#define XE_OPTION_LOG_KERNEL 1 #define XE_OPTION_LOG_KERNEL 1
// TODO(benvanik): make this a runtime option
#define XE_OPTION_OPTIMIZED 0
#endif // XENIA_CONFIG_H_ #endif // XENIA_CONFIG_H_

View File

@ -28,20 +28,28 @@ namespace codegen {
class FunctionGenerator { class FunctionGenerator {
public: public:
FunctionGenerator(xe_memory_ref memory, sdb::FunctionSymbol* fn, FunctionGenerator(
llvm::LLVMContext* context, llvm::Module* gen_module, xe_memory_ref memory, sdb::SymbolDatabase* sdb, sdb::FunctionSymbol* fn,
llvm::Function* gen_fn); llvm::LLVMContext* context, llvm::Module* gen_module,
llvm::Function* gen_fn);
~FunctionGenerator(); ~FunctionGenerator();
sdb::SymbolDatabase* sdb();
sdb::FunctionSymbol* fn(); sdb::FunctionSymbol* fn();
llvm::LLVMContext* context(); llvm::LLVMContext* context();
llvm::Module* gen_module(); llvm::Module* gen_module();
llvm::Function* gen_fn(); llvm::Function* gen_fn();
sdb::FunctionBlock* fn_block();
void GenerateBasicBlocks(); void GenerateBasicBlocks();
llvm::BasicBlock* GetBasicBlock(uint32_t address); 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(); llvm::Value* cia_value();
@ -54,24 +62,28 @@ public:
llvm::Value* ctr_value(); llvm::Value* ctr_value();
void update_ctr_value(llvm::Value* value); void update_ctr_value(llvm::Value* value);
llvm::Value* cr_value(uint32_t n); llvm::Value* cr_value();
void update_cr_value(uint32_t n, llvm::Value* value); void update_cr_value(llvm::Value* value);
llvm::Value* gpr_value(uint32_t n); llvm::Value* gpr_value(uint32_t n);
void update_gpr_value(uint32_t n, llvm::Value* value); void update_gpr_value(uint32_t n, llvm::Value* value);
llvm::Value* GetMembase();
llvm::Value* memory_addr(uint32_t addr); llvm::Value* memory_addr(uint32_t addr);
llvm::Value* read_memory(llvm::Value* addr, uint32_t size, bool extend); llvm::Value* ReadMemory(llvm::Value* addr, uint32_t size, bool extend);
void write_memory(llvm::Value* addr, uint32_t size, llvm::Value* value); void WriteMemory(llvm::Value* addr, uint32_t size, llvm::Value* value);
private: private:
void GenerateBasicBlock(sdb::FunctionBlock* block, llvm::BasicBlock* bb); void GenerateBasicBlock(sdb::FunctionBlock* block, llvm::BasicBlock* bb);
xe_memory_ref memory_; xe_memory_ref memory_;
sdb::FunctionSymbol* fn_; sdb::SymbolDatabase* sdb_;
llvm::LLVMContext* context_; sdb::FunctionSymbol* fn_;
llvm::Module* gen_module_; llvm::LLVMContext* context_;
llvm::Function* gen_fn_; llvm::Module* gen_module_;
llvm::Function* gen_fn_;
sdb::FunctionBlock* fn_block_;
llvm::BasicBlock* bb_;
llvm::IRBuilder<>* builder_; llvm::IRBuilder<>* builder_;
std::map<uint32_t, llvm::BasicBlock*> bbs_; std::map<uint32_t, llvm::BasicBlock*> bbs_;
@ -81,12 +93,17 @@ private:
struct { struct {
llvm::Value* xer; llvm::Value* xer;
bool xer_dirty;
llvm::Value* lr; llvm::Value* lr;
bool lr_dirty;
llvm::Value* ctr; llvm::Value* ctr;
bool ctr_dirty;
llvm::Value* cr[4]; llvm::Value* cr;
bool cr_dirty;
llvm::Value* gpr[32]; llvm::Value* gpr[32];
uint32_t gpr_dirty_bits;
} values_; } values_;
}; };

View File

@ -104,6 +104,14 @@ typedef struct {
uint32_t OPCD : 6; uint32_t OPCD : 6;
} DS; } DS;
// kXEPPCInstrFormatX // 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 // kXEPPCInstrFormatXL
struct { struct {
uint32_t LK : 1; uint32_t LK : 1;
@ -123,6 +131,15 @@ typedef struct {
// kXEPPCInstrFormatXFL // kXEPPCInstrFormatXFL
// kXEPPCInstrFormatXS // kXEPPCInstrFormatXS
// kXEPPCInstrFormatXO // 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 // kXEPPCInstrFormatA
// kXEPPCInstrFormatM // kXEPPCInstrFormatM
// kXEPPCInstrFormatMD // kXEPPCInstrFormatMD

View File

@ -19,6 +19,12 @@
#include <stdint.h> #include <stdint.h>
#ifdef XE_THUNK
#define XECACHEALIGN __attribute__ ((aligned(8)))
#define XECACHEALIGN64 __attribute__ ((aligned(64)))
#endif
// namespace FPRF { // namespace FPRF {
// enum FPRF_e { // enum FPRF_e {
// QUIET_NAN = 0x00088000, // QUIET_NAN = 0x00088000,
@ -34,7 +40,7 @@
// } // FPRF // } // FPRF
typedef struct XECACHEALIGN { typedef struct XECACHEALIGN xe_float4 {
union { union {
struct { struct {
float x; float x;
@ -51,17 +57,17 @@ typedef struct XECACHEALIGN {
} xe_float4_t; } xe_float4_t;
typedef struct XECACHEALIGN64 { typedef struct XECACHEALIGN64 xe_ppc_state {
uint64_t r[32]; // General purpose registers
xe_float4_t v[128]; // VMX128 vector registers
double f[32]; // Floating-point registers
uint32_t cia; // Current PC (CIA) uint32_t cia; // Current PC (CIA)
uint32_t nia; // Next PC (NIA) uint32_t nia; // Next PC (NIA)
uint64_t xer; // XER register uint64_t xer; // XER register
uint64_t lr; // Link register uint64_t lr; // Link register
uint64_t ctr; // Count 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 { union {
uint32_t value; uint32_t value;
struct { struct {
@ -76,6 +82,12 @@ typedef struct XECACHEALIGN64 {
uint8_t vx :1; // FP invalid operation exception summary - copy of FPSCR[VX] uint8_t vx :1; // FP invalid operation exception summary - copy of FPSCR[VX]
uint8_t ox :1; // FP overflow exception - copy of FPSCR[OX] uint8_t ox :1; // FP overflow exception - copy of FPSCR[OX]
} cr1; } 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 } cr; // Condition register
union { union {

View File

@ -68,7 +68,8 @@ public:
kTargetBlock = 1, kTargetBlock = 1,
kTargetFunction = 2, kTargetFunction = 2,
kTargetLR = 3, kTargetLR = 3,
kTargetNone = 4, kTargetCTR = 4,
kTargetNone = 5,
}; };
FunctionBlock(); FunctionBlock();
@ -106,7 +107,7 @@ public:
uint32_t start_address; uint32_t start_address;
uint32_t end_address; uint32_t end_address;
char *name; char* name;
FunctionType type; FunctionType type;
uint32_t flags; uint32_t flags;
@ -126,7 +127,7 @@ public:
virtual ~VariableSymbol(); virtual ~VariableSymbol();
uint32_t address; uint32_t address;
char *name; char* name;
}; };
class ExceptionEntrySymbol : public Symbol { class ExceptionEntrySymbol : public Symbol {

View File

@ -29,7 +29,8 @@ void RegisterEmitCategoryMemory();
#define XEREGISTEREMITTER(name, opcode) \ #define XEREGISTEREMITTER(name, opcode) \
RegisterInstrEmit(opcode, (void*)InstrEmit_##name) RegisterInstrEmit(opcode, (void*)InstrEmit_##name)
#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS #define XEINSTRNOTIMPLEMENTED()
//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS
} // namespace codegen } // namespace codegen

View File

@ -9,6 +9,8 @@
#include "cpu/codegen/emit.h" #include "cpu/codegen/emit.h"
#include <llvm/IR/Intrinsics.h>
#include <xenia/cpu/codegen/function_generator.h> #include <xenia/cpu/codegen/function_generator.h>
@ -24,137 +26,168 @@ namespace codegen {
// Integer arithmetic (A-3) // 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(addcx, 0X7C000014, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(addex, 0x7C000114, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(addi, 0x38000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(addicx, 0x34000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(addicx, 0x34000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(addzex, 0x7C000194, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(addis, 0x3C000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(divdx, 0x7C0003D2, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(addmex, 0x7C0001D4, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(divdux, 0x7C000392, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(addzex, 0x7C000194, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(divwx, 0x7C0003D6, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(divdx, 0x7C0003D2, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(divdux, 0x7C000392, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mulhdx, 0x7C000092, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(divwx, 0x7C0003D6, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mulhdux, 0x7C000012, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(divwux, 0x7C000396, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mulhwx, 0x7C000096, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mulhdx, 0x7C000092, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mulhwux, 0x7C000016, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mulhdux, 0x7C000012, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mulldx, 0x7C0001D2, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mulhwx, 0x7C000096, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mulli, 0x1C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mulhwux, 0x7C000016, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mullwx, 0x7C0001D6, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mulldx, 0x7C0001D2, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(negx, 0x7C0000D0, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mulli, 0x1C000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(subfx, 0x7C000050, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mullwx, 0x7C0001D6, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(subfcx, 0x7C000010, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(negx, 0x7C0000D0, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(subficx, 0x20000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(subfx, 0x7C000050, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(subfex, 0x7C000110, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(subfcx, 0x7C000010, XO )(FunctionGenerator& g, InstrData& i) { XEEMITTER(subfmex, 0x7C0001D0, XO )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(subficx, 0x20000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(subfzex, 0x7C000190, XO )(FunctionGenerator& g, IRBuilder<>& b, 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) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -162,168 +195,410 @@ XEEMITTER(subfzex, 0x7C000190, XO )(FunctionGenerator& g, InstrData& i) {
// Integer compare (A-4) // Integer compare (A-4)
XEEMITTER(cmp, 0x7C000000, X )(FunctionGenerator& g, InstrData& i) { void XeEmitCompareCore(FunctionGenerator& g, IRBuilder<>& b,
XEINSTRNOTIMPLEMENTED(); Value* lhs, Value* rhs, uint32_t BF, bool is_signed) {
return 1; 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) { XEEMITTER(cmp, 0x7C000000, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // if L = 0 then
return 1; // 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) { XEEMITTER(cmpi, 0x2C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // if L = 0 then
return 1; // 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) { XEEMITTER(cmpl, 0x7C000040, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // if L = 0 then
return 1; // a <- i32.0 || (RA)[32:63]
// b <- i32.0 || (RB)[32:63]
// else
// a <- (RA)
// b <- (RB)
// if a <u b then
// c <- 0b100
// else 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 <- 0b100
// else 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) // 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(); XEINSTRNOTIMPLEMENTED();
return 1; 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<Type*> 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(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(andisx, 0x74000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(extswx, 0x7C0007B4, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(cntlzdx, 0x7C000074, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(nandx, 0x7C0003B8, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(eqvx, 0x7C000238, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(ori, 0x60000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // RA <- (RS) | (i48.0 || UI)
return 1;
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) { XEEMITTER(oris, 0x64000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // RA <- (RS) | (i32.0 || UI || i16.0)
return 1;
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) { XEEMITTER(xorx, 0x7C000278, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // RA <- (RS) XOR (RB)
return 1;
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) { XEEMITTER(xori, 0x68000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // RA <- (RS) XOR (i48.0 || UI)
return 1;
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) { XEEMITTER(xoris, 0x6C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // RA <- (RS) XOR (i32.0 || UI || i16.0)
return 1;
}
XEEMITTER(norx, 0x7C0000F8, X )(FunctionGenerator& g, InstrData& i) { Value* v = b.CreateXor(g.gpr_value(i.D.D), ((uint64_t)i.D.SIMM) << 16);
XEINSTRNOTIMPLEMENTED(); g.update_gpr_value(i.D.A, v);
return 1;
}
XEEMITTER(orx, 0x7C000378, X )(FunctionGenerator& g, InstrData& i) { return 0;
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;
} }
// Integer rotate (A-6) // Integer rotate (A-6)
XEEMITTER(rldclx, 0x78000010, MDS)(FunctionGenerator& g, InstrData& i) { XEEMITTER(rldclx, 0x78000010, MDS)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(rldcrx, 0x78000012, MDS)(FunctionGenerator& g, InstrData& i) { XEEMITTER(rldcrx, 0x78000012, MDS)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(rldicx, 0x78000008, MD )(FunctionGenerator& g, InstrData& i) { XEEMITTER(rldicx, 0x78000008, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(rldiclx, 0x78000000, MD )(FunctionGenerator& g, InstrData& i) { XEEMITTER(rldiclx, 0x78000000, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(rldicrx, 0x78000004, MD )(FunctionGenerator& g, InstrData& i) { XEEMITTER(rldicrx, 0x78000004, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(rldimix, 0x7800000C, MD )(FunctionGenerator& g, InstrData& i) { XEEMITTER(rldimix, 0x7800000C, MD )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(rlwimix, 0x50000000, M )(FunctionGenerator& g, InstrData& i) { XEEMITTER(rlwimix, 0x50000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(rlwinmx, 0x54000000, M )(FunctionGenerator& g, InstrData& i) { XEEMITTER(rlwinmx, 0x54000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(rlwnmx, 0x5C000000, M )(FunctionGenerator& g, InstrData& i) { XEEMITTER(rlwnmx, 0x5C000000, M )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -331,42 +606,42 @@ XEEMITTER(rlwnmx, 0x5C000000, M )(FunctionGenerator& g, InstrData& i) {
// Integer shift (A-7) // Integer shift (A-7)
XEEMITTER(sldx, 0x7C000036, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(sldx, 0x7C000036, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(slwx, 0x7C000030, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(slwx, 0x7C000030, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(sradx, 0x7C000634, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(sradx, 0x7C000634, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(sradix, 0x7C000674, XS )(FunctionGenerator& g, InstrData& i) { XEEMITTER(sradix, 0x7C000674, XS )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(srawx, 0x7C000630, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(srawx, 0x7C000630, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(srawix, 0x7C000670, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(srawix, 0x7C000670, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(srdx, 0x7C000436, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(srdx, 0x7C000436, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(srwx, 0x7C000430, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(srwx, 0x7C000430, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }

View File

@ -15,6 +15,7 @@
using namespace llvm; using namespace llvm;
using namespace xe::cpu::codegen; using namespace xe::cpu::codegen;
using namespace xe::cpu::ppc; using namespace xe::cpu::ppc;
using namespace xe::cpu::sdb;
namespace xe { namespace xe {
@ -22,70 +23,356 @@ namespace cpu {
namespace codegen { namespace codegen {
XEEMITTER(bx, 0x48000000, I )(FunctionGenerator& g, InstrData& i) { int XeEmitBranchTo(FunctionGenerator& g, IRBuilder<>& b, const char* src,
XEINSTRNOTIMPLEMENTED(); uint32_t cia, bool lk) {
return 1; // 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) { XEEMITTER(bx, 0x48000000, I )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // if AA then
return 1; // 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) { XEEMITTER(bcx, 0x40000000, B )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // if ¬BO[2] then
return 1; // 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) { XEEMITTER(bcctrx, 0x4C000420, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1])
return 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) // Condition register logical (A-23)
XEEMITTER(crand, 0x4C000202, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(crand, 0x4C000202, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(crandc, 0x4C000102, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(crandc, 0x4C000102, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(creqv, 0x4C000242, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(creqv, 0x4C000242, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(crnand, 0x4C0001C2, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(crnand, 0x4C0001C2, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(crnor, 0x4C000042, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(crnor, 0x4C000042, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(cror, 0x4C000382, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(cror, 0x4C000382, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(crorc, 0x4C000342, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(crorc, 0x4C000342, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(crxor, 0x4C000182, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(crxor, 0x4C000182, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mcrf, 0x4C000000, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mcrf, 0x4C000000, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -93,7 +380,7 @@ XEEMITTER(mcrf, 0x4C000000, XL )(FunctionGenerator& g, InstrData& i) {
// System linkage (A-24) // System linkage (A-24)
XEEMITTER(sc, 0x44000002, SC )(FunctionGenerator& g, InstrData& i) { XEEMITTER(sc, 0x44000002, SC )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -101,22 +388,22 @@ XEEMITTER(sc, 0x44000002, SC )(FunctionGenerator& g, InstrData& i) {
// Trap (A-25) // Trap (A-25)
XEEMITTER(td, 0x7C000088, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(td, 0x7C000088, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(tdi, 0x08000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(tdi, 0x08000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(tw, 0x7C000008, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(tw, 0x7C000008, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(twi, 0x0C000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(twi, 0x0C000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -124,29 +411,82 @@ XEEMITTER(twi, 0x0C000000, D )(FunctionGenerator& g, InstrData& i) {
// Processor control (A-26) // Processor control (A-26)
XEEMITTER(mfcr, 0x7C000026, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mfcr, 0x7C000026, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mftb, 0x7C0002E6, XFX)(FunctionGenerator& g, InstrData& i) { XEEMITTER(mtcrf, 0x7C000120, XFX)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mtcrf, 0x7C000120, XFX)(FunctionGenerator& g, InstrData& i) { XEEMITTER(mtspr, 0x7C0003A6, XFX)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // n <- spr[5:9] || spr[0:4]
return 1; // if length(SPR(n)) = 64 then
} // SPR(n) <- (RS)
// else
// SPR(n) <- (RS)[32:63]
XEEMITTER(mtspr, 0x7C0003A6, XFX)(FunctionGenerator& g, InstrData& i) { Value* v = g.gpr_value(i.XFX.D);
XEINSTRNOTIMPLEMENTED();
return 1; 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;
} }

View File

@ -24,67 +24,67 @@ namespace codegen {
// Floating-point arithmetic (A-8) // Floating-point arithmetic (A-8)
XEEMITTER(faddx, 0xFC00002A, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(faddx, 0xFC00002A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(faddsx, 0xEC00002A, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(faddsx, 0xEC00002A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fdivx, 0xFC000024, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fdivx, 0xFC000024, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fdivsx, 0xEC000024, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fdivsx, 0xEC000024, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fmulx, 0xFC000032, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fmulx, 0xFC000032, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fmulsx, 0xEC000032, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fmulsx, 0xEC000032, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fresx, 0xEC000030, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fresx, 0xEC000030, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(frsqrtex, 0xFC000034, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(frsqrtex, 0xFC000034, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fsubx, 0xFC000028, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fsubx, 0xFC000028, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fsubsx, 0xEC000028, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fsubsx, 0xEC000028, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fselx, 0xFC00002E, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fselx, 0xFC00002E, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fsqrtx, 0xFC00002C, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fsqrtx, 0xFC00002C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fsqrtsx, 0xEC00002C, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fsqrtsx, 0xEC00002C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -92,42 +92,42 @@ XEEMITTER(fsqrtsx, 0xEC00002C, A )(FunctionGenerator& g, InstrData& i) {
// Floating-point multiply-add (A-9) // 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fmaddsx, 0xEC00003A, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fmaddsx, 0xEC00003A, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fmsubx, 0xFC000038, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fmsubx, 0xFC000038, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fmsubsx, 0xEC000038, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fmsubsx, 0xEC000038, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fnmaddx, 0xFC00003E, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fnmaddx, 0xFC00003E, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fnmaddsx, 0xEC00003E, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fnmaddsx, 0xEC00003E, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fnmsubx, 0xFC00003C, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fnmsubx, 0xFC00003C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fnmsubsx, 0xEC00003C, A )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fnmsubsx, 0xEC00003C, A )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -135,32 +135,32 @@ XEEMITTER(fnmsubsx, 0xEC00003C, A )(FunctionGenerator& g, InstrData& i) {
// Floating-point rounding and conversion (A-10) // 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fctidx, 0xFC00065C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fctidx, 0xFC00065C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fctidzx, 0xFC00065E, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fctidzx, 0xFC00065E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fctiwx, 0xFC00001C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fctiwx, 0xFC00001C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fctiwzx, 0xFC00001E, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fctiwzx, 0xFC00001E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(frspx, 0xFC000018, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(frspx, 0xFC000018, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -168,12 +168,12 @@ XEEMITTER(frspx, 0xFC000018, X )(FunctionGenerator& g, InstrData& i) {
// Floating-point compare (A-11) // Floating-point compare (A-11)
XEEMITTER(fcmpo, 0xFC000040, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fcmpo, 0xFC000040, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fcmpu, 0xFC000000, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fcmpu, 0xFC000000, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -181,32 +181,32 @@ XEEMITTER(fcmpu, 0xFC000000, X )(FunctionGenerator& g, InstrData& i) {
// Floating-point status and control register (A // 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mffsx, 0xFC00048E, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mffsx, 0xFC00048E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mtfsb0x, 0xFC00008C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mtfsb0x, 0xFC00008C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mtfsb1x, 0xFC00004C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mtfsb1x, 0xFC00004C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mtfsfx, 0xFC00058E, XFL)(FunctionGenerator& g, InstrData& i) { XEEMITTER(mtfsfx, 0xFC00058E, XFL)(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(mtfsfix, 0xFC00010C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(mtfsfix, 0xFC00010C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -214,22 +214,22 @@ XEEMITTER(mtfsfix, 0xFC00010C, X )(FunctionGenerator& g, InstrData& i) {
// Floating-point move (A-21) // Floating-point move (A-21)
XEEMITTER(fabsx, 0xFC000210, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fabsx, 0xFC000210, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fmrx, 0xFC000090, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fmrx, 0xFC000090, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fnabsx, 0xFC000110, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fnabsx, 0xFC000110, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(fnegx, 0xFC000050, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(fnegx, 0xFC000050, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }

View File

@ -24,231 +24,441 @@ namespace codegen {
// Integer load (A-13) // 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lbzu, 0x8C000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(ldx, 0x7C00002A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lbzux, 0x7C0000EE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lha, 0xA8000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lbzx, 0x7C0000AE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lhau, 0xAC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(ld, 0xE8000000, DS )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lhaux, 0x7C0002EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(ldux, 0x7C00006A, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lhax, 0x7C0002AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lha, 0xA8000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lhzux, 0x7C00026E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lhau, 0xAC000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lhzx, 0x7C00022E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lhaux, 0x7C0002EE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lwa, 0xE8000002, DS )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lhax, 0x7C0002AE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lwaux, 0x7C0002EA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lhz, 0xA0000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lwax, 0x7C0002AA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lhzux, 0x7C00026E, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lwzux, 0x7C00006E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lhzx, 0x7C00022E, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lwzx, 0x7C00002E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // if RA = 0 then
return 1; // b <- 0
} // else
// b <- (RA)
// EA <- b + (RB)
// RT <- i32.0 || MEM(EA, 4)
XEEMITTER(lwa, 0xE8000002, DS )(FunctionGenerator& g, InstrData& i) { Value* ea = g.gpr_value(i.X.B);
XEINSTRNOTIMPLEMENTED(); if (i.X.A) {
return 1; 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) { return 0;
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;
} }
// Integer store (A-14) // 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stbu, 0x9C000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stbux, 0x7C0001EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stbux, 0x7C0001EE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stbx, 0x7C0001AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(std, 0xF8000000, DS )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stdx, 0x7C00012A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
//const uint64 b = r(instr.DS.A);
//const uint64 EA = b + EXTS16(instr.DS.ds << 2);
//MEMSET64(EA, instr.DS.S);
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stdx, 0x7C00012A, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stwx, 0x7C00012E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); // if RA = 0 then
return 1; // b <- 0
} // else
// b <- (RA)
// EA <- b + (RB)
// MEM(EA, 4) <- (RS)[32:63]
XEEMITTER(sth, 0xB0000000, D )(FunctionGenerator& g, InstrData& i) { Value* ea = g.gpr_value(i.X.B);
XEINSTRNOTIMPLEMENTED(); if (i.X.A) {
return 1; 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) { return 0;
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;
} }
// Integer load and store with byte reverse (A-1 // 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lwbrx, 0x7C00042C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lwbrx, 0x7C00042C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(ldbrx, 0x7C000428, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(ldbrx, 0x7C000428, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(sthbrx, 0x7C00072C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(sthbrx, 0x7C00072C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stwbrx, 0x7C00052C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stwbrx, 0x7C00052C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stdbrx, 0x7C000528, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stdbrx, 0x7C000528, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -256,12 +466,12 @@ XEEMITTER(stdbrx, 0x7C000528, X )(FunctionGenerator& g, InstrData& i) {
// Integer load and store multiple (A-16) // 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stmw, 0xBC000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stmw, 0xBC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -269,22 +479,22 @@ XEEMITTER(stmw, 0xBC000000, D )(FunctionGenerator& g, InstrData& i) {
// Integer load and store string (A-17) // 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(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lswx, 0x7C00042A, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lswx, 0x7C00042A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stswi, 0x7C0005AA, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stswi, 0x7C0005AA, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stswx, 0x7C00052A, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stswx, 0x7C00052A, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -292,37 +502,37 @@ XEEMITTER(stswx, 0x7C00052A, X )(FunctionGenerator& g, InstrData& i) {
// Memory synchronization (A-18) // Memory synchronization (A-18)
XEEMITTER(eieio, 0x7C0006AC, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(eieio, 0x7C0006AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(isync, 0x4C00012C, XL )(FunctionGenerator& g, InstrData& i) { XEEMITTER(isync, 0x4C00012C, XL )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(ldarx, 0x7C0000A8, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(ldarx, 0x7C0000A8, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lwarx, 0x7C000028, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lwarx, 0x7C000028, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stdcx, 0x7C0001AD, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stdcx, 0x7C0001AD, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stwcx, 0x7C00012D, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stwcx, 0x7C00012D, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(sync, 0x7C0004AC, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(sync, 0x7C0004AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -330,42 +540,42 @@ XEEMITTER(sync, 0x7C0004AC, X )(FunctionGenerator& g, InstrData& i) {
// Floating-point load (A-19) // Floating-point load (A-19)
XEEMITTER(lfd, 0xC8000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lfd, 0xC8000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lfdu, 0xCC000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lfdu, 0xCC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lfdux, 0x7C0004EE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lfdux, 0x7C0004EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lfdx, 0x7C0004AE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lfdx, 0x7C0004AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lfs, 0xC0000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lfs, 0xC0000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lfsu, 0xC4000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lfsu, 0xC4000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lfsux, 0x7C00046E, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lfsux, 0x7C00046E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(lfsx, 0x7C00042E, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(lfsx, 0x7C00042E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -373,47 +583,47 @@ XEEMITTER(lfsx, 0x7C00042E, X )(FunctionGenerator& g, InstrData& i) {
// Floating-point store (A-20) // Floating-point store (A-20)
XEEMITTER(stfd, 0xD8000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stfd, 0xD8000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stfdu, 0xDC000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stfdu, 0xDC000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stfdux, 0x7C0005EE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stfdux, 0x7C0005EE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stfdx, 0x7C0005AE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stfdx, 0x7C0005AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stfiwx, 0x7C0007AE, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stfiwx, 0x7C0007AE, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stfs, 0xD0000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stfs, 0xD0000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stfsu, 0xD4000000, D )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stfsu, 0xD4000000, D )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stfsux, 0x7C00056E, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stfsux, 0x7C00056E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(stfsx, 0x7C00052E, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(stfsx, 0x7C00052E, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -421,33 +631,33 @@ XEEMITTER(stfsx, 0x7C00052E, X )(FunctionGenerator& g, InstrData& i) {
// Cache management (A-27) // Cache management (A-27)
XEEMITTER(dcbf, 0x7C0000AC, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(dcbf, 0x7C0000AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(dcbst, 0x7C00006C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(dcbst, 0x7C00006C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(dcbt, 0x7C00022C, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(dcbt, 0x7C00022C, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(dcbtst, 0x7C0001EC, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(dcbtst, 0x7C0001EC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(dcbz, 0x7C0007EC, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(dcbz, 0x7C0007EC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
// or dcbz128 0x7C2007EC // or dcbz128 0x7C2007EC
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
XEEMITTER(icbi, 0x7C0007AC, X )(FunctionGenerator& g, InstrData& i) { XEEMITTER(icbi, 0x7C0007AC, X )(FunctionGenerator& g, IRBuilder<>& b, InstrData& i) {
XEINSTRNOTIMPLEMENTED(); XEINSTRNOTIMPLEMENTED();
return 1; return 1;
} }
@ -459,6 +669,7 @@ void RegisterEmitCategoryMemory() {
XEREGISTEREMITTER(lbzux, 0x7C0000EE); XEREGISTEREMITTER(lbzux, 0x7C0000EE);
XEREGISTEREMITTER(lbzx, 0x7C0000AE); XEREGISTEREMITTER(lbzx, 0x7C0000AE);
XEREGISTEREMITTER(ld, 0xE8000000); XEREGISTEREMITTER(ld, 0xE8000000);
XEREGISTEREMITTER(ldu, 0xE8000001);
XEREGISTEREMITTER(ldux, 0x7C00006A); XEREGISTEREMITTER(ldux, 0x7C00006A);
XEREGISTEREMITTER(ldx, 0x7C00002A); XEREGISTEREMITTER(ldx, 0x7C00002A);
XEREGISTEREMITTER(lha, 0xA8000000); XEREGISTEREMITTER(lha, 0xA8000000);

View File

@ -9,6 +9,8 @@
#include <xenia/cpu/codegen/function_generator.h> #include <xenia/cpu/codegen/function_generator.h>
#include <xenia/cpu/ppc/state.h>
using namespace llvm; using namespace llvm;
using namespace xe::cpu::codegen; using namespace xe::cpu::codegen;
@ -35,21 +37,28 @@ using namespace xe::cpu::sdb;
*/ */
FunctionGenerator::FunctionGenerator(xe_memory_ref memory, FunctionSymbol* fn, FunctionGenerator::FunctionGenerator(
LLVMContext* context, Module* gen_module, xe_memory_ref memory, SymbolDatabase* sdb, FunctionSymbol* fn,
Function* gen_fn) { LLVMContext* context, Module* gen_module, Function* gen_fn) {
memory_ = memory; memory_ = memory;
sdb_ = sdb;
fn_ = fn; fn_ = fn;
context_ = context; context_ = context;
gen_module_ = gen_module; gen_module_ = gen_module;
gen_fn_ = gen_fn; gen_fn_ = gen_fn;
builder_ = new IRBuilder<>(*context_); builder_ = new IRBuilder<>(*context_);
xe_zero_struct(&values_, sizeof(values_));
} }
FunctionGenerator::~FunctionGenerator() { FunctionGenerator::~FunctionGenerator() {
delete builder_; delete builder_;
} }
SymbolDatabase* FunctionGenerator::sdb() {
return sdb_;
}
FunctionSymbol* FunctionGenerator::fn() { FunctionSymbol* FunctionGenerator::fn() {
return fn_; return fn_;
} }
@ -66,7 +75,21 @@ llvm::Function* FunctionGenerator::gen_fn() {
return gen_fn_; return gen_fn_;
} }
FunctionBlock* FunctionGenerator::fn_block() {
return fn_block_;
}
void FunctionGenerator::GenerateBasicBlocks() { 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. // Pass 1 creates all of the blocks - this way we can branch to them.
for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin(); for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin();
it != fn_->blocks.end(); ++it) { it != fn_->blocks.end(); ++it) {
@ -78,6 +101,11 @@ void FunctionGenerator::GenerateBasicBlocks() {
bbs_.insert(std::pair<uint32_t, BasicBlock*>(block->start_address, bb)); bbs_.insert(std::pair<uint32_t, BasicBlock*>(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<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin(); for (std::map<uint32_t, FunctionBlock*>::iterator it = fn_->blocks.begin();
it != fn_->blocks.end(); ++it) { it != fn_->blocks.end(); ++it) {
FunctionBlock* block = it->second; FunctionBlock* block = it->second;
@ -89,6 +117,9 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block,
BasicBlock* bb) { BasicBlock* bb) {
printf(" bb %.8X-%.8X:\n", block->start_address, block->end_address); printf(" bb %.8X-%.8X:\n", block->start_address, block->end_address);
fn_block_ = block;
bb_ = bb;
// Move the builder to this block and setup. // Move the builder to this block and setup.
builder_->SetInsertPoint(bb); builder_->SetInsertPoint(bb);
//i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname))); //i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
@ -110,11 +141,32 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block,
// builder_>SetCurrentDebugLocation(DebugLoc::get( // builder_>SetCurrentDebugLocation(DebugLoc::get(
// ia >> 8, ia & 0xFF, ctx->cu)); // 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); // If we fall through, create the branch.
builder_->CreateRetVoid(); 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 // TODO(benvanik): finish up BB
} }
@ -127,66 +179,299 @@ BasicBlock* FunctionGenerator::GetBasicBlock(uint32_t address) {
return NULL; return NULL;
} }
Function* FunctionGenerator::GetFunction(uint32_t addr) { BasicBlock* FunctionGenerator::GetNextBasicBlock() {
std::map<uint32_t, BasicBlock*>::iterator it = bbs_.find(
fn_block_->start_address);
++it;
if (it != bbs_.end()) {
return it->second;
}
return NULL; 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() { Value* FunctionGenerator::cia_value() {
return builder_->getInt32(cia_); return builder_->getInt32(cia_);
} }
void FunctionGenerator::FlushRegisters() { 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() { 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) { 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() { 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) { 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() { 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) { 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) { Value* FunctionGenerator::cr_value() {
return NULL; 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) { 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) { 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) { Value* FunctionGenerator::memory_addr(uint32_t addr) {
return NULL; return NULL;
} }
Value* FunctionGenerator::read_memory(Value* addr, uint32_t size, bool extend) { Value* FunctionGenerator::ReadMemory(Value* addr, uint32_t size, bool extend) {
return NULL; 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);
} }

View File

@ -104,6 +104,7 @@ int ModuleGenerator::Generate() {
} }
break; break;
default: default:
XEASSERTALWAYS();
break; break;
} }
} }
@ -139,6 +140,7 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) {
AttributeSet attrs = AttributeSet::get(context, awi); AttributeSet attrs = AttributeSet::get(context, awi);
std::vector<Type*> args; std::vector<Type*> args;
args.push_back(PointerType::getUnqual(Type::getInt8Ty(context)));
Type* return_type = Type::getInt32Ty(context); Type* return_type = Type::getInt32Ty(context);
FunctionType* ft = FunctionType::get(return_type, FunctionType* ft = FunctionType::get(return_type,
@ -148,6 +150,10 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) {
f->setCallingConv(CallingConv::C); f->setCallingConv(CallingConv::C);
f->setVisibility(GlobalValue::DefaultVisibility); 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. // TODO(benvanik): log errors.
BasicBlock* block = BasicBlock::Create(context, "entry", f); BasicBlock* block = BasicBlock::Create(context, "entry", f);
IRBuilder<> builder(block); IRBuilder<> builder(block);
@ -185,23 +191,21 @@ void ModuleGenerator::PrepareFunction(FunctionSymbol* fn) {
AttributeSet attrs = AttributeSet::get(context, awi); AttributeSet attrs = AttributeSet::get(context, awi);
std::vector<Type*> args; std::vector<Type*> args;
args.push_back(PointerType::getUnqual(Type::getInt8Ty(context)));
Type* return_type = Type::getVoidTy(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, FunctionType* ft = FunctionType::get(return_type,
ArrayRef<Type*>(args), false); ArrayRef<Type*>(args), false);
XEASSERTNOTNULL(fn->name);
Function* f = cast<Function>( Function* f = cast<Function>(
m->getOrInsertFunction(StringRef(pname), ft, attrs)); m->getOrInsertFunction(StringRef(fn->name), ft, attrs));
f->setCallingConv(CallingConv::C); f->setCallingConv(CallingConv::C);
f->setVisibility(GlobalValue::DefaultVisibility); 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(); CodegenFunction* cgf = new CodegenFunction();
cgf->symbol = fn; cgf->symbol = fn;
cgf->function_type = ft; cgf->function_type = ft;
@ -216,7 +220,8 @@ void ModuleGenerator::BuildFunction(CodegenFunction* cgf) {
printf("%s:\n", fn->name); printf("%s:\n", fn->name);
// Setup the generation context. // 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. // Run through and generate each basic block.
fgen.GenerateBasicBlocks(); fgen.GenerateBasicBlocks();
@ -229,6 +234,7 @@ void ModuleGenerator::BuildFunction(CodegenFunction* cgf) {
void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) { void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) {
FunctionPassManager pm(m); FunctionPassManager pm(m);
#if XE_OPTION(OPTIMIZED)
PassManagerBuilder pmb; PassManagerBuilder pmb;
pmb.OptLevel = 3; pmb.OptLevel = 3;
pmb.SizeLevel = 0; pmb.SizeLevel = 0;
@ -236,6 +242,7 @@ void ModuleGenerator::OptimizeFunction(Module* m, Function* fn) {
pmb.Vectorize = true; pmb.Vectorize = true;
pmb.LoopVectorize = true; pmb.LoopVectorize = true;
pmb.populateFunctionPassManager(pm); pmb.populateFunctionPassManager(pm);
#endif // XE_OPTION(OPTIMIZED)
pm.add(createVerifierPass()); pm.add(createVerifierPass());
pm.run(*fn); pm.run(*fn);
} }

View File

@ -126,6 +126,8 @@ int ExecModule::Prepare() {
context_.get(), gen_module_.get())); context_.get(), gen_module_.get()));
XEEXPECTZERO(codegen_->Generate()); XEEXPECTZERO(codegen_->Generate());
gen_module_->dump();
// Write to cache. // Write to cache.
outs = auto_ptr<raw_ostream>(new raw_fd_ostream( outs = auto_ptr<raw_ostream>(new raw_fd_ostream(
cache_path, error_message, raw_fd_ostream::F_Binary)); cache_path, error_message, raw_fd_ostream::F_Binary));
@ -141,6 +143,7 @@ int ExecModule::Prepare() {
// Run full module optimizations. // Run full module optimizations.
pm.add(new DataLayout(gen_module_.get())); pm.add(new DataLayout(gen_module_.get()));
#if XE_OPTION(OPTIMIZED)
pm.add(createVerifierPass()); pm.add(createVerifierPass());
pmb.OptLevel = 3; pmb.OptLevel = 3;
pmb.SizeLevel = 0; pmb.SizeLevel = 0;
@ -149,6 +152,7 @@ int ExecModule::Prepare() {
pmb.LoopVectorize = true; pmb.LoopVectorize = true;
pmb.populateModulePassManager(pm); pmb.populateModulePassManager(pm);
pmb.populateLTOPassManager(pm, false, true); pmb.populateLTOPassManager(pm, false, true);
#endif // XE_OPTION(OPTIMIZED)
pm.add(createVerifierPass()); pm.add(createVerifierPass());
pm.run(*gen_module_); pm.run(*gen_module_);
@ -158,9 +162,9 @@ int ExecModule::Prepare() {
XEEXPECTZERO(Init()); XEEXPECTZERO(Init());
// Force JIT of all functions. // Force JIT of all functions.
for (Module::iterator I = gen_module_->begin(), E = gen_module_->end(); for (Module::iterator it = gen_module_->begin(); it != gen_module_->end();
I != E; I++) { ++it) {
Function* fn = &*I; Function* fn = it;
if (!fn->isDeclaration()) { if (!fn->isDeclaration()) {
engine_->getPointerToFunction(fn); engine_->getPointerToFunction(fn);
} }
@ -174,7 +178,7 @@ XECLEANUP:
int ExecModule::InjectGlobals() { int ExecModule::InjectGlobals() {
LLVMContext& context = *context_.get(); LLVMContext& context = *context_.get();
const DataLayout* dl = engine_->getDataLayout(); const DataLayout* dl = engine_->getDataLayout();
Type* voidPtrTy = PointerType::getUnqual(Type::getVoidTy(context)); Type* int8PtrTy = PointerType::getUnqual(Type::getInt8Ty(context));
Type* intPtrTy = dl->getIntPtrType(context); Type* intPtrTy = dl->getIntPtrType(context);
GlobalVariable* gv; GlobalVariable* gv;
@ -182,7 +186,7 @@ int ExecModule::InjectGlobals() {
// This is the base void* pointer to the memory space. // This is the base void* pointer to the memory space.
gv = new GlobalVariable( gv = new GlobalVariable(
*gen_module_, *gen_module_,
voidPtrTy, int8PtrTy,
true, true,
GlobalValue::ExternalLinkage, GlobalValue::ExternalLinkage,
0, 0,
@ -191,10 +195,7 @@ int ExecModule::InjectGlobals() {
gv->setAlignment(64); gv->setAlignment(64);
gv->setInitializer(ConstantExpr::getIntToPtr( gv->setInitializer(ConstantExpr::getIntToPtr(
ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)), ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)),
voidPtrTy)); int8PtrTy));
// xe_ppc_state
// ...
return 0; return 0;
} }
@ -224,6 +225,6 @@ int ExecModule::Uninit() {
} }
void ExecModule::Dump() { void ExecModule::Dump() {
sdb_->Dump(); // sdb_->Dump();
gen_module_->dump(); // gen_module_->dump();
} }

View File

@ -97,7 +97,7 @@ int Processor::PrepareModule(UserModule* user_module,
modules_.push_back(exec_module); modules_.push_back(exec_module);
user_module->Dump(export_resolver.get()); //user_module->Dump(export_resolver.get());
exec_module->Dump(); exec_module->Dump();
return 0; return 0;

View File

@ -149,6 +149,16 @@ int SymbolDatabase::Analyze() {
FlushQueue(); 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<FunctionSymbol*>(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. // 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. // This can only be performed after we have all functions and basic blocks.
for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) { 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); printf(" call %.8X %s\n", block->outgoing_function->start_address, block->outgoing_function->name);
break; break;
case FunctionBlock::kTargetLR: case FunctionBlock::kTargetLR:
printf(" return\n"); printf(" branch lr\n");
break;
case FunctionBlock::kTargetCTR:
printf(" branch ctr\n");
break; break;
case FunctionBlock::kTargetNone: case FunctionBlock::kTargetNone:
printf("\n"); printf("\n");
@ -520,6 +533,11 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
fn->name = xestrdup(name); 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; InstrData i;
FunctionBlock* block = NULL; FunctionBlock* block = NULL;
uint32_t furthest_target = fn->start_address; uint32_t furthest_target = fn->start_address;
@ -615,6 +633,7 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
ends_block = true; ends_block = true;
} else if (i.type->opcode == 0x4C000020) { } else if (i.type->opcode == 0x4C000020) {
// bclr/bclrl // bclr/bclrl
block->outgoing_type = FunctionBlock::kTargetLR;
if (i.XL.LK) { if (i.XL.LK) {
XELOGSDB("bclrl %.8X\n", addr); XELOGSDB("bclrl %.8X\n", addr);
} else { } else {
@ -623,6 +642,7 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
ends_block = true; ends_block = true;
} else if (i.type->opcode == 0x4C000420) { } else if (i.type->opcode == 0x4C000420) {
// bcctr/bcctrl // bcctr/bcctrl
block->outgoing_type = FunctionBlock::kTargetCTR;
if (i.XL.LK) { if (i.XL.LK) {
XELOGSDB("bcctrl %.8X\n", addr); XELOGSDB("bcctrl %.8X\n", addr);
} else { } else {

View File

@ -21,13 +21,12 @@
// NOTE: only headers in this directory should be included. // NOTE: only headers in this directory should be included.
#include "xethunk.h" #include "xethunk.h"
#include <xenia/cpu/ppc/state.h>
// Global CPU state. // Global memory base.
// Instructions that dereference the state use this. // Dereference + PPC address to manipulate memory. Note that it's stored in
// TODO(benvanik): noalias/invariant/etc?s // big-endian!
static xe_ppc_state_t* xe_ppc_state; extern char* xe_memory_base;
int xe_module_init() { int xe_module_init() {

View File

@ -13,8 +13,8 @@
* include any other files. * include any other files.
*/ */
#ifndef XENIA_CPU_XELIB_H_ #ifndef XENIA_CPU_XETHUNK_H_
#define XENIA_CPU_XELIB_H_ #define XENIA_CPU_XETHUNK_H_
#endif // XENIA_CPU_XELIB_H_ #endif // XENIA_CPU_XETHUNK_H_

View File

@ -240,7 +240,7 @@ class SetupCommand(Command):
'-G"%s"' % (generator), '-G"%s"' % (generator),
'-DCMAKE_INSTALL_PREFIX:STRING=../../../%s' % (path), '-DCMAKE_INSTALL_PREFIX:STRING=../../../%s' % (path),
'-DCMAKE_BUILD_TYPE:STRING=%s' % (mode), '-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_EXAMPLES:BOOL=OFF',
'-DLLVM_INCLUDE_TESTS:BOOL=OFF', '-DLLVM_INCLUDE_TESTS:BOOL=OFF',
'../../../third_party/llvm/', '../../../third_party/llvm/',
@ -394,7 +394,7 @@ class XethunkCommand(Command):
print '' print ''
path = 'src/cpu/xethunk/xethunk' 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) throw_on_error=False)
if result != 0: if result != 0:
return result return result