JITIL: Disable all load/store instructions in 64-bit mode. This actually makes a lot of games work - but slowly. Investigation needed. Reindent a bunch of code.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3405 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2009-06-10 19:43:47 +00:00
parent 46f8178ab1
commit 759263351a
10 changed files with 1664 additions and 1639 deletions

File diff suppressed because it is too large Load Diff

View File

@ -170,314 +170,314 @@ namespace CPUCompare
extern u32 m_BlockStart;
}
void Jit(u32 em_address)
{
jit.Jit(em_address);
}
void Jit(u32 em_address)
{
jit.Jit(em_address);
}
void Jit64::Init()
{
asm_routines.compareEnabled = ::Core::g_CoreStartupParameter.bRunCompareClient;
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
CODE_SIZE = 1024*1024*8*8;
void Jit64::Init()
{
asm_routines.compareEnabled = ::Core::g_CoreStartupParameter.bRunCompareClient;
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
CODE_SIZE = 1024*1024*8*8;
jo.optimizeStack = true;
jo.enableBlocklink = true; // Speed boost, but not 100% safe
jo.optimizeStack = true;
jo.enableBlocklink = true; // Speed boost, but not 100% safe
#ifdef _M_X64
#ifdef JITTEST
jo.enableFastMem = false;
jo.enableFastMem = false;
#else
jo.enableFastMem = Core::GetStartupParameter().bUseFastMem;
jo.enableFastMem = Core::GetStartupParameter().bUseFastMem;
#endif
#else
jo.enableFastMem = false;
jo.enableFastMem = false;
#endif
jo.assumeFPLoadFromMem = true;
jo.fpAccurateFlags = true;
jo.optimizeGatherPipe = true;
jo.fastInterrupts = false;
jo.accurateSinglePrecision = false;
jo.assumeFPLoadFromMem = true;
jo.fpAccurateFlags = true;
jo.optimizeGatherPipe = true;
jo.fastInterrupts = false;
jo.accurateSinglePrecision = false;
gpr.SetEmitter(this);
fpr.SetEmitter(this);
gpr.SetEmitter(this);
fpr.SetEmitter(this);
trampolines.Init();
AllocCodeSpace(CODE_SIZE);
trampolines.Init();
AllocCodeSpace(CODE_SIZE);
blocks.Init();
asm_routines.Init();
}
blocks.Init();
asm_routines.Init();
}
void Jit64::ClearCache()
void Jit64::ClearCache()
{
blocks.Clear();
trampolines.ClearCodeSpace();
ClearCodeSpace();
}
void Jit64::Shutdown()
{
FreeCodeSpace();
blocks.Shutdown();
trampolines.Shutdown();
asm_routines.Shutdown();
}
void Jit64::WriteCallInterpreter(UGeckoInstruction inst)
{
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
if (js.isLastInstruction)
{
blocks.Clear();
trampolines.ClearCodeSpace();
ClearCodeSpace();
MOV(32, M(&PC), Imm32(js.compilerPC));
MOV(32, M(&NPC), Imm32(js.compilerPC + 4));
}
void Jit64::Shutdown()
Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst);
ABI_CallFunctionC((void*)instr, inst.hex);
if (js.isLastInstruction)
{
FreeCodeSpace();
blocks.Shutdown();
trampolines.Shutdown();
asm_routines.Shutdown();
}
void Jit64::WriteCallInterpreter(UGeckoInstruction inst)
{
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
if (js.isLastInstruction)
{
MOV(32, M(&PC), Imm32(js.compilerPC));
MOV(32, M(&NPC), Imm32(js.compilerPC + 4));
}
Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst);
ABI_CallFunctionC((void*)instr, inst.hex);
if (js.isLastInstruction)
{
MOV(32, R(EAX), M(&NPC));
WriteRfiExitDestInEAX();
}
}
void Jit64::unknown_instruction(UGeckoInstruction inst)
{
// CCPU::Break();
PanicAlert("unknown_instruction %08x - Fix me ;)", inst.hex);
}
void Jit64::Default(UGeckoInstruction _inst)
{
ibuild.EmitInterpreterFallback(
ibuild.EmitIntConst(_inst.hex),
ibuild.EmitIntConst(js.compilerPC));
}
void Jit64::HLEFunction(UGeckoInstruction _inst)
{
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
MOV(32, R(EAX), M(&NPC));
WriteExitDestInEAX(0);
WriteRfiExitDestInEAX();
}
}
void Jit64::DoNothing(UGeckoInstruction _inst)
void Jit64::unknown_instruction(UGeckoInstruction inst)
{
// CCPU::Break();
PanicAlert("unknown_instruction %08x - Fix me ;)", inst.hex);
}
void Jit64::Default(UGeckoInstruction _inst)
{
ibuild.EmitInterpreterFallback(
ibuild.EmitIntConst(_inst.hex),
ibuild.EmitIntConst(js.compilerPC));
}
void Jit64::HLEFunction(UGeckoInstruction _inst)
{
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
MOV(32, R(EAX), M(&NPC));
WriteExitDestInEAX(0);
}
void Jit64::DoNothing(UGeckoInstruction _inst)
{
// Yup, just don't do anything.
}
void Jit64::NotifyBreakpoint(u32 em_address, bool set)
{
int block_num = blocks.GetBlockNumberFromStartAddress(em_address);
if (block_num >= 0)
{
// Yup, just don't do anything.
blocks.DestroyBlock(block_num, false);
}
}
void Jit64::NotifyBreakpoint(u32 em_address, bool set)
{
int block_num = blocks.GetBlockNumberFromStartAddress(em_address);
if (block_num >= 0)
static const bool ImHereDebug = false;
static const bool ImHereLog = false;
static std::map<u32, int> been_here;
void ImHere()
{
static FILE *f = 0;
if (ImHereLog) {
if (!f)
{
blocks.DestroyBlock(block_num, false);
}
}
static const bool ImHereDebug = false;
static const bool ImHereLog = false;
static std::map<u32, int> been_here;
void ImHere()
{
static FILE *f = 0;
if (ImHereLog) {
if (!f)
{
#ifdef _M_X64
f = fopen("log64.txt", "w");
f = fopen("log64.txt", "w");
#else
f = fopen("log32.txt", "w");
f = fopen("log32.txt", "w");
#endif
}
fprintf(f, "%08x\n", PC);
}
if (been_here.find(PC) != been_here.end()) {
been_here.find(PC)->second++;
if ((been_here.find(PC)->second) & 1023)
return;
}
DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR);
// printf("I'm here - PC = %08x , LR = %08x", PC, LR);
been_here[PC] = 1;
fprintf(f, "%08x\n", PC);
}
void Jit64::Cleanup()
{
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
ABI_CallFunction((void *)&GPFifo::CheckGatherPipe);
if (been_here.find(PC) != been_here.end()) {
been_here.find(PC)->second++;
if ((been_here.find(PC)->second) & 1023)
return;
}
DEBUG_LOG(DYNA_REC, "I'm here - PC = %08x , LR = %08x", PC, LR);
// printf("I'm here - PC = %08x , LR = %08x", PC, LR);
been_here[PC] = 1;
}
void Jit64::WriteExit(u32 destination, int exit_num)
void Jit64::Cleanup()
{
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
ABI_CallFunction((void *)&GPFifo::CheckGatherPipe);
}
void Jit64::WriteExit(u32 destination, int exit_num)
{
Cleanup();
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
//If nobody has taken care of this yet (this can be removed when all branches are done)
JitBlock *b = js.curBlock;
b->exitAddress[exit_num] = destination;
b->exitPtrs[exit_num] = GetWritableCodePtr();
// Link opportunity!
int block = blocks.GetBlockNumberFromStartAddress(destination);
if (block >= 0 && jo.enableBlocklink)
{
Cleanup();
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
//If nobody has taken care of this yet (this can be removed when all branches are done)
JitBlock *b = js.curBlock;
b->exitAddress[exit_num] = destination;
b->exitPtrs[exit_num] = GetWritableCodePtr();
// Link opportunity!
int block = blocks.GetBlockNumberFromStartAddress(destination);
if (block >= 0 && jo.enableBlocklink)
{
// It exists! Joy of joy!
JMP(blocks.GetBlock(block)->checkedEntry, true);
b->linkStatus[exit_num] = true;
}
else
{
MOV(32, M(&PC), Imm32(destination));
JMP(asm_routines.dispatcher, true);
}
// It exists! Joy of joy!
JMP(blocks.GetBlock(block)->checkedEntry, true);
b->linkStatus[exit_num] = true;
}
void Jit64::WriteExitDestInEAX(int exit_num)
else
{
MOV(32, M(&PC), R(EAX));
Cleanup();
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
MOV(32, M(&PC), Imm32(destination));
JMP(asm_routines.dispatcher, true);
}
}
void Jit64::WriteRfiExitDestInEAX()
{
MOV(32, M(&PC), R(EAX));
Cleanup();
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_routines.testExceptions, true);
}
void Jit64::WriteExitDestInEAX(int exit_num)
{
MOV(32, M(&PC), R(EAX));
Cleanup();
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_routines.dispatcher, true);
}
void Jit64::WriteExceptionExit(u32 exception)
void Jit64::WriteRfiExitDestInEAX()
{
MOV(32, M(&PC), R(EAX));
Cleanup();
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_routines.testExceptions, true);
}
void Jit64::WriteExceptionExit(u32 exception)
{
Cleanup();
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(exception));
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
JMP(asm_routines.testExceptions, true);
}
void STACKALIGN Jit64::Run()
{
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
pExecAddr();
//Will return when PowerPC::state changes
}
void Jit64::SingleStep()
{
// NOT USED, NOT TESTED, PROBABLY NOT WORKING YET
// PanicAlert("Single");
/*
JitBlock temp_block;
PPCAnalyst::CodeBuffer temp_codebuffer(1); // Only room for one instruction! Single step!
const u8 *code = DoJit(PowerPC::ppcState.pc, &temp_codebuffer, &temp_block);
CompiledCode pExecAddr = (CompiledCode)code;
pExecAddr();*/
}
void STACKALIGN Jit64::Jit(u32 em_address)
{
if (GetSpaceLeft() < 0x10000 || blocks.IsFull())
{
Cleanup();
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(exception));
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
JMP(asm_routines.testExceptions, true);
INFO_LOG(DYNA_REC, "JIT cache full - clearing.")
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
{
ERROR_LOG(DYNA_REC, "What? JIT cache still full - clearing.");
PanicAlert("What? JIT cache still full - clearing.");
}
ClearCache();
}
int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b));
}
const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b)
{
if (em_address == 0)
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
int size;
js.isLastInstruction = false;
js.blockStart = em_address;
js.fifoBytesThisBlock = 0;
js.curBlock = b;
js.blockSetsQuantizers = false;
js.block_flags = 0;
js.cancel = false;
//Analyze the block, collect all instructions it is made of (including inlining,
//if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, code_buffer);
PPCAnalyst::CodeOp *ops = code_buffer->codebuffer;
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr
b->checkedEntry = start;
b->runCount = 0;
// Downcount flag check. The last block decremented downcounter, and the flag should still be available.
FixupBranch skip = J_CC(CC_NBE);
MOV(32, M(&PC), Imm32(js.blockStart));
JMP(asm_routines.doTiming, true); // downcount hit zero - go doTiming.
SetJumpTarget(skip);
const u8 *normalEntry = GetCodePtr();
b->normalEntry = normalEntry;
void STACKALIGN Jit64::Run()
if (ImHereDebug)
ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful
if (js.fpa.any)
{
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
pExecAddr();
//Will return when PowerPC::state changes
}
void Jit64::SingleStep()
{
// NOT USED, NOT TESTED, PROBABLY NOT WORKING YET
// PanicAlert("Single");
/*
JitBlock temp_block;
PPCAnalyst::CodeBuffer temp_codebuffer(1); // Only room for one instruction! Single step!
const u8 *code = DoJit(PowerPC::ppcState.pc, &temp_codebuffer, &temp_block);
CompiledCode pExecAddr = (CompiledCode)code;
pExecAddr();*/
}
void STACKALIGN Jit64::Jit(u32 em_address)
{
if (GetSpaceLeft() < 0x10000 || blocks.IsFull())
{
INFO_LOG(DYNA_REC, "JIT cache full - clearing.")
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
{
ERROR_LOG(DYNA_REC, "What? JIT cache still full - clearing.");
PanicAlert("What? JIT cache still full - clearing.");
}
ClearCache();
}
int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b));
}
const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b)
{
if (em_address == 0)
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
int size;
js.isLastInstruction = false;
js.blockStart = em_address;
js.fifoBytesThisBlock = 0;
js.curBlock = b;
js.blockSetsQuantizers = false;
js.block_flags = 0;
js.cancel = false;
//Analyze the block, collect all instructions it is made of (including inlining,
//if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, code_buffer);
PPCAnalyst::CodeOp *ops = code_buffer->codebuffer;
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr
b->checkedEntry = start;
b->runCount = 0;
// Downcount flag check. The last block decremented downcounter, and the flag should still be available.
FixupBranch skip = J_CC(CC_NBE);
//This block uses FPU - needs to add FP exception bailout
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); //Test FP enabled bit
FixupBranch b1 = J_CC(CC_NZ);
MOV(32, M(&PC), Imm32(js.blockStart));
JMP(asm_routines.doTiming, true); // downcount hit zero - go doTiming.
SetJumpTarget(skip);
const u8 *normalEntry = GetCodePtr();
b->normalEntry = normalEntry;
if (ImHereDebug)
ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful
if (js.fpa.any)
{
//This block uses FPU - needs to add FP exception bailout
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); //Test FP enabled bit
FixupBranch b1 = J_CC(CC_NZ);
MOV(32, M(&PC), Imm32(js.blockStart));
JMP(asm_routines.fpException, true);
SetJumpTarget(b1);
}
js.rewriteStart = (u8*)GetCodePtr();
// Start up IR builder (structure that collects the
// instruction processed by the JIT routines)
ibuild.Reset();
js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address);
js.blockSize = size;
// Translate instructions
for (int i = 0; i < (int)size; i++)
{
js.compilerPC = ops[i].address;
js.op = &ops[i];
js.instructionNumber = i;
if (i == (int)size - 1)
{
js.isLastInstruction = true;
js.next_inst = 0;
}
else
{
// help peephole optimizations
js.next_inst = ops[i + 1].inst;
js.next_compilerPC = ops[i + 1].address;
}
if (!ops[i].skip)
PPCTables::CompileInstruction(ops[i].inst);
}
// Perform actual code generation
WriteCode();
b->flags = js.block_flags;
b->codeSize = (u32)(GetCodePtr() - normalEntry);
b->originalSize = size;
return normalEntry;
JMP(asm_routines.fpException, true);
SetJumpTarget(b1);
}
js.rewriteStart = (u8*)GetCodePtr();
// Start up IR builder (structure that collects the
// instruction processed by the JIT routines)
ibuild.Reset();
js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address);
js.blockSize = size;
// Translate instructions
for (int i = 0; i < (int)size; i++)
{
js.compilerPC = ops[i].address;
js.op = &ops[i];
js.instructionNumber = i;
if (i == (int)size - 1)
{
js.isLastInstruction = true;
js.next_inst = 0;
}
else
{
// help peephole optimizations
js.next_inst = ops[i + 1].inst;
js.next_compilerPC = ops[i + 1].address;
}
if (!ops[i].skip)
PPCTables::CompileInstruction(ops[i].inst);
}
// Perform actual code generation
WriteCode();
b->flags = js.block_flags;
b->codeSize = (u32)(GetCodePtr() - normalEntry);
b->originalSize = size;
return normalEntry;
}

