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

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

File diff suppressed because it is too large Load Diff

View File

@ -170,314 +170,314 @@ namespace CPUCompare
extern u32 m_BlockStart; 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;
}

View File

@ -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:

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
} }

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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);
}