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