View File

@ -71,6 +71,14 @@ struct CONTEXT
Core::g_CoreStartupParameter.bJIT##type##Off) \
{Default(inst); return;}
#ifdef _M_X64
#define DISABLE64 \
{Default(inst); return;}
#else
#define DISABLE64
#endif
class TrampolineCache : public Gen::XCodeBlock
{
public:

View File

@ -45,150 +45,149 @@
using namespace Gen;
void Jit64::sc(UGeckoInstruction inst)
{
ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC));
void Jit64::sc(UGeckoInstruction inst)
{
ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC));
}
void Jit64::rfi(UGeckoInstruction inst)
{
ibuild.EmitRFIExit();
}
void Jit64::bx(UGeckoInstruction inst)
{
NORMALBRANCH_START
INSTRUCTION_START;
if (inst.LK)
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
u32 destination;
if (inst.AA)
destination = SignExt26(inst.LI << 2);
else
destination = js.compilerPC + SignExt26(inst.LI << 2);
if (destination == js.compilerPC) {
ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC));
return;
}
void Jit64::rfi(UGeckoInstruction inst)
ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination));
}
static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) {
IREmitter::InstLoc CRTest = 0, CTRTest = 0;
if ((inst.BO & 16) == 0) // Test a CR bit
{
ibuild.EmitRFIExit();
IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2);
IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3));
CRTest = ibuild.EmitAnd(CRReg, CRCmp);
if (!(inst.BO & 8))
CRTest = ibuild.EmitXor(CRTest, CRCmp);
}
void Jit64::bx(UGeckoInstruction inst)
{
NORMALBRANCH_START
INSTRUCTION_START;
if (inst.LK)
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
u32 destination;
if (inst.AA)
destination = SignExt26(inst.LI << 2);
else
destination = js.compilerPC + SignExt26(inst.LI << 2);
if (destination == js.compilerPC) {
ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC));
return;
}
ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination));
}
static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) {
IREmitter::InstLoc CRTest = 0, CTRTest = 0;
if ((inst.BO & 16) == 0) // Test a CR bit
{
IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2);
IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3));
CRTest = ibuild.EmitAnd(CRReg, CRCmp);
if (!(inst.BO & 8))
CRTest = ibuild.EmitXor(CRTest, CRCmp);
}
if ((inst.BO & 4) == 0) {
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
ibuild.EmitStoreCTR(c);
if (inst.BO & 2) {
CTRTest = ibuild.EmitICmpEq(c,
ibuild.EmitIntConst(0));
} else {
CTRTest = c;
}
}
IREmitter::InstLoc Test = CRTest;
if (CTRTest) {
if (Test)
Test = ibuild.EmitAnd(Test, CTRTest);
else
Test = CTRTest;
}
if (!Test) {
Test = ibuild.EmitIntConst(1);
}
return Test;
}
void Jit64::bcx(UGeckoInstruction inst)
{
NORMALBRANCH_START
if (inst.LK)
ibuild.EmitStoreLink(
ibuild.EmitIntConst(js.compilerPC + 4));
IREmitter::InstLoc Test = TestBranch(ibuild, inst);
u32 destination;
if(inst.AA)
destination = SignExt16(inst.BD << 2);
else
destination = js.compilerPC + SignExt16(inst.BD << 2);
if (Core::GetStartupParameter().bSkipIdle &&
inst.hex == 0x4182fff8 &&
(Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
(Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 ||
(Core::GetStartupParameter().bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000))
)
{
ibuild.EmitIdleBranch(Test, ibuild.EmitIntConst(destination));
}
else
{
ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination));
}
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
}
void Jit64::bcctrx(UGeckoInstruction inst)
{
NORMALBRANCH_START
if ((inst.BO & 4) == 0) {
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
ibuild.EmitStoreCTR(c);
}
IREmitter::InstLoc test;
if ((inst.BO & 16) == 0) // Test a CR bit
{
IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2);
IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3));
test = ibuild.EmitAnd(CRReg, CRCmp);
if (!(inst.BO & 8))
test = ibuild.EmitXor(test, CRCmp);
if ((inst.BO & 4) == 0) {
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
ibuild.EmitStoreCTR(c);
if (inst.BO & 2) {
CTRTest = ibuild.EmitICmpEq(c,
ibuild.EmitIntConst(0));
} else {
test = ibuild.EmitIntConst(1);
CTRTest = c;
}
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
IREmitter::InstLoc destination = ibuild.EmitLoadCTR();
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
if (inst.LK)
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
ibuild.EmitBranchUncond(destination);
}
void Jit64::bclrx(UGeckoInstruction inst)
IREmitter::InstLoc Test = CRTest;
if (CTRTest) {
if (Test)
Test = ibuild.EmitAnd(Test, CTRTest);
else
Test = CTRTest;
}
if (!Test) {
Test = ibuild.EmitIntConst(1);
}
return Test;
}
void Jit64::bcx(UGeckoInstruction inst)
{
NORMALBRANCH_START
if (inst.LK)
ibuild.EmitStoreLink(
ibuild.EmitIntConst(js.compilerPC + 4));
IREmitter::InstLoc Test = TestBranch(ibuild, inst);
u32 destination;
if(inst.AA)
destination = SignExt16(inst.BD << 2);
else
destination = js.compilerPC + SignExt16(inst.BD << 2);
if (Core::GetStartupParameter().bSkipIdle &&
inst.hex == 0x4182fff8 &&
(Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
(Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 ||
(Core::GetStartupParameter().bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000))
)
{
ibuild.EmitIdleBranch(Test, ibuild.EmitIntConst(destination));
}
else
{
NORMALBRANCH_START
if (inst.hex == 0x4e800020) {
ibuild.EmitBranchUncond(ibuild.EmitLoadLink());
return;
}
IREmitter::InstLoc test = TestBranch(ibuild, inst);
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
IREmitter::InstLoc destination = ibuild.EmitLoadLink();
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
if (inst.LK)
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
ibuild.EmitBranchUncond(destination);
ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination));
}
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
}
void Jit64::bcctrx(UGeckoInstruction inst)
{
NORMALBRANCH_START
if ((inst.BO & 4) == 0) {
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
ibuild.EmitStoreCTR(c);
}
IREmitter::InstLoc test;
if ((inst.BO & 16) == 0) // Test a CR bit
{
IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2);
IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3));
test = ibuild.EmitAnd(CRReg, CRCmp);
if (!(inst.BO & 8))
test = ibuild.EmitXor(test, CRCmp);
} else {
test = ibuild.EmitIntConst(1);
}
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
IREmitter::InstLoc destination = ibuild.EmitLoadCTR();
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
if (inst.LK)
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
ibuild.EmitBranchUncond(destination);
}
void Jit64::bclrx(UGeckoInstruction inst)
{
NORMALBRANCH_START
if (inst.hex == 0x4e800020) {
ibuild.EmitBranchUncond(ibuild.EmitLoadLink());
return;
}
IREmitter::InstLoc test = TestBranch(ibuild, inst);
test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0));
ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4));
IREmitter::InstLoc destination = ibuild.EmitLoadLink();
destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4));
if (inst.LK)
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
ibuild.EmitBranchUncond(destination);
}

View File

@ -28,86 +28,86 @@
//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START
void Jit64::fp_arith_s(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)
if (inst.Rc || (inst.SUBOP5 != 25 && inst.SUBOP5 != 20 && inst.SUBOP5 != 21)) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
switch (inst.SUBOP5)
{
case 25: //mul
val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
break;
case 18: //div
case 20: //sub
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
break;
case 21: //add
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
break;
case 23: //sel
case 24: //res
default:
_assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!");
}
if (inst.OPCD == 59) {
val = ibuild.EmitDoubleToSingle(val);
val = ibuild.EmitDupSingleToMReg(val);
} else {
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
}
ibuild.EmitStoreFReg(val, inst.FD);
void Jit64::fp_arith_s(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)
if (inst.Rc || (inst.SUBOP5 != 25 && inst.SUBOP5 != 20 && inst.SUBOP5 != 21)) {
Default(inst); return;
}
void Jit64::fmaddXX(UGeckoInstruction inst)
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
switch (inst.SUBOP5)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
case 25: //mul
val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
if (inst.SUBOP5 & 1)
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
else
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
if (inst.SUBOP5 & 2)
val = ibuild.EmitFDNeg(val);
if (inst.OPCD == 59) {
val = ibuild.EmitDoubleToSingle(val);
val = ibuild.EmitDupSingleToMReg(val);
} else {
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
}
ibuild.EmitStoreFReg(val, inst.FD);
}
void Jit64::fmrx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FB);
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
ibuild.EmitStoreFReg(val, inst.FD);
break;
case 18: //div
case 20: //sub
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
break;
case 21: //add
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
break;
case 23: //sel
case 24: //res
default:
_assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!");
}
void Jit64::fcmpx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)
IREmitter::InstLoc lhs, rhs, res;
lhs = ibuild.EmitLoadFRegDENToZero(inst.FA);
rhs = ibuild.EmitLoadFRegDENToZero(inst.FB);
res = ibuild.EmitFDCmpCR(lhs, rhs);
ibuild.EmitStoreFPRF(res);
ibuild.EmitStoreCR(res, inst.CRFD);
if (inst.OPCD == 59) {
val = ibuild.EmitDoubleToSingle(val);
val = ibuild.EmitDupSingleToMReg(val);
} else {
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
}
ibuild.EmitStoreFReg(val, inst.FD);
}
void Jit64::fmaddXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
if (inst.SUBOP5 & 1)
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
else
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
if (inst.SUBOP5 & 2)
val = ibuild.EmitFDNeg(val);
if (inst.OPCD == 59) {
val = ibuild.EmitDoubleToSingle(val);
val = ibuild.EmitDupSingleToMReg(val);
} else {
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
}
ibuild.EmitStoreFReg(val, inst.FD);
}
void Jit64::fmrx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FB);
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
ibuild.EmitStoreFReg(val, inst.FD);
}
void Jit64::fcmpx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)
IREmitter::InstLoc lhs, rhs, res;
lhs = ibuild.EmitLoadFRegDENToZero(inst.FA);
rhs = ibuild.EmitLoadFRegDENToZero(inst.FB);
res = ibuild.EmitFDCmpCR(lhs, rhs);
ibuild.EmitStoreFPRF(res);
ibuild.EmitStoreCR(res, inst.CRFD);
}

