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:
parent
46f8178ab1
commit
759263351a
File diff suppressed because it is too large
Load Diff
|
@ -170,314 +170,314 @@ namespace CPUCompare
|
||||||
extern u32 m_BlockStart;
|
extern u32 m_BlockStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit(u32 em_address)
|
void Jit(u32 em_address)
|
||||||
{
|
{
|
||||||
jit.Jit(em_address);
|
jit.Jit(em_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::Init()
|
void Jit64::Init()
|
||||||
{
|
{
|
||||||
asm_routines.compareEnabled = ::Core::g_CoreStartupParameter.bRunCompareClient;
|
asm_routines.compareEnabled = ::Core::g_CoreStartupParameter.bRunCompareClient;
|
||||||
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
|
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
|
||||||
CODE_SIZE = 1024*1024*8*8;
|
CODE_SIZE = 1024*1024*8*8;
|
||||||
|
|
||||||
jo.optimizeStack = true;
|
jo.optimizeStack = true;
|
||||||
jo.enableBlocklink = true; // Speed boost, but not 100% safe
|
jo.enableBlocklink = true; // Speed boost, but not 100% safe
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
#ifdef JITTEST
|
#ifdef JITTEST
|
||||||
jo.enableFastMem = false;
|
jo.enableFastMem = false;
|
||||||
#else
|
#else
|
||||||
jo.enableFastMem = Core::GetStartupParameter().bUseFastMem;
|
jo.enableFastMem = Core::GetStartupParameter().bUseFastMem;
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
jo.enableFastMem = false;
|
jo.enableFastMem = false;
|
||||||
#endif
|
#endif
|
||||||
jo.assumeFPLoadFromMem = true;
|
jo.assumeFPLoadFromMem = true;
|
||||||
jo.fpAccurateFlags = true;
|
jo.fpAccurateFlags = true;
|
||||||
jo.optimizeGatherPipe = true;
|
jo.optimizeGatherPipe = true;
|
||||||
jo.fastInterrupts = false;
|
jo.fastInterrupts = false;
|
||||||
jo.accurateSinglePrecision = false;
|
jo.accurateSinglePrecision = false;
|
||||||
|
|
||||||
gpr.SetEmitter(this);
|
gpr.SetEmitter(this);
|
||||||
fpr.SetEmitter(this);
|
fpr.SetEmitter(this);
|
||||||
|
|
||||||
trampolines.Init();
|
trampolines.Init();
|
||||||
AllocCodeSpace(CODE_SIZE);
|
AllocCodeSpace(CODE_SIZE);
|
||||||
|
|
||||||
blocks.Init();
|
blocks.Init();
|
||||||
asm_routines.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();
|
MOV(32, M(&PC), Imm32(js.compilerPC));
|
||||||
trampolines.ClearCodeSpace();
|
MOV(32, M(&NPC), Imm32(js.compilerPC + 4));
|
||||||
ClearCodeSpace();
|
|
||||||
}
|
}
|
||||||
|
Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst);
|
||||||
void Jit64::Shutdown()
|
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));
|
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)
|
static const bool ImHereDebug = false;
|
||||||
{
|
static const bool ImHereLog = false;
|
||||||
int block_num = blocks.GetBlockNumberFromStartAddress(em_address);
|
static std::map<u32, int> been_here;
|
||||||
if (block_num >= 0)
|
|
||||||
|
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
|
#ifdef _M_X64
|
||||||
f = fopen("log64.txt", "w");
|
f = fopen("log64.txt", "w");
|
||||||
#else
|
#else
|
||||||
f = fopen("log32.txt", "w");
|
f = fopen("log32.txt", "w");
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
fprintf(f, "%08x\n", PC);
|
|
||||||
}
|
}
|
||||||
if (been_here.find(PC) != been_here.end()) {
|
fprintf(f, "%08x\n", PC);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
if (been_here.find(PC) != been_here.end()) {
|
||||||
void Jit64::Cleanup()
|
been_here.find(PC)->second++;
|
||||||
{
|
if ((been_here.find(PC)->second) & 1023)
|
||||||
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
|
return;
|
||||||
ABI_CallFunction((void *)&GPFifo::CheckGatherPipe);
|
|
||||||
}
|
}
|
||||||
|
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();
|
// It exists! Joy of joy!
|
||||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
JMP(blocks.GetBlock(block)->checkedEntry, true);
|
||||||
|
b->linkStatus[exit_num] = true;
|
||||||
//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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
void Jit64::WriteExitDestInEAX(int exit_num)
|
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), Imm32(destination));
|
||||||
Cleanup();
|
|
||||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
|
||||||
JMP(asm_routines.dispatcher, true);
|
JMP(asm_routines.dispatcher, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Jit64::WriteRfiExitDestInEAX()
|
void Jit64::WriteExitDestInEAX(int exit_num)
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
Cleanup();
|
Cleanup();
|
||||||
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||||
JMP(asm_routines.testExceptions, true);
|
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();
|
INFO_LOG(DYNA_REC, "JIT cache full - clearing.")
|
||||||
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(exception));
|
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
|
||||||
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
|
{
|
||||||
JMP(asm_routines.testExceptions, true);
|
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;
|
//This block uses FPU - needs to add FP exception bailout
|
||||||
pExecAddr();
|
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); //Test FP enabled bit
|
||||||
//Will return when PowerPC::state changes
|
FixupBranch b1 = J_CC(CC_NZ);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
MOV(32, M(&PC), Imm32(js.blockStart));
|
MOV(32, M(&PC), Imm32(js.blockStart));
|
||||||
JMP(asm_routines.doTiming, true); // downcount hit zero - go doTiming.
|
JMP(asm_routines.fpException, true);
|
||||||
SetJumpTarget(skip);
|
SetJumpTarget(b1);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -71,6 +71,14 @@ struct CONTEXT
|
||||||
Core::g_CoreStartupParameter.bJIT##type##Off) \
|
Core::g_CoreStartupParameter.bJIT##type##Off) \
|
||||||
{Default(inst); return;}
|
{Default(inst); return;}
|
||||||
|
|
||||||
|
#ifdef _M_X64
|
||||||
|
#define DISABLE64 \
|
||||||
|
{Default(inst); return;}
|
||||||
|
#else
|
||||||
|
#define DISABLE64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class TrampolineCache : public Gen::XCodeBlock
|
class TrampolineCache : public Gen::XCodeBlock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -45,150 +45,149 @@
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
void Jit64::sc(UGeckoInstruction inst)
|
void Jit64::sc(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC));
|
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)
|
if ((inst.BO & 4) == 0) {
|
||||||
{
|
IREmitter::InstLoc c = ibuild.EmitLoadCTR();
|
||||||
NORMALBRANCH_START
|
c = ibuild.EmitSub(c, ibuild.EmitIntConst(1));
|
||||||
INSTRUCTION_START;
|
ibuild.EmitStoreCTR(c);
|
||||||
|
if (inst.BO & 2) {
|
||||||
if (inst.LK)
|
CTRTest = ibuild.EmitICmpEq(c,
|
||||||
ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4));
|
ibuild.EmitIntConst(0));
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
} 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
|
ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination));
|
||||||
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.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);
|
||||||
|
}
|
||||||
|
|
|
@ -28,86 +28,86 @@
|
||||||
//#define INSTRUCTION_START Default(inst); return;
|
//#define INSTRUCTION_START Default(inst); return;
|
||||||
#define INSTRUCTION_START
|
#define INSTRUCTION_START
|
||||||
|
|
||||||
void Jit64::fp_arith_s(UGeckoInstruction inst)
|
void Jit64::fp_arith_s(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(FloatingPoint)
|
JITDISABLE(FloatingPoint)
|
||||||
if (inst.Rc || (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);
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
|
||||||
void Jit64::fmaddXX(UGeckoInstruction inst)
|
switch (inst.SUBOP5)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
case 25: //mul
|
||||||
JITDISABLE(FloatingPoint)
|
|
||||||
if (inst.Rc) {
|
|
||||||
Default(inst); return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA);
|
|
||||||
val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
|
val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC));
|
||||||
if (inst.SUBOP5 & 1)
|
break;
|
||||||
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
|
case 18: //div
|
||||||
else
|
case 20: //sub
|
||||||
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
|
val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB));
|
||||||
if (inst.SUBOP5 & 2)
|
break;
|
||||||
val = ibuild.EmitFDNeg(val);
|
case 21: //add
|
||||||
if (inst.OPCD == 59) {
|
val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB));
|
||||||
val = ibuild.EmitDoubleToSingle(val);
|
break;
|
||||||
val = ibuild.EmitDupSingleToMReg(val);
|
case 23: //sel
|
||||||
} else {
|
case 24: //res
|
||||||
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
|
default:
|
||||||
}
|
_assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!");
|
||||||
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)
|
if (inst.OPCD == 59) {
|
||||||
{
|
val = ibuild.EmitDoubleToSingle(val);
|
||||||
INSTRUCTION_START
|
val = ibuild.EmitDupSingleToMReg(val);
|
||||||
JITDISABLE(FloatingPoint)
|
} else {
|
||||||
IREmitter::InstLoc lhs, rhs, res;
|
val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD));
|
||||||
lhs = ibuild.EmitLoadFRegDENToZero(inst.FA);
|
|
||||||
rhs = ibuild.EmitLoadFRegDENToZero(inst.FB);
|
|
||||||
res = ibuild.EmitFDCmpCR(lhs, rhs);
|
|
||||||
ibuild.EmitStoreFPRF(res);
|
|
||||||
ibuild.EmitStoreCR(res, inst.CRFD);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -31,514 +31,514 @@
|
||||||
//#define INSTRUCTION_START Default(inst); return;
|
//#define INSTRUCTION_START Default(inst); return;
|
||||||
#define INSTRUCTION_START
|
#define INSTRUCTION_START
|
||||||
|
|
||||||
static void ComputeRC(IREmitter::IRBuilder& ibuild,
|
static void ComputeRC(IREmitter::IRBuilder& ibuild,
|
||||||
IREmitter::InstLoc val) {
|
IREmitter::InstLoc val) {
|
||||||
IREmitter::InstLoc res =
|
IREmitter::InstLoc res =
|
||||||
ibuild.EmitICmpCRSigned(val, ibuild.EmitIntConst(0));
|
ibuild.EmitICmpCRSigned(val, ibuild.EmitIntConst(0));
|
||||||
ibuild.EmitStoreCR(res, 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
|
case 14: //addi
|
||||||
JITDISABLE(Integer)
|
val = ibuild.EmitIntConst(inst.SIMM_16);
|
||||||
int d = inst.RD, a = inst.RA, s = inst.RS;
|
if (a)
|
||||||
IREmitter::InstLoc val, test, c;
|
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
|
||||||
switch (inst.OPCD)
|
ibuild.EmitStoreGReg(val, d);
|
||||||
{
|
break;
|
||||||
case 14: //addi
|
case 15: //addis
|
||||||
val = ibuild.EmitIntConst(inst.SIMM_16);
|
val = ibuild.EmitIntConst(inst.SIMM_16 << 16);
|
||||||
if (a)
|
if (a)
|
||||||
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
|
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
|
||||||
ibuild.EmitStoreGReg(val, d);
|
ibuild.EmitStoreGReg(val, d);
|
||||||
break;
|
break;
|
||||||
case 15: //addis
|
case 24: //ori
|
||||||
val = ibuild.EmitIntConst(inst.SIMM_16 << 16);
|
val = ibuild.EmitIntConst(inst.UIMM);
|
||||||
if (a)
|
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
|
||||||
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
|
ibuild.EmitStoreGReg(val, a);
|
||||||
ibuild.EmitStoreGReg(val, d);
|
break;
|
||||||
break;
|
case 25: //oris
|
||||||
case 24: //ori
|
val = ibuild.EmitIntConst(inst.UIMM << 16);
|
||||||
val = ibuild.EmitIntConst(inst.UIMM);
|
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
|
||||||
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
|
ibuild.EmitStoreGReg(val, a);
|
||||||
ibuild.EmitStoreGReg(val, a);
|
break;
|
||||||
break;
|
case 28: //andi
|
||||||
case 25: //oris
|
val = ibuild.EmitIntConst(inst.UIMM);
|
||||||
val = ibuild.EmitIntConst(inst.UIMM << 16);
|
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
|
||||||
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
|
ibuild.EmitStoreGReg(val, a);
|
||||||
ibuild.EmitStoreGReg(val, a);
|
ComputeRC(ibuild, val);
|
||||||
break;
|
break;
|
||||||
case 28: //andi
|
case 29: //andis
|
||||||
val = ibuild.EmitIntConst(inst.UIMM);
|
val = ibuild.EmitIntConst(inst.UIMM << 16);
|
||||||
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
|
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
|
||||||
ibuild.EmitStoreGReg(val, a);
|
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);
|
ComputeRC(ibuild, val);
|
||||||
break;
|
break;
|
||||||
case 29: //andis
|
default:
|
||||||
val = ibuild.EmitIntConst(inst.UIMM << 16);
|
Default(inst);
|
||||||
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
|
break;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Jit64::cmpXX(UGeckoInstruction inst)
|
void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc lhs, rhs, res;
|
IREmitter::InstLoc lhs, rhs, res;
|
||||||
lhs = ibuild.EmitLoadGReg(inst.RA);
|
lhs = ibuild.EmitLoadGReg(inst.RA);
|
||||||
if (inst.OPCD == 31) {
|
if (inst.OPCD == 31) {
|
||||||
rhs = ibuild.EmitLoadGReg(inst.RB);
|
rhs = ibuild.EmitLoadGReg(inst.RB);
|
||||||
if (inst.SUBOP10 == 32) {
|
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);
|
|
||||||
res = ibuild.EmitICmpCRUnsigned(lhs, rhs);
|
res = ibuild.EmitICmpCRUnsigned(lhs, rhs);
|
||||||
} else { // inst.OPCD == 11
|
} else {
|
||||||
rhs = ibuild.EmitIntConst(inst.SIMM_16);
|
|
||||||
res = ibuild.EmitICmpCRSigned(lhs, rhs);
|
res = ibuild.EmitICmpCRSigned(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
} else if (inst.OPCD == 10) {
|
||||||
ibuild.EmitStoreCR(res, inst.CRFD);
|
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];
|
ibuild.EmitStoreCR(res, inst.CRFD);
|
||||||
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::andx(UGeckoInstruction inst)
|
void Jit64::orx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||||
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(inst.RS), val);
|
val = ibuild.EmitOr(ibuild.EmitLoadGReg(inst.RS), val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
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)
|
// m_GPR[_inst.RA] = m_GPR[_inst.RS] ^ m_GPR[_inst.RB];
|
||||||
{
|
void Jit64::xorx(UGeckoInstruction inst)
|
||||||
INSTRUCTION_START
|
{
|
||||||
JITDISABLE(Integer)
|
INSTRUCTION_START
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
JITDISABLE(Integer)
|
||||||
val = ibuild.EmitSExt16(val);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
val = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RS), val);
|
||||||
if (inst.Rc)
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
ComputeRC(ibuild, val);
|
if (inst.Rc)
|
||||||
}
|
ComputeRC(ibuild, val);
|
||||||
|
}
|
||||||
|
|
||||||
void Jit64::subfic(UGeckoInstruction inst)
|
void Jit64::andx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc nota, lhs, val, test;
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||||
nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA),
|
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(inst.RS), val);
|
||||||
ibuild.EmitIntConst(-1));
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
if (inst.SIMM_16 == -1) {
|
if (inst.Rc)
|
||||||
val = nota;
|
ComputeRC(ibuild, val);
|
||||||
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::subfcx(UGeckoInstruction inst)
|
void Jit64::extsbx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
if (inst.OE) PanicAlert("OE: subfcx");
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
IREmitter::InstLoc val, test, lhs, rhs;
|
val = ibuild.EmitSExt8(val);
|
||||||
lhs = ibuild.EmitLoadGReg(inst.RB);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
rhs = ibuild.EmitLoadGReg(inst.RA);
|
if (inst.Rc)
|
||||||
val = ibuild.EmitSub(lhs, rhs);
|
ComputeRC(ibuild, val);
|
||||||
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::subfex(UGeckoInstruction inst)
|
void Jit64::extshx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
if (inst.OE) PanicAlert("OE: subfex");
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
IREmitter::InstLoc val, test, lhs, rhs, carry;
|
val = ibuild.EmitSExt16(val);
|
||||||
rhs = ibuild.EmitLoadGReg(inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
carry = ibuild.EmitLoadCarry();
|
if (inst.Rc)
|
||||||
rhs = ibuild.EmitXor(rhs, ibuild.EmitIntConst(-1));
|
ComputeRC(ibuild, val);
|
||||||
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::subfx(UGeckoInstruction inst)
|
void Jit64::subfic(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
if (inst.OE) PanicAlert("OE: subfx");
|
IREmitter::InstLoc nota, lhs, val, test;
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA),
|
||||||
val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA));
|
ibuild.EmitIntConst(-1));
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
if (inst.SIMM_16 == -1) {
|
||||||
if (inst.Rc)
|
val = nota;
|
||||||
ComputeRC(ibuild, val);
|
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)
|
void Jit64::subfcx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
|
if (inst.OE) PanicAlert("OE: subfcx");
|
||||||
val = ibuild.EmitMul(val, ibuild.EmitIntConst(inst.SIMM_16));
|
IREmitter::InstLoc val, test, lhs, rhs;
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
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)
|
void Jit64::subfex(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
if (inst.OE) PanicAlert("OE: subfex");
|
||||||
val = ibuild.EmitMul(ibuild.EmitLoadGReg(inst.RA), val);
|
IREmitter::InstLoc val, test, lhs, rhs, carry;
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
rhs = ibuild.EmitLoadGReg(inst.RA);
|
||||||
if (inst.Rc)
|
carry = ibuild.EmitLoadCarry();
|
||||||
ComputeRC(ibuild, val);
|
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)
|
void Jit64::subfx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
Default(inst); return;
|
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 0
|
||||||
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITIntegerOff)
|
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITIntegerOff)
|
||||||
{Default(inst); return;} // turn off from debugger
|
{Default(inst); return;} // turn off from debugger
|
||||||
|
|
||||||
INSTRUCTION_START;
|
INSTRUCTION_START;
|
||||||
int a = inst.RA, b = inst.RB, d = inst.RD;
|
int a = inst.RA, b = inst.RB, d = inst.RD;
|
||||||
gpr.FlushLockX(EDX);
|
gpr.FlushLockX(EDX);
|
||||||
gpr.Lock(a, b, d);
|
gpr.Lock(a, b, d);
|
||||||
if (d != a && d != b) {
|
if (d != a && d != b) {
|
||||||
gpr.LoadToX64(d, false, true);
|
gpr.LoadToX64(d, false, true);
|
||||||
} else {
|
} else {
|
||||||
gpr.LoadToX64(d, true, true);
|
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
|
|
||||||
}
|
}
|
||||||
|
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
|
// skipped some of the special handling in here - if we get crashes, let the interpreter handle this op
|
||||||
void Jit64::divwux(UGeckoInstruction inst) {
|
void Jit64::divwux(UGeckoInstruction inst) {
|
||||||
Default(inst); return;
|
Default(inst); return;
|
||||||
#if 0
|
#if 0
|
||||||
int a = inst.RA, b = inst.RB, d = inst.RD;
|
int a = inst.RA, b = inst.RB, d = inst.RD;
|
||||||
gpr.FlushLockX(EDX);
|
gpr.FlushLockX(EDX);
|
||||||
gpr.Lock(a, b, d);
|
gpr.Lock(a, b, d);
|
||||||
if (d != a && d != b) {
|
if (d != a && d != b) {
|
||||||
gpr.LoadToX64(d, false, true);
|
gpr.LoadToX64(d, false, true);
|
||||||
} else {
|
} else {
|
||||||
gpr.LoadToX64(d, true, true);
|
gpr.LoadToX64(d, true, true);
|
||||||
}
|
}
|
||||||
MOV(32, R(EAX), gpr.R(a));
|
MOV(32, R(EAX), gpr.R(a));
|
||||||
XOR(32, R(EDX), R(EDX));
|
XOR(32, R(EDX), R(EDX));
|
||||||
gpr.KillImmediate(b);
|
gpr.KillImmediate(b);
|
||||||
DIV(32, gpr.R(b));
|
DIV(32, gpr.R(b));
|
||||||
MOV(32, gpr.R(d), R(EAX));
|
MOV(32, gpr.R(d), R(EAX));
|
||||||
gpr.UnlockAll();
|
gpr.UnlockAll();
|
||||||
gpr.UnlockAllX();
|
gpr.UnlockAllX();
|
||||||
if (inst.Rc) {
|
if (inst.Rc) {
|
||||||
CALL((u8*)asm_routines.computeRc);
|
CALL((u8*)asm_routines.computeRc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Helper_Mask(u8 mb, u8 me)
|
u32 Helper_Mask(u8 mb, u8 me)
|
||||||
{
|
{
|
||||||
return (((mb > 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)-1 >> mb) ^ ((me >= 31) ? 0 : (u32) -1 >> (me + 1))))
|
(((u32)-1 >> mb) ^ ((me >= 31) ? 0 : (u32) -1 >> (me + 1))))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::addx(UGeckoInstruction inst)
|
void Jit64::addx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
|
||||||
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val);
|
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::addzex(UGeckoInstruction inst)
|
void Jit64::addzex(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA),
|
IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA),
|
||||||
val, newcarry;
|
val, newcarry;
|
||||||
val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry());
|
val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry());
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
newcarry = ibuild.EmitICmpUlt(val, lhs);
|
newcarry = ibuild.EmitICmpUlt(val, lhs);
|
||||||
ibuild.EmitStoreCarry(newcarry);
|
ibuild.EmitStoreCarry(newcarry);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
// This can be optimized
|
// This can be optimized
|
||||||
void Jit64::addex(UGeckoInstruction inst)
|
void Jit64::addex(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
Default(inst); return;
|
Default(inst); return;
|
||||||
#if 0
|
#if 0
|
||||||
// USES_XER
|
// USES_XER
|
||||||
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITIntegerOff)
|
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITIntegerOff)
|
||||||
{Default(inst); return;} // turn off from debugger
|
{Default(inst); return;} // turn off from debugger
|
||||||
|
|
||||||
INSTRUCTION_START;
|
INSTRUCTION_START;
|
||||||
int a = inst.RA, b = inst.RB, d = inst.RD;
|
int a = inst.RA, b = inst.RB, d = inst.RD;
|
||||||
gpr.FlushLockX(ECX);
|
gpr.FlushLockX(ECX);
|
||||||
gpr.Lock(a, b, d);
|
gpr.Lock(a, b, d);
|
||||||
if (d != a && d != b)
|
if (d != a && d != b)
|
||||||
gpr.LoadToX64(d, false);
|
gpr.LoadToX64(d, false);
|
||||||
else
|
else
|
||||||
gpr.LoadToX64(d, true);
|
gpr.LoadToX64(d, true);
|
||||||
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
|
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
|
SHR(32, R(EAX), Imm8(30)); // shift the carry flag out into the x86 carry flag
|
||||||
MOV(32, R(EAX), gpr.R(a));
|
MOV(32, R(EAX), gpr.R(a));
|
||||||
ADC(32, R(EAX), gpr.R(b));
|
ADC(32, R(EAX), gpr.R(b));
|
||||||
MOV(32, gpr.R(d), R(EAX));
|
MOV(32, gpr.R(d), R(EAX));
|
||||||
//GenerateCarry(ECX);
|
//GenerateCarry(ECX);
|
||||||
gpr.UnlockAll();
|
gpr.UnlockAll();
|
||||||
gpr.UnlockAllX();
|
gpr.UnlockAllX();
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
{
|
{
|
||||||
CALL((u8*)asm_routines.computeRc);
|
CALL((u8*)asm_routines.computeRc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::rlwinmx(UGeckoInstruction inst)
|
void Jit64::rlwinmx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
unsigned mask = Helper_Mask(inst.MB, inst.ME);
|
unsigned mask = Helper_Mask(inst.MB, inst.ME);
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
|
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
|
||||||
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Jit64::rlwimix(UGeckoInstruction inst)
|
void Jit64::rlwimix(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
unsigned mask = Helper_Mask(inst.MB, inst.ME);
|
unsigned mask = Helper_Mask(inst.MB, inst.ME);
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
|
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
|
||||||
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
||||||
IREmitter::InstLoc ival = ibuild.EmitLoadGReg(inst.RA);
|
IREmitter::InstLoc ival = ibuild.EmitLoadGReg(inst.RA);
|
||||||
ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask));
|
ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask));
|
||||||
val = ibuild.EmitOr(ival, val);
|
val = ibuild.EmitOr(ival, val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::rlwnmx(UGeckoInstruction inst)
|
void Jit64::rlwnmx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
unsigned int mask = Helper_Mask(inst.MB, inst.ME);
|
unsigned int mask = Helper_Mask(inst.MB, inst.ME);
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB));
|
val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB));
|
||||||
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::negx(UGeckoInstruction inst)
|
void Jit64::negx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
|
||||||
val = ibuild.EmitSub(ibuild.EmitIntConst(0), val);
|
val = ibuild.EmitSub(ibuild.EmitIntConst(0), val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RD);
|
ibuild.EmitStoreGReg(val, inst.RD);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::srwx(UGeckoInstruction inst)
|
void Jit64::srwx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
|
||||||
samt = ibuild.EmitLoadGReg(inst.RB),
|
samt = ibuild.EmitLoadGReg(inst.RB),
|
||||||
corr;
|
corr;
|
||||||
// FIXME: We can do better with a cmov
|
// FIXME: We can do better with a cmov
|
||||||
// FIXME: We can do better on 64-bit
|
// FIXME: We can do better on 64-bit
|
||||||
val = ibuild.EmitShrl(val, samt);
|
val = ibuild.EmitShrl(val, samt);
|
||||||
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
|
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
|
||||||
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
|
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
|
||||||
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
||||||
val = ibuild.EmitAnd(corr, val);
|
val = ibuild.EmitAnd(corr, val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::slwx(UGeckoInstruction inst)
|
void Jit64::slwx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
|
||||||
samt = ibuild.EmitLoadGReg(inst.RB),
|
samt = ibuild.EmitLoadGReg(inst.RB),
|
||||||
corr;
|
corr;
|
||||||
// FIXME: We can do better with a cmov
|
// FIXME: We can do better with a cmov
|
||||||
// FIXME: We can do better on 64-bit
|
// FIXME: We can do better on 64-bit
|
||||||
val = ibuild.EmitShl(val, samt);
|
val = ibuild.EmitShl(val, samt);
|
||||||
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
|
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
|
||||||
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
|
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
|
||||||
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
|
||||||
val = ibuild.EmitAnd(corr, val);
|
val = ibuild.EmitAnd(corr, val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::srawx(UGeckoInstruction inst)
|
void Jit64::srawx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
// FIXME: We can do a lot better on 64-bit
|
// FIXME: We can do a lot better on 64-bit
|
||||||
IREmitter::InstLoc val, samt, mask, mask2, test;
|
IREmitter::InstLoc val, samt, mask, mask2, test;
|
||||||
val = ibuild.EmitLoadGReg(inst.RS);
|
val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
samt = ibuild.EmitLoadGReg(inst.RB);
|
samt = ibuild.EmitLoadGReg(inst.RB);
|
||||||
mask = ibuild.EmitIntConst(-1);
|
mask = ibuild.EmitIntConst(-1);
|
||||||
val = ibuild.EmitSarl(val, samt);
|
val = ibuild.EmitSarl(val, samt);
|
||||||
mask = ibuild.EmitShl(mask, samt);
|
mask = ibuild.EmitShl(mask, samt);
|
||||||
samt = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
|
samt = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
|
||||||
samt = ibuild.EmitSarl(samt, ibuild.EmitIntConst(31));
|
samt = ibuild.EmitSarl(samt, ibuild.EmitIntConst(31));
|
||||||
samt = ibuild.EmitAnd(samt, ibuild.EmitIntConst(31));
|
samt = ibuild.EmitAnd(samt, ibuild.EmitIntConst(31));
|
||||||
val = ibuild.EmitSarl(val, samt);
|
val = ibuild.EmitSarl(val, samt);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
mask = ibuild.EmitShl(mask, samt);
|
mask = ibuild.EmitShl(mask, samt);
|
||||||
mask2 = ibuild.EmitAnd(mask, ibuild.EmitIntConst(0x7FFFFFFF));
|
mask2 = ibuild.EmitAnd(mask, ibuild.EmitIntConst(0x7FFFFFFF));
|
||||||
test = ibuild.EmitOr(val, mask2);
|
test = ibuild.EmitOr(val, mask2);
|
||||||
test = ibuild.EmitICmpUgt(test, mask);
|
test = ibuild.EmitICmpUgt(test, mask);
|
||||||
ibuild.EmitStoreCarry(test);
|
ibuild.EmitStoreCarry(test);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::srawix(UGeckoInstruction inst)
|
void Jit64::srawix(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS), test;
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS), test;
|
||||||
val = ibuild.EmitSarl(val, ibuild.EmitIntConst(inst.SH));
|
val = ibuild.EmitSarl(val, ibuild.EmitIntConst(inst.SH));
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
unsigned int mask = -1u << inst.SH;
|
unsigned int mask = -1u << inst.SH;
|
||||||
test = ibuild.EmitOr(val, ibuild.EmitIntConst(mask & 0x7FFFFFFF));
|
test = ibuild.EmitOr(val, ibuild.EmitIntConst(mask & 0x7FFFFFFF));
|
||||||
test = ibuild.EmitICmpUgt(test, ibuild.EmitIntConst(mask));
|
test = ibuild.EmitICmpUgt(test, ibuild.EmitIntConst(mask));
|
||||||
|
|
||||||
ibuild.EmitStoreCarry(test);
|
ibuild.EmitStoreCarry(test);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
// count leading zeroes
|
// count leading zeroes
|
||||||
void Jit64::cntlzwx(UGeckoInstruction inst)
|
void Jit64::cntlzwx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(Integer)
|
JITDISABLE(Integer)
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
|
||||||
val = ibuild.EmitCntlzw(val);
|
val = ibuild.EmitCntlzw(val);
|
||||||
ibuild.EmitStoreGReg(val, inst.RA);
|
ibuild.EmitStoreGReg(val, inst.RA);
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC(ibuild, val);
|
ComputeRC(ibuild, val);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
void Jit64::lhax(UGeckoInstruction inst)
|
void Jit64::lhax(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStore)
|
JITDISABLE(LoadStore)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
|
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
|
||||||
if (inst.RA)
|
if (inst.RA)
|
||||||
|
@ -53,6 +54,7 @@ void Jit64::lhax(UGeckoInstruction inst)
|
||||||
void Jit64::lXz(UGeckoInstruction inst)
|
void Jit64::lXz(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStore)
|
JITDISABLE(LoadStore)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||||
if (inst.RA)
|
if (inst.RA)
|
||||||
|
@ -73,6 +75,7 @@ void Jit64::lXz(UGeckoInstruction inst)
|
||||||
void Jit64::lha(UGeckoInstruction inst)
|
void Jit64::lha(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStore)
|
JITDISABLE(LoadStore)
|
||||||
IREmitter::InstLoc addr =
|
IREmitter::InstLoc addr =
|
||||||
ibuild.EmitIntConst((s32)(s16)inst.SIMM_16);
|
ibuild.EmitIntConst((s32)(s16)inst.SIMM_16);
|
||||||
|
@ -86,6 +89,7 @@ void Jit64::lha(UGeckoInstruction inst)
|
||||||
void Jit64::lXzx(UGeckoInstruction inst)
|
void Jit64::lXzx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStore)
|
JITDISABLE(LoadStore)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
|
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB);
|
||||||
if (inst.RA) {
|
if (inst.RA) {
|
||||||
|
@ -108,6 +112,8 @@ void Jit64::lXzx(UGeckoInstruction inst)
|
||||||
void Jit64::dcbz(UGeckoInstruction inst)
|
void Jit64::dcbz(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
Default(inst); return;
|
Default(inst); return;
|
||||||
|
|
||||||
|
// TODO!
|
||||||
#if 0
|
#if 0
|
||||||
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITLoadStoreOff)
|
if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITLoadStoreOff)
|
||||||
{Default(inst); return;} // turn off from debugger
|
{Default(inst); return;} // turn off from debugger
|
||||||
|
@ -131,6 +137,7 @@ void Jit64::dcbz(UGeckoInstruction inst)
|
||||||
void Jit64::stX(UGeckoInstruction inst)
|
void Jit64::stX(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStore)
|
JITDISABLE(LoadStore)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16),
|
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16),
|
||||||
value = ibuild.EmitLoadGReg(inst.RS);
|
value = ibuild.EmitLoadGReg(inst.RS);
|
||||||
|
@ -150,6 +157,7 @@ void Jit64::stX(UGeckoInstruction inst)
|
||||||
void Jit64::stXx(UGeckoInstruction inst)
|
void Jit64::stXx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStore)
|
JITDISABLE(LoadStore)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB),
|
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB),
|
||||||
value = ibuild.EmitLoadGReg(inst.RS);
|
value = ibuild.EmitLoadGReg(inst.RS);
|
||||||
|
@ -169,6 +177,7 @@ void Jit64::stXx(UGeckoInstruction inst)
|
||||||
void Jit64::lmw(UGeckoInstruction inst)
|
void Jit64::lmw(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStore)
|
JITDISABLE(LoadStore)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||||
if (inst.RA)
|
if (inst.RA)
|
||||||
|
@ -184,6 +193,7 @@ void Jit64::lmw(UGeckoInstruction inst)
|
||||||
void Jit64::stmw(UGeckoInstruction inst)
|
void Jit64::stmw(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStore)
|
JITDISABLE(LoadStore)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||||
if (inst.RA)
|
if (inst.RA)
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
void Jit64::lfs(UGeckoInstruction inst)
|
void Jit64::lfs(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStoreFloating)
|
JITDISABLE(LoadStoreFloating)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), val;
|
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), val;
|
||||||
if (inst.RA)
|
if (inst.RA)
|
||||||
|
@ -58,6 +59,7 @@ void Jit64::lfs(UGeckoInstruction inst)
|
||||||
void Jit64::lfd(UGeckoInstruction inst)
|
void Jit64::lfd(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStoreFloating)
|
JITDISABLE(LoadStoreFloating)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), val;
|
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), val;
|
||||||
if (inst.RA)
|
if (inst.RA)
|
||||||
|
@ -72,6 +74,7 @@ void Jit64::lfd(UGeckoInstruction inst)
|
||||||
void Jit64::stfd(UGeckoInstruction inst)
|
void Jit64::stfd(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStoreFloating)
|
JITDISABLE(LoadStoreFloating)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16),
|
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16),
|
||||||
val = ibuild.EmitLoadFReg(inst.RS);
|
val = ibuild.EmitLoadFReg(inst.RS);
|
||||||
|
@ -87,6 +90,7 @@ void Jit64::stfd(UGeckoInstruction inst)
|
||||||
void Jit64::stfs(UGeckoInstruction inst)
|
void Jit64::stfs(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStoreFloating)
|
JITDISABLE(LoadStoreFloating)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16),
|
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16),
|
||||||
val = ibuild.EmitLoadFReg(inst.RS);
|
val = ibuild.EmitLoadFReg(inst.RS);
|
||||||
|
@ -103,6 +107,7 @@ void Jit64::stfs(UGeckoInstruction inst)
|
||||||
void Jit64::stfsx(UGeckoInstruction inst)
|
void Jit64::stfsx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStoreFloating)
|
JITDISABLE(LoadStoreFloating)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB),
|
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB),
|
||||||
val = ibuild.EmitLoadFReg(inst.RS);
|
val = ibuild.EmitLoadFReg(inst.RS);
|
||||||
|
@ -117,6 +122,7 @@ void Jit64::stfsx(UGeckoInstruction inst)
|
||||||
void Jit64::lfsx(UGeckoInstruction inst)
|
void Jit64::lfsx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStoreFloating)
|
JITDISABLE(LoadStoreFloating)
|
||||||
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB), val;
|
IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB), val;
|
||||||
if (inst.RA)
|
if (inst.RA)
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
void Jit64::psq_st(UGeckoInstruction inst)
|
void Jit64::psq_st(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStorePaired)
|
JITDISABLE(LoadStorePaired)
|
||||||
if (inst.W || !Core::GetStartupParameter().bOptimizeQuantizers) {Default(inst); return;}
|
if (inst.W || !Core::GetStartupParameter().bOptimizeQuantizers) {Default(inst); return;}
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12), val;
|
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)
|
void Jit64::psq_l(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
|
DISABLE64
|
||||||
JITDISABLE(LoadStorePaired)
|
JITDISABLE(LoadStorePaired)
|
||||||
if (inst.W || !Core::GetStartupParameter().bOptimizeQuantizers) {Default(inst); return;}
|
if (inst.W || !Core::GetStartupParameter().bOptimizeQuantizers) {Default(inst); return;}
|
||||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12), val;
|
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12), val;
|
||||||
|
|
|
@ -26,193 +26,193 @@
|
||||||
#include "Jit.h"
|
#include "Jit.h"
|
||||||
#include "JitRegCache.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;
|
Default(inst); return;
|
||||||
}
|
}
|
||||||
|
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), rhs;
|
||||||
void Jit64::ps_sel(UGeckoInstruction inst)
|
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;
|
case 20:
|
||||||
}
|
val = ibuild.EmitFPSub(val, rhs);
|
||||||
|
break;
|
||||||
void Jit64::ps_sign(UGeckoInstruction inst)
|
case 21:
|
||||||
{
|
val = ibuild.EmitFPAdd(val, rhs);
|
||||||
Default(inst); return;
|
break;
|
||||||
}
|
case 25:
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
val = ibuild.EmitFPMul(val, rhs);
|
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
|
switch (inst.SUBOP10)
|
||||||
void Jit64::ps_mergeXX(UGeckoInstruction inst)
|
|
||||||
{
|
{
|
||||||
INSTRUCTION_START
|
case 528:
|
||||||
JITDISABLE(Paired)
|
val = ibuild.EmitFPMerge00(val, rhs);
|
||||||
if (inst.Rc) {
|
break; //00
|
||||||
Default(inst); return;
|
case 560:
|
||||||
}
|
val = ibuild.EmitFPMerge01(val, rhs);
|
||||||
|
break; //01
|
||||||
IREmitter::InstLoc val = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FA)),
|
case 592:
|
||||||
rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
val = ibuild.EmitFPMerge10(val, rhs);
|
||||||
|
break; //10
|
||||||
switch (inst.SUBOP10)
|
case 624:
|
||||||
{
|
val = ibuild.EmitFPMerge11(val, rhs);
|
||||||
case 528:
|
break; //11
|
||||||
val = ibuild.EmitFPMerge00(val, rhs);
|
default:
|
||||||
break; //00
|
_assert_msg_(DYNA_REC, 0, "ps_merge - invalid op");
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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
|
case 14: {//madds0
|
||||||
JITDISABLE(Paired)
|
op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC));
|
||||||
if (inst.Rc) {
|
op2 = ibuild.EmitFPDup0(op2);
|
||||||
Default(inst); return;
|
val = ibuild.EmitFPMul(val, op2);
|
||||||
}
|
op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB));
|
||||||
|
val = ibuild.EmitFPAdd(val, op3);
|
||||||
IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), op2, op3;
|
break;
|
||||||
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 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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue