Misc accumulated Jit64IL work; I don't recall whether any of these

changes individually led to perf improvements, although overall it's 
spending a lot less time in interpreter fallbacks.



git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1904 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
magumagu9 2009-01-17 22:22:54 +00:00
parent 9cb25d6ba2
commit ee2bf31e56
9 changed files with 184 additions and 83 deletions

View File

@ -38,7 +38,7 @@
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// Include // Include
// ¯¯¯¯¯¯¯¯¯¯ // ¯¯¯¯¯¯¯¯¯¯
#ifdef JITTEST #if JITTEST
#include "../Jit64IL/Jit.h" #include "../Jit64IL/Jit.h"
#else #else

View File

@ -1197,11 +1197,9 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
case RFIExit: case RFIExit:
case InterpreterBranch: case InterpreterBranch:
case IdleLoop: case IdleLoop:
// No liveness effects case ShortIdleLoop:
break;
case Tramp: case Tramp:
if (thisUsed) // No liveness effects
regMarkUse(RI, I, I - 1 - (*I >> 8), 1);
break; break;
case SExt8: case SExt8:
case SExt16: case SExt16:
@ -1232,6 +1230,7 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
break; break;
case StoreCR: case StoreCR:
case StoreCarry: case StoreCarry:
case StoreFPRF:
regMarkUse(RI, I, getOp1(I), 1); regMarkUse(RI, I, getOp1(I), 1);
break; break;
case StoreGReg: case StoreGReg:
@ -1277,6 +1276,7 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
case FPMerge01: case FPMerge01:
case FPMerge10: case FPMerge10:
case FPMerge11: case FPMerge11:
case FDCmpCR:
case InsertDoubleInMReg: case InsertDoubleInMReg:
if (thisUsed) { if (thisUsed) {
regMarkUse(RI, I, getOp1(I), 1); regMarkUse(RI, I, getOp1(I), 1);
@ -1411,6 +1411,15 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
regNormalRegClear(RI, I); regNormalRegClear(RI, I);
break; break;
} }
case StoreFPRF: {
Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I)));
Jit->AND(32, R(ECX), Imm8(0x1F));
Jit->SHL(32, R(ECX), Imm8(12));
Jit->AND(32, M(&FPSCR), Imm32(~(0x1F << 12)));
Jit->OR(32, M(&FPSCR), R(ECX));
regNormalRegClear(RI, I);
break;
}
case Load8: { case Load8: {
regEmitMemLoad(RI, I, 8); regEmitMemLoad(RI, I, 8);
break; break;
@ -1851,6 +1860,35 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
fregEmitBinInst(RI, I, &Jit64::SUBSD); fregEmitBinInst(RI, I, &Jit64::SUBSD);
break; break;
} }
case FDCmpCR: {
X64Reg destreg = regFindFreeReg(RI);
// TODO: Add case for NaN (CC_P)
Jit->MOVSD(XMM0, fregLocForInst(RI, getOp1(I)));
Jit->UCOMISD(XMM0, fregLocForInst(RI, getOp2(I)));
FixupBranch pNan = Jit->J_CC(CC_P);
FixupBranch pEqual = Jit->J_CC(CC_Z);
FixupBranch pLesser = Jit->J_CC(CC_C);
// Greater
Jit->MOV(32, R(destreg), Imm32(0x4));
FixupBranch continue1 = Jit->J();
// NaN
Jit->SetJumpTarget(pNan);
Jit->MOV(32, R(destreg), Imm32(0x1));
FixupBranch continue2 = Jit->J();
// Equal
Jit->SetJumpTarget(pEqual);
Jit->MOV(32, R(destreg), Imm32(0x2));
FixupBranch continue3 = Jit->J();
// Less
Jit->SetJumpTarget(pLesser);
Jit->MOV(32, R(destreg), Imm32(0x8));
Jit->SetJumpTarget(continue1);
Jit->SetJumpTarget(continue2);
Jit->SetJumpTarget(continue3);
RI.regs[destreg] = I;
fregNormalRegClear(RI, I);
break;
}
case FPAdd: { case FPAdd: {
if (!thisUsed) break; if (!thisUsed) break;
fregEmitBinInst(RI, I, &Jit64::ADDPS); fregEmitBinInst(RI, I, &Jit64::ADDPS);
@ -1962,7 +2000,14 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
unsigned IdleParam = ibuild->GetImmValue(getOp1(I)); unsigned IdleParam = ibuild->GetImmValue(getOp1(I));
unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); unsigned InstLoc = ibuild->GetImmValue(getOp2(I));
Jit->ABI_CallFunctionC((void *)&PowerPC::OnIdle, IdleParam); Jit->ABI_CallFunctionC((void *)&PowerPC::OnIdle, IdleParam);
Jit->MOV(32, M(&PowerPC::ppcState.pc), Imm32(InstLoc + 12)); Jit->MOV(32, M(&PC), Imm32(InstLoc + 12));
Jit->JMP(asm_routines.testExceptions, true);
break;
}
case ShortIdleLoop: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
Jit->ABI_CallFunction((void *)&CoreTiming::Idle);
Jit->MOV(32, M(&PC), Imm32(InstLoc));
Jit->JMP(asm_routines.testExceptions, true); Jit->JMP(asm_routines.testExceptions, true);
break; break;
} }
@ -1998,25 +2043,7 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
Jit->WriteRfiExitDestInEAX(); Jit->WriteRfiExitDestInEAX();
break; break;
} }
case Tramp: { case Tramp: break;
if (!thisUsed) break;
// FIXME: Optimize!
InstLoc Op = I - 1 - (*I >> 8);
if (isFResult(*Op)) {
X64Reg reg = fregFindFreeReg(RI);
Jit->MOVAPD(reg, fregLocForInst(RI, Op));
RI.fregs[reg] = I;
if (RI.IInfo[I - RI.FirstI] & 4)
fregClearInst(RI, Op);
} else {
X64Reg reg = regFindFreeReg(RI);
Jit->MOV(32, R(reg), regLocForInst(RI, Op));
RI.regs[reg] = I;
if (RI.IInfo[I - RI.FirstI] & 4)
regClearInst(RI, Op);
}
break;
}
case Nop: break; case Nop: break;
default: default:
PanicAlert("Unknown JIT instruction; aborting!"); PanicAlert("Unknown JIT instruction; aborting!");
@ -2034,7 +2061,7 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
} }
} }
if (UseProfile && RI.numSpills) if (!RI.MakeProfile && RI.numSpills)
printf("Block: %x, numspills %d\n", Jit->js.blockStart, RI.numSpills); printf("Block: %x, numspills %d\n", Jit->js.blockStart, RI.numSpills);
Jit->UD2(); Jit->UD2();