View File

@ -31,514 +31,514 @@
//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START
static void ComputeRC(IREmitter::IRBuilder& ibuild,
IREmitter::InstLoc val) {
IREmitter::InstLoc res =
ibuild.EmitICmpCRSigned(val, ibuild.EmitIntConst(0));
ibuild.EmitStoreCR(res, 0);
}
static void ComputeRC(IREmitter::IRBuilder& ibuild,
IREmitter::InstLoc val) {
IREmitter::InstLoc res =
ibuild.EmitICmpCRSigned(val, ibuild.EmitIntConst(0));
ibuild.EmitStoreCR(res, 0);
}
void Jit64::reg_imm(UGeckoInstruction inst)
void Jit64::reg_imm(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
int d = inst.RD, a = inst.RA, s = inst.RS;
IREmitter::InstLoc val, test, c;
switch (inst.OPCD)
{
INSTRUCTION_START
JITDISABLE(Integer)
int d = inst.RD, a = inst.RA, s = inst.RS;
IREmitter::InstLoc val, test, c;
switch (inst.OPCD)
{
case 14: //addi
val = ibuild.EmitIntConst(inst.SIMM_16);
if (a)
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
ibuild.EmitStoreGReg(val, d);
break;
case 15: //addis
val = ibuild.EmitIntConst(inst.SIMM_16 << 16);
if (a)
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
ibuild.EmitStoreGReg(val, d);
break;
case 24: //ori
val = ibuild.EmitIntConst(inst.UIMM);
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
break;
case 25: //oris
val = ibuild.EmitIntConst(inst.UIMM << 16);
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
break;
case 28: //andi
val = ibuild.EmitIntConst(inst.UIMM);
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
case 14: //addi
val = ibuild.EmitIntConst(inst.SIMM_16);
if (a)
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
ibuild.EmitStoreGReg(val, d);
break;
case 15: //addis
val = ibuild.EmitIntConst(inst.SIMM_16 << 16);
if (a)
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
ibuild.EmitStoreGReg(val, d);
break;
case 24: //ori
val = ibuild.EmitIntConst(inst.UIMM);
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
break;
case 25: //oris
val = ibuild.EmitIntConst(inst.UIMM << 16);
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
break;
case 28: //andi
val = ibuild.EmitIntConst(inst.UIMM);
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
ComputeRC(ibuild, val);
break;
case 29: //andis
val = ibuild.EmitIntConst(inst.UIMM << 16);
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
ComputeRC(ibuild, val);
break;
case 26: //xori
val = ibuild.EmitIntConst(inst.UIMM);
val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
break;
case 27: //xoris
val = ibuild.EmitIntConst(inst.UIMM << 16);
val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
break;
case 12: //addic
case 13: //addic_rc
c = ibuild.EmitIntConst(inst.SIMM_16);
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), c);
ibuild.EmitStoreGReg(val, d);
test = ibuild.EmitICmpUgt(c, val);
ibuild.EmitStoreCarry(test);
if (inst.OPCD == 13)
ComputeRC(ibuild, val);
break;
case 29: //andis
val = ibuild.EmitIntConst(inst.UIMM << 16);
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
ComputeRC(ibuild, val);
break;
case 26: //xori
val = ibuild.EmitIntConst(inst.UIMM);
val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
break;
case 27: //xoris
val = ibuild.EmitIntConst(inst.UIMM << 16);
val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val);
ibuild.EmitStoreGReg(val, a);
break;
case 12: //addic
case 13: //addic_rc
c = ibuild.EmitIntConst(inst.SIMM_16);
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), c);
ibuild.EmitStoreGReg(val, d);
test = ibuild.EmitICmpUgt(c, val);
ibuild.EmitStoreCarry(test);
if (inst.OPCD == 13)
ComputeRC(ibuild, val);
break;
default:
Default(inst);
break;
}
break;
default:
Default(inst);
break;
}
}
void Jit64::cmpXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc lhs, rhs, res;
lhs = ibuild.EmitLoadGReg(inst.RA);
if (inst.OPCD == 31) {
rhs = ibuild.EmitLoadGReg(inst.RB);
if (inst.SUBOP10 == 32) {
res = ibuild.EmitICmpCRUnsigned(lhs, rhs);
} else {
res = ibuild.EmitICmpCRSigned(lhs, rhs);
}
} else if (inst.OPCD == 10) {
rhs = ibuild.EmitIntConst(inst.UIMM);
void Jit64::cmpXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc lhs, rhs, res;
lhs = ibuild.EmitLoadGReg(inst.RA);
if (inst.OPCD == 31) {
rhs = ibuild.EmitLoadGReg(inst.RB);
if (inst.SUBOP10 == 32) {
res = ibuild.EmitICmpCRUnsigned(lhs, rhs);
} else { // inst.OPCD == 11
rhs = ibuild.EmitIntConst(inst.SIMM_16);
} else {
res = ibuild.EmitICmpCRSigned(lhs, rhs);
}
ibuild.EmitStoreCR(res, inst.CRFD);
} else if (inst.OPCD == 10) {
rhs = ibuild.EmitIntConst(inst.UIMM);
res = ibuild.EmitICmpCRUnsigned(lhs, rhs);
} else { // inst.OPCD == 11
rhs = ibuild.EmitIntConst(inst.SIMM_16);
res = ibuild.EmitICmpCRSigned(lhs, rhs);
}
void Jit64::orx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitOr(ibuild.EmitLoadGReg(inst.RS), val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
// m_GPR[_inst.RA] = m_GPR[_inst.RS] ^ m_GPR[_inst.RB];
void Jit64::xorx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RS), val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
ibuild.EmitStoreCR(res, inst.CRFD);
}
void Jit64::andx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(inst.RS), val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::orx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitOr(ibuild.EmitLoadGReg(inst.RS), val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::extsbx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitSExt8(val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::extshx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitSExt16(val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
// m_GPR[_inst.RA] = m_GPR[_inst.RS] ^ m_GPR[_inst.RB];
void Jit64::xorx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RS), val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::subfic(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc nota, lhs, val, test;
nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA),
ibuild.EmitIntConst(-1));
if (inst.SIMM_16 == -1) {
val = nota;
test = ibuild.EmitIntConst(1);
} else {
lhs = ibuild.EmitIntConst(inst.SIMM_16 + 1);
val = ibuild.EmitAdd(nota, lhs);
test = ibuild.EmitICmpUgt(lhs, val);
}
ibuild.EmitStoreGReg(val, inst.RD);
ibuild.EmitStoreCarry(test);
}
void Jit64::andx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(inst.RS), val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::subfcx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
if (inst.OE) PanicAlert("OE: subfcx");
IREmitter::InstLoc val, test, lhs, rhs;
lhs = ibuild.EmitLoadGReg(inst.RB);
rhs = ibuild.EmitLoadGReg(inst.RA);
val = ibuild.EmitSub(lhs, rhs);
ibuild.EmitStoreGReg(val, inst.RD);
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
ibuild.EmitStoreCarry(test);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::extsbx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitSExt8(val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::subfex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
if (inst.OE) PanicAlert("OE: subfex");
IREmitter::InstLoc val, test, lhs, rhs, carry;
rhs = ibuild.EmitLoadGReg(inst.RA);
carry = ibuild.EmitLoadCarry();
rhs = ibuild.EmitXor(rhs, ibuild.EmitIntConst(-1));
rhs = ibuild.EmitAdd(rhs, carry);
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
test = ibuild.EmitAnd(test, carry);
lhs = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitAdd(lhs, rhs);
ibuild.EmitStoreGReg(val, inst.RD);
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
ibuild.EmitStoreCarry(test);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::extshx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitSExt16(val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::subfx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
if (inst.OE) PanicAlert("OE: subfx");
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA));
ibuild.EmitStoreGReg(val, inst.RD);
if (inst.Rc)
ComputeRC(ibuild, val);
void Jit64::subfic(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc nota, lhs, val, test;
nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA),
ibuild.EmitIntConst(-1));
if (inst.SIMM_16 == -1) {
val = nota;
test = ibuild.EmitIntConst(1);
} else {
lhs = ibuild.EmitIntConst(inst.SIMM_16 + 1);
val = ibuild.EmitAdd(nota, lhs);
test = ibuild.EmitICmpUgt(lhs, val);
}
ibuild.EmitStoreGReg(val, inst.RD);
ibuild.EmitStoreCarry(test);
}
void Jit64::mulli(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
val = ibuild.EmitMul(val, ibuild.EmitIntConst(inst.SIMM_16));
ibuild.EmitStoreGReg(val, inst.RD);
}
void Jit64::subfcx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
if (inst.OE) PanicAlert("OE: subfcx");
IREmitter::InstLoc val, test, lhs, rhs;
lhs = ibuild.EmitLoadGReg(inst.RB);
rhs = ibuild.EmitLoadGReg(inst.RA);
val = ibuild.EmitSub(lhs, rhs);
ibuild.EmitStoreGReg(val, inst.RD);
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
ibuild.EmitStoreCarry(test);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::mullwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitMul(ibuild.EmitLoadGReg(inst.RA), val);
ibuild.EmitStoreGReg(val, inst.RD);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::subfex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
if (inst.OE) PanicAlert("OE: subfex");
IREmitter::InstLoc val, test, lhs, rhs, carry;
rhs = ibuild.EmitLoadGReg(inst.RA);
carry = ibuild.EmitLoadCarry();
rhs = ibuild.EmitXor(rhs, ibuild.EmitIntConst(-1));
rhs = ibuild.EmitAdd(rhs, carry);
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
test = ibuild.EmitAnd(test, carry);
lhs = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitAdd(lhs, rhs);
ibuild.EmitStoreGReg(val, inst.RD);
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
ibuild.EmitStoreCarry(test);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::mulhwux(UGeckoInstruction inst)
{
Default(inst); return;
void Jit64::subfx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
if (inst.OE) PanicAlert("OE: subfx");
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA));
ibuild.EmitStoreGReg(val, inst.RD);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::mulli(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
val = ibuild.EmitMul(val, ibuild.EmitIntConst(inst.SIMM_16));
ibuild.EmitStoreGReg(val, inst.RD);
}
void Jit64::mullwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitMul(ibuild.EmitLoadGReg(inst.RA), val);
ibuild.EmitStoreGReg(val, inst.RD);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::mulhwux(UGeckoInstruction inst)
{
Default(inst); return;
#if 0
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITIntegerOff)
{Default(inst); return;} // turn off from debugger
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITIntegerOff)
{Default(inst); return;} // turn off from debugger
INSTRUCTION_START;
int a = inst.RA, b = inst.RB, d = inst.RD;
gpr.FlushLockX(EDX);
gpr.Lock(a, b, d);
if (d != a && d != b) {
gpr.LoadToX64(d, false, true);
} else {
gpr.LoadToX64(d, true, true);
}
if (gpr.RX(d) == EDX)
PanicAlert("mulhwux : WTF");
MOV(32, R(EAX), gpr.R(a));
gpr.KillImmediate(b);
MUL(32, gpr.R(b));
gpr.UnlockAll();
gpr.UnlockAllX();
if (inst.Rc) {
MOV(32, R(EAX), R(EDX));
MOV(32, gpr.R(d), R(EDX));
// result is already in eax
CALL((u8*)asm_routines.computeRc);
} else {
MOV(32, gpr.R(d), R(EDX));
}
#endif
INSTRUCTION_START;
int a = inst.RA, b = inst.RB, d = inst.RD;
gpr.FlushLockX(EDX);
gpr.Lock(a, b, d);
if (d != a && d != b) {
gpr.LoadToX64(d, false, true);
} else {
gpr.LoadToX64(d, true, true);
}
if (gpr.RX(d) == EDX)
PanicAlert("mulhwux : WTF");
MOV(32, R(EAX), gpr.R(a));
gpr.KillImmediate(b);
MUL(32, gpr.R(b));
gpr.UnlockAll();
gpr.UnlockAllX();
if (inst.Rc) {
MOV(32, R(EAX), R(EDX));
MOV(32, gpr.R(d), R(EDX));
// result is already in eax
CALL((u8*)asm_routines.computeRc);
} else {
MOV(32, gpr.R(d), R(EDX));
}
#endif
}
// skipped some of the special handling in here - if we get crashes, let the interpreter handle this op
void Jit64::divwux(UGeckoInstruction inst) {
Default(inst); return;
// skipped some of the special handling in here - if we get crashes, let the interpreter handle this op
void Jit64::divwux(UGeckoInstruction inst) {
Default(inst); return;
#if 0
int a = inst.RA, b = inst.RB, d = inst.RD;
gpr.FlushLockX(EDX);
gpr.Lock(a, b, d);
if (d != a && d != b) {
gpr.LoadToX64(d, false, true);
} else {
gpr.LoadToX64(d, true, true);
}
MOV(32, R(EAX), gpr.R(a));
XOR(32, R(EDX), R(EDX));
gpr.KillImmediate(b);
DIV(32, gpr.R(b));
MOV(32, gpr.R(d), R(EAX));
gpr.UnlockAll();
gpr.UnlockAllX();
if (inst.Rc) {
CALL((u8*)asm_routines.computeRc);
}
int a = inst.RA, b = inst.RB, d = inst.RD;
gpr.FlushLockX(EDX);
gpr.Lock(a, b, d);
if (d != a && d != b) {
gpr.LoadToX64(d, false, true);
} else {
gpr.LoadToX64(d, true, true);
}
MOV(32, R(EAX), gpr.R(a));
XOR(32, R(EDX), R(EDX));
gpr.KillImmediate(b);
DIV(32, gpr.R(b));
MOV(32, gpr.R(d), R(EAX));
gpr.UnlockAll();
gpr.UnlockAllX();
if (inst.Rc) {
CALL((u8*)asm_routines.computeRc);
}
#endif
}
}
u32 Helper_Mask(u8 mb, u8 me)
{
return (((mb > me) ?
~(((u32)-1 >> mb) ^ ((me >= 31) ? 0 : (u32) -1 >> (me + 1)))
:
(((u32)-1 >> mb) ^ ((me >= 31) ? 0 : (u32) -1 >> (me + 1))))
);
}
u32 Helper_Mask(u8 mb, u8 me)
{
return (((mb > me) ?
~(((u32)-1 >> mb) ^ ((me >= 31) ? 0 : (u32) -1 >> (me + 1)))
:
(((u32)-1 >> mb) ^ ((me >= 31) ? 0 : (u32) -1 >> (me + 1))))
);
}
void Jit64::addx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val);
ibuild.EmitStoreGReg(val, inst.RD);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::addx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val);
ibuild.EmitStoreGReg(val, inst.RD);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::addzex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA),
val, newcarry;
val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry());
ibuild.EmitStoreGReg(val, inst.RD);
newcarry = ibuild.EmitICmpUlt(val, lhs);
ibuild.EmitStoreCarry(newcarry);
if (inst.Rc)
ComputeRC(ibuild, val);
}
// This can be optimized
void Jit64::addex(UGeckoInstruction inst)
{
Default(inst); return;
void Jit64::addzex(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA),
val, newcarry;
val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry());
ibuild.EmitStoreGReg(val, inst.RD);
newcarry = ibuild.EmitICmpUlt(val, lhs);
ibuild.EmitStoreCarry(newcarry);
if (inst.Rc)
ComputeRC(ibuild, val);
}
// This can be optimized
void Jit64::addex(UGeckoInstruction inst)
{
Default(inst); return;
#if 0
// USES_XER
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITIntegerOff)
{Default(inst); return;} // turn off from debugger
// USES_XER
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITIntegerOff)
{Default(inst); return;} // turn off from debugger
INSTRUCTION_START;
int a = inst.RA, b = inst.RB, d = inst.RD;
gpr.FlushLockX(ECX);
gpr.Lock(a, b, d);
if (d != a && d != b)
gpr.LoadToX64(d, false);
else
gpr.LoadToX64(d, true);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
MOV(32, R(EAX), gpr.R(a));
ADC(32, R(EAX), gpr.R(b));
MOV(32, gpr.R(d), R(EAX));
//GenerateCarry(ECX);
gpr.UnlockAll();
gpr.UnlockAllX();
if (inst.Rc)
{
CALL((u8*)asm_routines.computeRc);
}
INSTRUCTION_START;
int a = inst.RA, b = inst.RB, d = inst.RD;
gpr.FlushLockX(ECX);
gpr.Lock(a, b, d);
if (d != a && d != b)
gpr.LoadToX64(d, false);
else
gpr.LoadToX64(d, true);
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
MOV(32, R(EAX), gpr.R(a));
ADC(32, R(EAX), gpr.R(b));
MOV(32, gpr.R(d), R(EAX));
//GenerateCarry(ECX);
gpr.UnlockAll();
gpr.UnlockAllX();
if (inst.Rc)
{
CALL((u8*)asm_routines.computeRc);
}
#endif
}
}
void Jit64::rlwinmx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
unsigned mask = Helper_Mask(inst.MB, inst.ME);
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::rlwinmx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
unsigned mask = Helper_Mask(inst.MB, inst.ME);
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::rlwimix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
unsigned mask = Helper_Mask(inst.MB, inst.ME);
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
IREmitter::InstLoc ival = ibuild.EmitLoadGReg(inst.RA);
ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask));
val = ibuild.EmitOr(ival, val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::rlwimix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
unsigned mask = Helper_Mask(inst.MB, inst.ME);
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
IREmitter::InstLoc ival = ibuild.EmitLoadGReg(inst.RA);
ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask));
val = ibuild.EmitOr(ival, val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::rlwnmx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
unsigned int mask = Helper_Mask(inst.MB, inst.ME);
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB));
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::rlwnmx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
unsigned int mask = Helper_Mask(inst.MB, inst.ME);
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB));
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::negx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
val = ibuild.EmitSub(ibuild.EmitIntConst(0), val);
ibuild.EmitStoreGReg(val, inst.RD);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::negx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
val = ibuild.EmitSub(ibuild.EmitIntConst(0), val);
ibuild.EmitStoreGReg(val, inst.RD);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::srwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
samt = ibuild.EmitLoadGReg(inst.RB),
corr;
// FIXME: We can do better with a cmov
// FIXME: We can do better on 64-bit
val = ibuild.EmitShrl(val, samt);
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
val = ibuild.EmitAnd(corr, val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::srwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
samt = ibuild.EmitLoadGReg(inst.RB),
corr;
// FIXME: We can do better with a cmov
// FIXME: We can do better on 64-bit
val = ibuild.EmitShrl(val, samt);
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
val = ibuild.EmitAnd(corr, val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::slwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
samt = ibuild.EmitLoadGReg(inst.RB),
corr;
// FIXME: We can do better with a cmov
// FIXME: We can do better on 64-bit
val = ibuild.EmitShl(val, samt);
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
val = ibuild.EmitAnd(corr, val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::slwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
samt = ibuild.EmitLoadGReg(inst.RB),
corr;
// FIXME: We can do better with a cmov
// FIXME: We can do better on 64-bit
val = ibuild.EmitShl(val, samt);
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
val = ibuild.EmitAnd(corr, val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::srawx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
// FIXME: We can do a lot better on 64-bit
IREmitter::InstLoc val, samt, mask, mask2, test;
val = ibuild.EmitLoadGReg(inst.RS);
samt = ibuild.EmitLoadGReg(inst.RB);
mask = ibuild.EmitIntConst(-1);
val = ibuild.EmitSarl(val, samt);
mask = ibuild.EmitShl(mask, samt);
samt = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
samt = ibuild.EmitSarl(samt, ibuild.EmitIntConst(31));
samt = ibuild.EmitAnd(samt, ibuild.EmitIntConst(31));
val = ibuild.EmitSarl(val, samt);
ibuild.EmitStoreGReg(val, inst.RA);
mask = ibuild.EmitShl(mask, samt);
mask2 = ibuild.EmitAnd(mask, ibuild.EmitIntConst(0x7FFFFFFF));
test = ibuild.EmitOr(val, mask2);
test = ibuild.EmitICmpUgt(test, mask);
ibuild.EmitStoreCarry(test);
}
void Jit64::srawx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
// FIXME: We can do a lot better on 64-bit
IREmitter::InstLoc val, samt, mask, mask2, test;
val = ibuild.EmitLoadGReg(inst.RS);
samt = ibuild.EmitLoadGReg(inst.RB);
mask = ibuild.EmitIntConst(-1);
val = ibuild.EmitSarl(val, samt);
mask = ibuild.EmitShl(mask, samt);
samt = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
samt = ibuild.EmitSarl(samt, ibuild.EmitIntConst(31));
samt = ibuild.EmitAnd(samt, ibuild.EmitIntConst(31));
val = ibuild.EmitSarl(val, samt);
ibuild.EmitStoreGReg(val, inst.RA);
mask = ibuild.EmitShl(mask, samt);
mask2 = ibuild.EmitAnd(mask, ibuild.EmitIntConst(0x7FFFFFFF));
test = ibuild.EmitOr(val, mask2);
test = ibuild.EmitICmpUgt(test, mask);
ibuild.EmitStoreCarry(test);
}
void Jit64::srawix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS), test;
val = ibuild.EmitSarl(val, ibuild.EmitIntConst(inst.SH));
ibuild.EmitStoreGReg(val, inst.RA);
unsigned int mask = -1u << inst.SH;
test = ibuild.EmitOr(val, ibuild.EmitIntConst(mask & 0x7FFFFFFF));
test = ibuild.EmitICmpUgt(test, ibuild.EmitIntConst(mask));
ibuild.EmitStoreCarry(test);
if (inst.Rc)
ComputeRC(ibuild, val);
}
void Jit64::srawix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS), test;
val = ibuild.EmitSarl(val, ibuild.EmitIntConst(inst.SH));
ibuild.EmitStoreGReg(val, inst.RA);
unsigned int mask = -1u << inst.SH;
test = ibuild.EmitOr(val, ibuild.EmitIntConst(mask & 0x7FFFFFFF));
test = ibuild.EmitICmpUgt(test, ibuild.EmitIntConst(mask));
ibuild.EmitStoreCarry(test);
if (inst.Rc)
ComputeRC(ibuild, val);
}
// count leading zeroes
void Jit64::cntlzwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitCntlzw(val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}
// count leading zeroes
void Jit64::cntlzwx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
val = ibuild.EmitCntlzw(val);
ibuild.EmitStoreGReg(val, inst.RA);
if (inst.Rc)
ComputeRC(ibuild, val);
}