View File

@ -54,6 +54,7 @@ namespace IREmitter {
StoreCarry, StoreCarry,
StoreCTR, StoreCTR,
StoreMSR, StoreMSR,
StoreFPRF,
// Arbitrary interpreter instruction // Arbitrary interpreter instruction
InterpreterFallback, InterpreterFallback,
@ -184,6 +185,7 @@ namespace IREmitter {
StoreSingle, StoreSingle,
StoreDouble, StoreDouble,
StoreFReg, StoreFReg,
FDCmpCR,
// "Trinary" operators // "Trinary" operators
// FIXME: Need to change representation! // FIXME: Need to change representation!
@ -197,7 +199,9 @@ namespace IREmitter {
SystemCall, SystemCall,
RFIExit, RFIExit,
InterpreterBranch, InterpreterBranch,
IdleLoop, IdleLoop, // The "usual" idle loop, load+compare+branch
ShortIdleLoop, // Idle loop seen in homebrew like wii mahjong,
// just a branch
// "Opcode" representing a register too far away to // "Opcode" representing a register too far away to
// reference directly; this is a size optimization // reference directly; this is a size optimization
@ -227,11 +231,19 @@ namespace IREmitter {
} }
InstLoc inline getOp1(InstLoc i) { InstLoc inline getOp1(InstLoc i) {
return i - 1 - ((*i >> 8) & 255); i = i - 1 - ((*i >> 8) & 255);
if (getOpcode(*i) == Tramp) {
i = i - 1 - (*i >> 8);
}
return i;
} }
InstLoc inline getOp2(InstLoc i) { InstLoc inline getOp2(InstLoc i) {
return i - 1 - ((*i >> 16) & 255); i = i - 1 - ((*i >> 16) & 255);
if (getOpcode(*i) == Tramp) {
i = i - 1 - (*i >> 8);
}
return i;
} }
class IRBuilder { class IRBuilder {
@ -288,6 +300,9 @@ namespace IREmitter {
InstLoc EmitStoreMSR(InstLoc val) { InstLoc EmitStoreMSR(InstLoc val) {
return FoldUOp(StoreMSR, val); return FoldUOp(StoreMSR, val);
} }
InstLoc EmitStoreFPRF(InstLoc value) {
return FoldUOp(StoreFPRF, value);
}
InstLoc EmitLoadGReg(unsigned reg) { InstLoc EmitLoadGReg(unsigned reg) {
return FoldZeroOp(LoadGReg, reg); return FoldZeroOp(LoadGReg, reg);
} }
@ -390,6 +405,9 @@ namespace IREmitter {
InstLoc EmitInterpreterBranch() { InstLoc EmitInterpreterBranch() {
return FoldZeroOp(InterpreterBranch, 0); return FoldZeroOp(InterpreterBranch, 0);
} }
InstLoc EmitLoadCarry() {
return FoldZeroOp(LoadCarry, 0);
}
InstLoc EmitStoreCarry(InstLoc op1) { InstLoc EmitStoreCarry(InstLoc op1) {
return FoldUOp(StoreCarry, op1); return FoldUOp(StoreCarry, op1);
} }
@ -402,6 +420,9 @@ namespace IREmitter {
InstLoc EmitIdleLoop(InstLoc idleParam, InstLoc pc) { InstLoc EmitIdleLoop(InstLoc idleParam, InstLoc pc) {
return FoldBiOp(IdleLoop, idleParam, pc); return FoldBiOp(IdleLoop, idleParam, pc);
} }
InstLoc EmitShortIdleLoop(InstLoc pc) {
return FoldUOp(ShortIdleLoop, pc);
}
InstLoc EmitLoadSingle(InstLoc addr) { InstLoc EmitLoadSingle(InstLoc addr) {
return FoldUOp(LoadSingle, addr); return FoldUOp(LoadSingle, addr);
} }
@ -498,6 +519,9 @@ namespace IREmitter {
InstLoc EmitDoubleToSingle(InstLoc op1) { InstLoc EmitDoubleToSingle(InstLoc op1) {
return FoldUOp(DoubleToSingle, op1); return FoldUOp(DoubleToSingle, op1);
} }
InstLoc EmitFDCmpCR(InstLoc op1, InstLoc op2) {
return FoldBiOp(FDCmpCR, op1, op2);
}
void StartBackPass() { curReadPtr = &InstList[InstList.size()]; } void StartBackPass() { curReadPtr = &InstList[InstList.size()]; }
void StartForwardPass() { curReadPtr = &InstList[0]; } void StartForwardPass() { curReadPtr = &InstList[0]; }

View File

@ -280,12 +280,9 @@ public:
void subfx(UGeckoInstruction inst); void subfx(UGeckoInstruction inst);
void subfex(UGeckoInstruction inst); void subfex(UGeckoInstruction inst);
void lbzx(UGeckoInstruction inst); void lXzx(UGeckoInstruction inst);
void lwzx(UGeckoInstruction inst);
void lhax(UGeckoInstruction inst); void lhax(UGeckoInstruction inst);
void lwzux(UGeckoInstruction inst);
void stXx(UGeckoInstruction inst); void stXx(UGeckoInstruction inst);
void lmw(UGeckoInstruction inst); void lmw(UGeckoInstruction inst);

View File

@ -68,6 +68,11 @@ using namespace Gen;
else else
destination = js.compilerPC + SignExt26(inst.LI << 2); destination = js.compilerPC + SignExt26(inst.LI << 2);
if (destination == js.compilerPC) {
ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC));
return;
}
ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination)); ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination));
} }
@ -109,7 +114,8 @@ using namespace Gen;
} }
if (!Test) { if (!Test) {
PanicAlert("Unconditional conditional branch?!"); Test = ibuild.EmitIntConst(1);
//PanicAlert("Unconditional conditional branch?!");
} }
u32 destination; u32 destination;

View File

@ -28,7 +28,7 @@
void Jit64::fp_arith_s(UGeckoInstruction inst) void Jit64::fp_arith_s(UGeckoInstruction inst)
{ {
if (inst.Rc || inst.OPCD != 59 || (inst.SUBOP5 != 25 && inst.SUBOP5 != 20 && inst.SUBOP5 != 21)) { if (inst.Rc || (inst.SUBOP5 != 25 && inst.SUBOP5 != 20 && inst.SUBOP5 != 21)) {
Default(inst); return; Default(inst); return;
} }
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
@ -61,22 +61,24 @@
void Jit64::fmaddXX(UGeckoInstruction inst) void Jit64::fmaddXX(UGeckoInstruction inst)
{ {
if (inst.Rc || inst.OPCD != 59) { if (inst.Rc) {
Default(inst); return; Default(inst); return;
} }
bool single_precision = inst.OPCD == 59;
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
val = ibuild.EmitDoubleToSingle(val); val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFSMul(val, ibuild.EmitDoubleToSingle(ibuild.EmitLoadFReg(inst.FC)));
if (inst.SUBOP5 & 1) if (inst.SUBOP5 & 1)
val = ibuild.EmitFSAdd(val, ibuild.EmitDoubleToSingle(ibuild.EmitLoadFReg(inst.FB))); val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
else else
val = ibuild.EmitFSSub(val, ibuild.EmitDoubleToSingle(ibuild.EmitLoadFReg(inst.FB))); val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
if (inst.SUBOP5 & 2) if (inst.SUBOP5 & 2)
val = ibuild.EmitFSNeg(val); val = ibuild.EmitFDNeg(val);
if (inst.OPCD == 59) {
val = ibuild.EmitDoubleToSingle(val);
val = ibuild.EmitDupSingleToMReg(val); val = ibuild.EmitDupSingleToMReg(val);
} else {
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
}
ibuild.EmitStoreFReg(val, inst.FD); ibuild.EmitStoreFReg(val, inst.FD);
} }
@ -92,6 +94,11 @@
void Jit64::fcmpx(UGeckoInstruction inst) void Jit64::fcmpx(UGeckoInstruction inst)
{ {
Default(inst); printf("fcmpx at %x\n", js.compilerPC);
return; IREmitter::InstLoc lhs, rhs, res;
lhs = ibuild.EmitLoadFReg(inst.FA);
rhs = ibuild.EmitLoadFReg(inst.FB);
res = ibuild.EmitFDCmpCR(lhs, rhs);
ibuild.EmitStoreFPRF(res);
ibuild.EmitStoreCR(res, inst.CRFD);
} }

View File

@ -211,19 +211,21 @@
void Jit64::subfex(UGeckoInstruction inst) void Jit64::subfex(UGeckoInstruction inst)
{ {
INSTRUCTION_START; if (inst.OE) PanicAlert("OE: subfex");
Default(inst); IREmitter::InstLoc val, test, lhs, rhs, carry;
return; rhs = ibuild.EmitLoadGReg(inst.RA);
/* carry = ibuild.EmitLoadCarry();
u32 a = m_GPR[_inst.RA]; rhs = ibuild.EmitXor(rhs, ibuild.EmitIntConst(-1));
u32 b = m_GPR[_inst.RB]; rhs = ibuild.EmitAdd(rhs, carry);
int carry = GetCarry(); test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
m_GPR[_inst.RD] = (~a) + b + carry; test = ibuild.EmitAnd(test, carry);
SetCarry(Helper_Carry(~a, b) || Helper_Carry((~a) + b, carry)); lhs = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitAdd(lhs, rhs);
if (_inst.OE) PanicAlert("OE: subfcx"); ibuild.EmitStoreGReg(val, inst.RD);
if (_inst.Rc) Helper_UpdateCR0(m_GPR[_inst.RD]); test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
*/ ibuild.EmitStoreCarry(test);
if (inst.Rc)
ComputeRC(ibuild, val);
} }
void Jit64::subfx(UGeckoInstruction inst) void Jit64::subfx(UGeckoInstruction inst)

View File

@ -39,24 +39,6 @@
//#define INSTRUCTION_START Default(inst); return; //#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START #define INSTRUCTION_START
void Jit64::lbzx(UGeckoInstruction inst)
{
INSTRUCTION_START
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
if (inst.RA)
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
ibuild.EmitStoreGReg(ibuild.EmitLoad8(addr), inst.RD);
}
void Jit64::lwzx(UGeckoInstruction inst)
{
INSTRUCTION_START
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
if (inst.RA)
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
ibuild.EmitStoreGReg(ibuild.EmitLoad32(addr), inst.RD);
}
void Jit64::lhax(UGeckoInstruction inst) void Jit64::lhax(UGeckoInstruction inst)
{ {
INSTRUCTION_START INSTRUCTION_START
@ -113,15 +95,24 @@ void Jit64::lha(UGeckoInstruction inst)
ibuild.EmitStoreGReg(val, inst.RD); ibuild.EmitStoreGReg(val, inst.RD);
} }
void Jit64::lwzux(UGeckoInstruction inst) void Jit64::lXzx(UGeckoInstruction inst)
{ {
INSTRUCTION_START INSTRUCTION_START
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
if (inst.RA) { if (inst.RA) {
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
if (inst.SUBOP10 & 32)
ibuild.EmitStoreGReg(addr, inst.RA); ibuild.EmitStoreGReg(addr, inst.RA);
} }
ibuild.EmitStoreGReg(ibuild.EmitLoad32(addr), inst.RD); IREmitter::InstLoc val;
switch (inst.SUBOP10 & ~32)
{
default: PanicAlert("lXzx: invalid access size");
case 23: val = ibuild.EmitLoad32(addr); break; //lwzx
case 279: val = ibuild.EmitLoad16(addr); break; //lhzx
case 87: val = ibuild.EmitLoad8(addr); break; //lbzx
}
ibuild.EmitStoreGReg(val, inst.RD);
} }
// Zero cache line. // Zero cache line.
@ -183,10 +174,28 @@ void Jit64::stXx(UGeckoInstruction inst)
// A few games use these heavily in video codecs. // A few games use these heavily in video codecs.
void Jit64::lmw(UGeckoInstruction inst) void Jit64::lmw(UGeckoInstruction inst)
{ {
Default(inst); return; INSTRUCTION_START
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
if (inst.RA)
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
for (int i = inst.RD; i < 32; i++)
{
IREmitter::InstLoc val = ibuild.EmitLoad32(addr);
ibuild.EmitStoreGReg(val, i);
addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4));
}
} }
void Jit64::stmw(UGeckoInstruction inst) void Jit64::stmw(UGeckoInstruction inst)
{ {
Default(inst); return; INSTRUCTION_START
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
if (inst.RA)
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
for (int i = inst.RD; i < 32; i++)
{
IREmitter::InstLoc val = ibuild.EmitLoadGReg(i);
ibuild.EmitStore32(val, addr);
addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4));
}
} }