View File

@ -41,6 +41,7 @@
void Jit64::lhax(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStore)
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
if (inst.RA)
@ -53,6 +54,7 @@ void Jit64::lhax(UGeckoInstruction inst)
void Jit64::lXz(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStore)
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
if (inst.RA)
@ -73,6 +75,7 @@ void Jit64::lXz(UGeckoInstruction inst)
void Jit64::lha(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStore)
IREmitter::InstLoc addr =
ibuild.EmitIntConst((s32)(s16)inst.SIMM_16);
@ -86,6 +89,7 @@ void Jit64::lha(UGeckoInstruction inst)
void Jit64::lXzx(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStore)
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
if (inst.RA) {
@ -108,6 +112,8 @@ void Jit64::lXzx(UGeckoInstruction inst)
void Jit64::dcbz(UGeckoInstruction inst)
{
Default(inst); return;
// TODO!
#if 0
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITLoadStoreOff)
{Default(inst); return;} // turn off from debugger
@ -131,6 +137,7 @@ void Jit64::dcbz(UGeckoInstruction inst)
void Jit64::stX(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStore)
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16),
value = ibuild.EmitLoadGReg(inst.RS);
@ -150,6 +157,7 @@ void Jit64::stX(UGeckoInstruction inst)
void Jit64::stXx(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStore)
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB),
value = ibuild.EmitLoadGReg(inst.RS);
@ -169,6 +177,7 @@ void Jit64::stXx(UGeckoInstruction inst)
void Jit64::lmw(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStore)
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
if (inst.RA)
@ -184,6 +193,7 @@ void Jit64::lmw(UGeckoInstruction inst)
void Jit64::stmw(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStore)
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
if (inst.RA)

View File

@ -45,6 +45,7 @@
void Jit64::lfs(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStoreFloating)
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), val;
if (inst.RA)
@ -58,6 +59,7 @@ void Jit64::lfs(UGeckoInstruction inst)
void Jit64::lfd(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStoreFloating)
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), val;
if (inst.RA)
@ -72,6 +74,7 @@ void Jit64::lfd(UGeckoInstruction inst)
void Jit64::stfd(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStoreFloating)
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16),
val = ibuild.EmitLoadFReg(inst.RS);
@ -87,6 +90,7 @@ void Jit64::stfd(UGeckoInstruction inst)
void Jit64::stfs(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStoreFloating)
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16),
val = ibuild.EmitLoadFReg(inst.RS);
@ -103,6 +107,7 @@ void Jit64::stfs(UGeckoInstruction inst)
void Jit64::stfsx(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStoreFloating)
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB),
val = ibuild.EmitLoadFReg(inst.RS);
@ -117,6 +122,7 @@ void Jit64::stfsx(UGeckoInstruction inst)
void Jit64::lfsx(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStoreFloating)
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB), val;
if (inst.RA)

View File

@ -44,6 +44,7 @@
void Jit64::psq_st(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStorePaired)
if (inst.W || !Core::GetStartupParameter().bOptimizeQuantizers) {Default(inst); return;}
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12), val;
@ -59,6 +60,7 @@ void Jit64::psq_st(UGeckoInstruction inst)
void Jit64::psq_l(UGeckoInstruction inst)
{
INSTRUCTION_START
DISABLE64
JITDISABLE(LoadStorePaired)
if (inst.W || !Core::GetStartupParameter().bOptimizeQuantizers) {Default(inst); return;}
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12), val;