View File

@ -167,12 +167,21 @@ static GekkoOPTemplate primarytable[] =
{28, Interpreter::andi_rc, &Jit64::reg_imm, {"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, {28, Interpreter::andi_rc, &Jit64::reg_imm, {"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}},
{29, Interpreter::andis_rc, &Jit64::reg_imm, {"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, {29, Interpreter::andis_rc, &Jit64::reg_imm, {"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}},
#if JITTEST
{32, Interpreter::lwz, &Jit64::lXz, {"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{33, Interpreter::lwzu, &Jit64::lXz, {"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
{34, Interpreter::lbz, &Jit64::lXz, {"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{35, Interpreter::lbzu, &Jit64::lXz, {"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
{40, Interpreter::lhz, &Jit64::lXz, {"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{41, Interpreter::lhzu, &Jit64::lXz, {"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
#else
{32, Interpreter::lwz, &Jit64::lXz, {"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, {32, Interpreter::lwz, &Jit64::lXz, {"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{33, Interpreter::lwzu, &Jit64::Default, {"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, {33, Interpreter::lwzu, &Jit64::Default, {"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
{34, Interpreter::lbz, &Jit64::lXz, {"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, {34, Interpreter::lbz, &Jit64::lXz, {"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{35, Interpreter::lbzu, &Jit64::Default, {"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, {35, Interpreter::lbzu, &Jit64::Default, {"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
{40, Interpreter::lhz, &Jit64::lXz, {"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, {40, Interpreter::lhz, &Jit64::lXz, {"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{41, Interpreter::lhzu, &Jit64::Default, {"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, {41, Interpreter::lhzu, &Jit64::Default, {"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
#endif
{42, Interpreter::lha, &Jit64::lha, {"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, {42, Interpreter::lha, &Jit64::lha, {"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{43, Interpreter::lhau, &Jit64::Default, {"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, {43, Interpreter::lhau, &Jit64::Default, {"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
@ -302,13 +311,33 @@ static GekkoOPTemplate table31[] =
{24, Interpreter::slwx, &Jit64::slwx, {"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {24, Interpreter::slwx, &Jit64::slwx, {"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}},
{54, Interpreter::dcbst, &Jit64::Default, {"dcbst", OPTYPE_DCACHE, 0, 4}}, {54, Interpreter::dcbst, &Jit64::Default, {"dcbst", OPTYPE_DCACHE, 0, 4}},
#if JITTEST
{86, Interpreter::dcbf, &Jit64::DoNothing, {"dcbf", OPTYPE_DCACHE, 0, 4}},
#else
{86, Interpreter::dcbf, &Jit64::Default, {"dcbf", OPTYPE_DCACHE, 0, 4}}, {86, Interpreter::dcbf, &Jit64::Default, {"dcbf", OPTYPE_DCACHE, 0, 4}},
#endif
{246, Interpreter::dcbtst, &Jit64::Default, {"dcbtst", OPTYPE_DCACHE, 0, 1}}, {246, Interpreter::dcbtst, &Jit64::Default, {"dcbtst", OPTYPE_DCACHE, 0, 1}},
{278, Interpreter::dcbt, &Jit64::Default, {"dcbt", OPTYPE_DCACHE, 0, 1}}, {278, Interpreter::dcbt, &Jit64::Default, {"dcbt", OPTYPE_DCACHE, 0, 1}},
{470, Interpreter::dcbi, &Jit64::Default, {"dcbi", OPTYPE_DCACHE, 0, 4}}, {470, Interpreter::dcbi, &Jit64::Default, {"dcbi", OPTYPE_DCACHE, 0, 4}},
{758, Interpreter::dcba, &Jit64::Default, {"dcba", OPTYPE_DCACHE, 0, 4}}, {758, Interpreter::dcba, &Jit64::Default, {"dcba", OPTYPE_DCACHE, 0, 4}},
{1014, Interpreter::dcbz, &Jit64::dcbz, {"dcbz", OPTYPE_DCACHE, 0, 4}}, {1014, Interpreter::dcbz, &Jit64::dcbz, {"dcbz", OPTYPE_DCACHE, 0, 4}},
#if JITTEST
//load word
{23, Interpreter::lwzx, &Jit64::lXzx, {"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{55, Interpreter::lwzux, &Jit64::lXzx, {"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
//load halfword
{279, Interpreter::lhzx, &Jit64::lXzx, {"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{311, Interpreter::lhzux, &Jit64::lXzx, {"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
//load halfword signextend
{343, Interpreter::lhax, &Jit64::lhax, {"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{375, Interpreter::lhaux, &Jit64::Default, {"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
//load byte
{87, Interpreter::lbzx, &Jit64::lXzx, {"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{119, Interpreter::lbzux, &Jit64::lXzx, {"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
#else
//load word //load word
{23, Interpreter::lwzx, &Jit64::lwzx, {"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, {23, Interpreter::lwzx, &Jit64::lwzx, {"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{55, Interpreter::lwzux, &Jit64::lwzux, {"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, {55, Interpreter::lwzux, &Jit64::lwzux, {"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
@ -324,7 +353,7 @@ static GekkoOPTemplate table31[] =
//load byte //load byte
{87, Interpreter::lbzx, &Jit64::lbzx, {"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, {87, Interpreter::lbzx, &Jit64::lbzx, {"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{119, Interpreter::lbzux, &Jit64::Default, {"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, {119, Interpreter::lbzux, &Jit64::Default, {"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
#endif
//load byte reverse //load byte reverse
{534, Interpreter::lwbrx, &Jit64::Default, {"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, {534, Interpreter::lwbrx, &Jit64::Default, {"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{790, Interpreter::lhbrx, &Jit64::Default, {"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, {790, Interpreter::lhbrx, &Jit64::Default, {"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},