View File

@ -26,193 +26,193 @@
#include "Jit.h"
#include "JitRegCache.h"
void Jit64::ps_mr(UGeckoInstruction inst)
{
void Jit64::ps_mr(UGeckoInstruction inst)
{
Default(inst); return;
}
void Jit64::ps_sel(UGeckoInstruction inst)
{
Default(inst); return;
}
void Jit64::ps_sign(UGeckoInstruction inst)
{
Default(inst); return;
}
void Jit64::ps_rsqrte(UGeckoInstruction inst)
{
Default(inst); return;
}
void Jit64::ps_arith(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc || (inst.SUBOP5 != 21 && inst.SUBOP5 != 20 && inst.SUBOP5 != 25)) {
Default(inst); return;
}
void Jit64::ps_sel(UGeckoInstruction inst)
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), rhs;
if (inst.SUBOP5 == 25)
rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
else
rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitCompactMRegToPacked(val);
switch (inst.SUBOP5)
{
Default(inst); return;
}
void Jit64::ps_sign(UGeckoInstruction inst)
{
Default(inst); return;
}
void Jit64::ps_rsqrte(UGeckoInstruction inst)
{
Default(inst); return;
}
void Jit64::ps_arith(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc || (inst.SUBOP5 != 21 && inst.SUBOP5 != 20 && inst.SUBOP5 != 25)) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), rhs;
if (inst.SUBOP5 == 25)
rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
else
rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitCompactMRegToPacked(val);
switch (inst.SUBOP5)
{
case 20:
val = ibuild.EmitFPSub(val, rhs);
break;
case 21:
val = ibuild.EmitFPAdd(val, rhs);
break;
case 25:
val = ibuild.EmitFPMul(val, rhs);
}
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
}
void Jit64::ps_sum(UGeckoInstruction inst)
{
// FIXME: This operation strikes me as a bit strange...
// perhaps we can optimize it depending on the users?
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc || inst.SUBOP5 != 10) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), temp;
val = ibuild.EmitCompactMRegToPacked(val);
val = ibuild.EmitFPDup0(val);
temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, temp);
temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMerge11(val, temp);
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
}
void Jit64::ps_muls(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA),
rhs = ibuild.EmitLoadFReg(inst.FC);
val = ibuild.EmitCompactMRegToPacked(val);
rhs = ibuild.EmitCompactMRegToPacked(rhs);
if (inst.SUBOP5 == 12)
rhs = ibuild.EmitFPDup0(rhs);
else
rhs = ibuild.EmitFPDup1(rhs);
case 20:
val = ibuild.EmitFPSub(val, rhs);
break;
case 21:
val = ibuild.EmitFPAdd(val, rhs);
break;
case 25:
val = ibuild.EmitFPMul(val, rhs);
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
}
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
}
void Jit64::ps_sum(UGeckoInstruction inst)
{
// FIXME: This operation strikes me as a bit strange...
// perhaps we can optimize it depending on the users?
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc || inst.SUBOP5 != 10) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), temp;
val = ibuild.EmitCompactMRegToPacked(val);
val = ibuild.EmitFPDup0(val);
temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, temp);
temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMerge11(val, temp);
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
}
void Jit64::ps_muls(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA),
rhs = ibuild.EmitLoadFReg(inst.FC);
val = ibuild.EmitCompactMRegToPacked(val);
rhs = ibuild.EmitCompactMRegToPacked(rhs);
if (inst.SUBOP5 == 12)
rhs = ibuild.EmitFPDup0(rhs);
else
rhs = ibuild.EmitFPDup1(rhs);
val = ibuild.EmitFPMul(val, rhs);
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
}
//TODO: find easy cases and optimize them, do a breakout like ps_arith
void Jit64::ps_mergeXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FA)),
rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
//TODO: find easy cases and optimize them, do a breakout like ps_arith
void Jit64::ps_mergeXX(UGeckoInstruction inst)
switch (inst.SUBOP10)
{
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FA)),
rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
switch (inst.SUBOP10)
{
case 528:
val = ibuild.EmitFPMerge00(val, rhs);
break; //00
case 560:
val = ibuild.EmitFPMerge01(val, rhs);
break; //01
case 592:
val = ibuild.EmitFPMerge10(val, rhs);
break; //10
case 624:
val = ibuild.EmitFPMerge11(val, rhs);
break; //11
default:
_assert_msg_(DYNA_REC, 0, "ps_merge - invalid op");
}
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
case 528:
val = ibuild.EmitFPMerge00(val, rhs);
break; //00
case 560:
val = ibuild.EmitFPMerge01(val, rhs);
break; //01
case 592:
val = ibuild.EmitFPMerge10(val, rhs);
break; //10
case 624:
val = ibuild.EmitFPMerge11(val, rhs);
break; //11
default:
_assert_msg_(DYNA_REC, 0, "ps_merge - invalid op");
}
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
}
void Jit64::ps_maddXX(UGeckoInstruction inst)
void Jit64::ps_maddXX(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), op2, op3;
val = ibuild.EmitCompactMRegToPacked(val);
switch (inst.SUBOP5)
{
INSTRUCTION_START
JITDISABLE(Paired)
if (inst.Rc) {
Default(inst); return;
}
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), op2, op3;
val = ibuild.EmitCompactMRegToPacked(val);
switch (inst.SUBOP5)
{
case 14: {//madds0
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
op2 = ibuild.EmitFPDup0(op2);
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, op3);
break;
}
case 15: {//madds1
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
op2 = ibuild.EmitFPDup1(op2);
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, op3);
break;
}
case 28: {//msub
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPSub(val, op3);
break;
}
case 29: {//madd
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, op3);
break;
}
case 30: {//nmsub
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPSub(val, op3);
val = ibuild.EmitFPNeg(val);
break;
}
case 31: {//nmadd
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, op3);
val = ibuild.EmitFPNeg(val);
break;
}
}
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
case 14: {//madds0
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
op2 = ibuild.EmitFPDup0(op2);
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, op3);
break;
}
case 15: {//madds1
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
op2 = ibuild.EmitFPDup1(op2);
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, op3);
break;
}
case 28: {//msub
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPSub(val, op3);
break;
}
case 29: {//madd
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, op3);
break;
}
case 30: {//nmsub
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPSub(val, op3);
val = ibuild.EmitFPNeg(val);
break;
}
case 31: {//nmadd
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
val = ibuild.EmitFPMul(val, op2);
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
val = ibuild.EmitFPAdd(val, op3);
val = ibuild.EmitFPNeg(val);
break;
}
}
val = ibuild.EmitExpandPackedToMReg(val);
ibuild.EmitStoreFReg(val, inst.FD);
}