Merge pull request #527 from delroth/flags-opt

[RFC] PowerPC flags emulation optimization
This commit is contained in:
Lioncash
2014-07-31 02:51:48 -04:00
40 changed files with 929 additions and 3300 deletions
-1
View File
@@ -137,7 +137,6 @@
<string name="jit64_recompiler">JIT64 Recompiler</string>
<string name="jitil_recompiler">JITIL Recompiler</string>
<string name="jit_arm_recompiler">JIT ARM Recompiler</string>
<string name="jitil_arm_recompiler">JITIL ARM Recompiler</string>
<string name="cpu_settings">CPU</string>
<string name="cpu_core">CPUコア</string>
<string name="cpu_core_desc">%s</string>
-2
View File
@@ -19,12 +19,10 @@
<string-array name="emuCoreEntriesARM" translatable="false">
<item>@string/interpreter</item>
<item>@string/jit_arm_recompiler</item>
<item>@string/jitil_arm_recompiler</item>
</string-array>
<string-array name="emuCoreValuesARM" translatable="false">
<item>0</item>
<item>3</item>
<item>4</item>
</string-array>
<!-- CPU core selection - Other -->
-1
View File
@@ -138,7 +138,6 @@
<string name="jit64_recompiler">JIT64 Recompiler</string>
<string name="jitil_recompiler">JITIL Recompiler</string>
<string name="jit_arm_recompiler">JIT ARM Recompiler</string>
<string name="jitil_arm_recompiler">JITIL ARM Recompiler</string>
<string name="cpu_settings">CPU</string>
<string name="cpu_core">CPU Core</string>
<string name="cpu_core_desc">%s</string>
+1 -1
View File
@@ -721,7 +721,7 @@ void XEmitter::SETcc(CCFlags flag, OpArg dest)
{
if (dest.IsImm()) _assert_msg_(DYNA_REC, 0, "SETcc - Imm argument");
dest.operandReg = 0;
dest.WriteRex(this, 0, 0);
dest.WriteRex(this, 0, 8);
Write8(0x0F);
Write8(0x90 + (u8)flag);
dest.WriteRest(this);
-6
View File
@@ -218,12 +218,6 @@ if(_M_ARM_32)
PowerPC/JitArm32/JitArm_LoadStorePaired.cpp
PowerPC/JitArm32/JitArm_SystemRegisters.cpp
PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp
#JitArmIL
PowerPC/JitArmIL/JitIL.cpp
PowerPC/JitArmIL/JitILAsm.cpp
PowerPC/JitArmIL/JitIL_Tables.cpp
PowerPC/JitArmIL/JitIL_Branch.cpp
PowerPC/JitArmIL/IR_Arm.cpp
)
endif()
@@ -84,7 +84,7 @@ static void Trace(UGeckoInstruction& instCode)
char ppcInst[256];
DisassembleGekko(instCode.hex, PC, ppcInst, 256);
DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str(), instCode.hex, ppcInst);
DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx FPSCR: %08x MSR: %08x LR: %08x %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_val[0], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), instCode.hex, ppcInst);
}
int Interpreter::SingleStepInner(void)
@@ -4,32 +4,22 @@
#include "Core/PowerPC/Interpreter/Interpreter.h"
void Interpreter::Helper_UpdateCR0(u32 _uValue)
void Interpreter::Helper_UpdateCR0(u32 value)
{
u32 new_cr0;
int sValue = (int)_uValue;
if (sValue > 0)
new_cr0 = 0x4;
else if (sValue < 0)
new_cr0 = 0x8;
else
new_cr0 = 0x2;
new_cr0 |= GetXER_SO();
SetCRField(0, new_cr0);
s64 sign_extended = (s64)(s32)value;
u64 cr_val = (u64)sign_extended;
cr_val = (cr_val & ~(1ull << 61)) | ((u64)GetXER_SO() << 61);
PowerPC::ppcState.cr_val[0] = cr_val;
}
void Interpreter::Helper_UpdateCRx(int _x, u32 _uValue)
void Interpreter::Helper_UpdateCRx(int idx, u32 value)
{
u32 new_crX;
int sValue = (int)_uValue;
if (sValue > 0)
new_crX = 0x4;
else if (sValue < 0)
new_crX = 0x8;
else
new_crX = 0x2;
new_crX |= GetXER_SO();
SetCRField(_x, new_crX);
s64 sign_extended = (s64)(s32)value;
u64 cr_val = (u64)sign_extended;
cr_val = (cr_val & ~(1ull << 61)) | ((u64)GetXER_SO() << 61);
PowerPC::ppcState.cr_val[idx] = cr_val;
}
u32 Interpreter::Helper_Carry(u32 _uValue1, u32 _uValue2)
+2 -4
View File
@@ -377,10 +377,8 @@ void Jit64::Trace()
}
#endif
DEBUG_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3],
PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr,
PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str());
DEBUG_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str());
}
void STACKALIGN Jit64::Jit(u32 em_address)
+10
View File
@@ -106,6 +106,16 @@ public:
void GenerateRC();
void ComputeRC(const Gen::OpArg & arg);
// Reads a given bit of a given CR register part. Clobbers ABI_PARAM1,
// don't forget to xlock it before.
void GetCRFieldBit(int field, int bit, Gen::X64Reg out);
// Clobbers ABI_PARAM1 and ABI_PARAM2, xlock them before.
void SetCRFieldBit(int field, int bit, Gen::X64Reg in);
// Generates a branch that will check if a given bit of a CR register part
// is set or not.
FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set = true);
void tri_op(int d, int a, int b, bool reversible, void (XEmitter::*op)(Gen::X64Reg, Gen::OpArg));
typedef u32 (*Operation)(u32 a, u32 b);
void regimmop(int d, int a, bool binary, u32 value, Operation doop, void (XEmitter::*op)(int, const Gen::OpArg&, const Gen::OpArg&), bool Rc = false, bool carry = false);
+6 -18
View File
@@ -117,11 +117,8 @@ void Jit64::bcx(UGeckoInstruction inst)
FixupBranch pConditionDontBranch;
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit
{
TEST(8, M(&PowerPC::ppcState.cr_fast[inst.BI >> 2]), Imm8(8 >> (inst.BI & 3)));
if (inst.BO & BO_BRANCH_IF_TRUE) // Conditional branch
pConditionDontBranch = J_CC(CC_Z, true);
else
pConditionDontBranch = J_CC(CC_NZ, true);
pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3),
!(inst.BO_2 & BO_BRANCH_IF_TRUE));
}
if (inst.LK)
@@ -179,14 +176,8 @@ void Jit64::bcctrx(UGeckoInstruction inst)
// BO_2 == 001zy -> b if false
// BO_2 == 011zy -> b if true
// Ripped from bclrx
TEST(8, M(&PowerPC::ppcState.cr_fast[inst.BI >> 2]), Imm8(8 >> (inst.BI & 3)));
Gen::CCFlags branch;
if (inst.BO_2 & BO_BRANCH_IF_TRUE)
branch = CC_Z;
else
branch = CC_NZ;
FixupBranch b = J_CC(branch, true);
FixupBranch b = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3),
!(inst.BO_2 & BO_BRANCH_IF_TRUE));
MOV(32, R(EAX), M(&CTR));
AND(32, R(EAX), Imm32(0xFFFFFFFC));
//MOV(32, M(&PC), R(EAX)); => Already done in WriteExitDestInEAX()
@@ -222,11 +213,8 @@ void Jit64::bclrx(UGeckoInstruction inst)
FixupBranch pConditionDontBranch;
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit
{
TEST(8, M(&PowerPC::ppcState.cr_fast[inst.BI >> 2]), Imm8(8 >> (inst.BI & 3)));
if (inst.BO & BO_BRANCH_IF_TRUE) // Conditional branch
pConditionDontBranch = J_CC(CC_Z, true);
else
pConditionDontBranch = J_CC(CC_NZ, true);
pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3),
!(inst.BO_2 & BO_BRANCH_IF_TRUE));
}
// This below line can be used to prove that blr "eats flags" in practice.
@@ -237,26 +237,22 @@ void Jit64::fcmpx(UGeckoInstruction inst)
pGreater = J_CC(CC_B);
}
// Equal
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2));
MOV(64, R(RAX), Imm64(PPCCRToInternal(CR_EQ)));
continue1 = J();
// NAN
SetJumpTarget(pNaN);
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x1));
MOV(64, R(RAX), Imm64(PPCCRToInternal(CR_SO)));
if (a != b)
{
continue2 = J();
// Greater Than
SetJumpTarget(pGreater);
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x4));
MOV(64, R(RAX), Imm64(PPCCRToInternal(CR_GT)));
continue3 = J();
// Less Than
SetJumpTarget(pLesser);
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x8));
MOV(64, R(RAX), Imm64(PPCCRToInternal(CR_LT)));
}
SetJumpTarget(continue1);
@@ -266,6 +262,7 @@ void Jit64::fcmpx(UGeckoInstruction inst)
SetJumpTarget(continue3);
}
MOV(64, M(&PowerPC::ppcState.cr_val[crf]), R(RAX));
fpr.UnlockAll();
}
File diff suppressed because it is too large Load Diff
@@ -10,6 +10,130 @@
#include "Core/PowerPC/Jit64/Jit.h"
#include "Core/PowerPC/Jit64/JitRegCache.h"
void Jit64::GetCRFieldBit(int field, int bit, Gen::X64Reg out)
{
switch (bit)
{
case CR_SO_BIT: // check bit 61 set
MOV(64, R(ABI_PARAM1), Imm64(1ull << 61));
TEST(64, M(&PowerPC::ppcState.cr_val[field]), R(ABI_PARAM1));
SETcc(CC_NZ, R(out));
break;
case CR_EQ_BIT: // check bits 31-0 == 0
CMP(32, M(&PowerPC::ppcState.cr_val[field]), Imm32(0));
SETcc(CC_Z, R(out));
break;
case CR_GT_BIT: // check val > 0
MOV(64, R(ABI_PARAM1), M(&PowerPC::ppcState.cr_val[field]));
TEST(64, R(ABI_PARAM1), R(ABI_PARAM1));
SETcc(CC_G, R(out));
break;
case CR_LT_BIT: // check bit 62 set
MOV(64, R(ABI_PARAM1), Imm64(1ull << 62));
TEST(64, M(&PowerPC::ppcState.cr_val[field]), R(ABI_PARAM1));
SETcc(CC_NZ, R(out));
break;
default:
_assert_msg_(DYNA_REC, false, "Invalid CR bit");
}
}
void Jit64::SetCRFieldBit(int field, int bit, Gen::X64Reg in)
{
MOV(64, R(ABI_PARAM2), M(&PowerPC::ppcState.cr_val[field]));
TEST(8, R(in), Imm8(1));
FixupBranch input_is_set = J_CC(CC_NZ, false);
// New value is 0.
switch (bit)
{
case CR_SO_BIT: // unset bit 61
MOV(64, R(ABI_PARAM1), Imm64(~(1ull << 61)));
AND(64, R(ABI_PARAM2), R(ABI_PARAM1));
break;
case CR_EQ_BIT: // set bit 0 to 1
OR(8, R(ABI_PARAM2), Imm8(1));
break;
case CR_GT_BIT: // !GT, set bit 63
MOV(64, R(ABI_PARAM1), Imm64(1ull << 63));
OR(64, R(ABI_PARAM2), R(ABI_PARAM1));
break;
case CR_LT_BIT: // !LT, unset bit 62
MOV(64, R(ABI_PARAM1), Imm64(~(1ull << 62)));
AND(64, R(ABI_PARAM2), R(ABI_PARAM1));
break;
}
FixupBranch end = J();
SetJumpTarget(input_is_set);
switch (bit)
{
case CR_SO_BIT: // set bit 61
MOV(64, R(ABI_PARAM1), Imm64(1ull << 61));
OR(64, R(ABI_PARAM2), R(ABI_PARAM1));
break;
case CR_EQ_BIT: // set bits 31-0 to 0
MOV(64, R(ABI_PARAM1), Imm64(0xFFFFFFFF00000000));
AND(64, R(ABI_PARAM2), R(ABI_PARAM1));
break;
case CR_GT_BIT: // unset bit 63
MOV(64, R(ABI_PARAM1), Imm64(~(1ull << 63)));
AND(64, R(ABI_PARAM2), R(ABI_PARAM1));
break;
case CR_LT_BIT: // set bit 62
MOV(64, R(ABI_PARAM1), Imm64(1ull << 62));
OR(64, R(ABI_PARAM2), R(ABI_PARAM1));
break;
}
SetJumpTarget(end);
MOV(64, R(ABI_PARAM1), Imm64(1ull << 32));
OR(64, R(ABI_PARAM2), R(ABI_PARAM1));
MOV(64, M(&PowerPC::ppcState.cr_val[field]), R(ABI_PARAM2));
}
FixupBranch Jit64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
{
switch (bit)
{
case CR_SO_BIT: // check bit 61 set
MOV(64, R(RAX), Imm64(1ull << 61));
TEST(64, M(&PowerPC::ppcState.cr_val[field]), R(RAX));
return J_CC(jump_if_set ? CC_NZ : CC_Z, true);
case CR_EQ_BIT: // check bits 31-0 == 0
CMP(32, M(&PowerPC::ppcState.cr_val[field]), Imm32(0));
return J_CC(jump_if_set ? CC_Z : CC_NZ, true);
case CR_GT_BIT: // check val > 0
MOV(64, R(RAX), M(&PowerPC::ppcState.cr_val[field]));
TEST(64, R(RAX), R(RAX));
return J_CC(jump_if_set ? CC_G : CC_LE, true);
case CR_LT_BIT: // check bit 62 set
MOV(64, R(RAX), Imm64(1ull << 62));
TEST(64, M(&PowerPC::ppcState.cr_val[field]), R(RAX));
return J_CC(jump_if_set ? CC_NZ : CC_Z, true);
default:
_assert_msg_(DYNA_REC, false, "Invalid CR bit");
}
// Should never happen.
return FixupBranch();
}
void Jit64::mtspr(UGeckoInstruction inst)
{
INSTRUCTION_START
@@ -154,16 +278,47 @@ void Jit64::mfcr(UGeckoInstruction inst)
int d = inst.RD;
gpr.Lock(d);
gpr.KillImmediate(d, false, true);
MOV(8, R(EAX), M(&PowerPC::ppcState.cr_fast[0]));
XOR(32, R(EAX), R(EAX));
for (int i = 1; i < 8; i++)
gpr.FlushLockX(ABI_PARAM1, ABI_PARAM2);
X64Reg cr_val = ABI_PARAM1;
X64Reg tmp = ABI_PARAM2;
for (int i = 0; i < 8; i++)
{
SHL(32, R(EAX), Imm8(4));
OR(8, R(EAX), M(&PowerPC::ppcState.cr_fast[i]));
if (i != 0)
SHL(32, R(EAX), Imm8(4));
MOV(64, R(cr_val), M(&PowerPC::ppcState.cr_val[i]));
// SO: Bit 61 set.
MOV(64, R(tmp), R(cr_val));
SHR(64, R(tmp), Imm8(61));
AND(32, R(tmp), Imm8(1));
OR(32, R(EAX), R(tmp));
// EQ: Bits 31-0 == 0.
XOR(32, R(tmp), R(tmp));
TEST(32, R(cr_val), R(cr_val));
SETcc(CC_Z, R(tmp));
SHL(32, R(tmp), Imm8(1));
OR(32, R(EAX), R(tmp));
// GT: Value > 0.
TEST(64, R(cr_val), R(cr_val));
SETcc(CC_G, R(tmp));
SHL(32, R(tmp), Imm8(2));
OR(32, R(EAX), R(tmp));
// LT: Bit 62 set.
MOV(64, R(tmp), R(cr_val));
SHR(64, R(tmp), Imm8(62 - 3));
AND(32, R(tmp), Imm8(0x8));
OR(32, R(EAX), R(tmp));
}
MOV(32, gpr.R(d), R(EAX));
gpr.UnlockAll();
gpr.UnlockAllX();
}
void Jit64::mtcrf(UGeckoInstruction inst)
@@ -182,7 +337,8 @@ void Jit64::mtcrf(UGeckoInstruction inst)
if ((crm & (0x80 >> i)) != 0)
{
u8 newcr = (gpr.R(inst.RS).offset >> (28 - (i * 4))) & 0xF;
MOV(8, M(&PowerPC::ppcState.cr_fast[i]), Imm8(newcr));
MOV(64, R(RAX), Imm64(PPCCRToInternal(newcr)));
MOV(64, M(&PowerPC::ppcState.cr_val[i]), R(RAX));
}
}
}
@@ -190,17 +346,50 @@ void Jit64::mtcrf(UGeckoInstruction inst)
{
gpr.Lock(inst.RS);
gpr.BindToRegister(inst.RS, true, false);
gpr.FlushLockX(ABI_PARAM1, ABI_PARAM2);
for (int i = 0; i < 8; i++)
{
if ((crm & (0x80 >> i)) != 0)
{
MOV(32, R(EAX), gpr.R(inst.RS));
SHR(32, R(EAX), Imm8(28 - (i * 4)));
AND(32, R(EAX), Imm32(0xF));
MOV(8, M(&PowerPC::ppcState.cr_fast[i]), R(EAX));
MOVZX(64, 32, EAX, gpr.R(inst.RS));
SHR(64, R(EAX), Imm8(28 - (i * 4)));
AND(64, R(EAX), Imm32(0xF));
X64Reg cr_val = ABI_PARAM1;
X64Reg tmp = ABI_PARAM2;
MOV(64, R(cr_val), Imm64(1ull << 32));
// SO
MOV(64, R(tmp), R(EAX));
SHL(64, R(tmp), Imm8(63));
SHR(64, R(tmp), Imm8(63 - 61));
OR(64, R(cr_val), R(tmp));
// EQ
MOV(64, R(tmp), R(EAX));
NOT(64, R(tmp));
AND(64, R(tmp), Imm8(CR_EQ));
OR(64, R(cr_val), R(tmp));
// GT
MOV(64, R(tmp), R(EAX));
NOT(64, R(tmp));
AND(64, R(tmp), Imm8(CR_GT));
SHL(64, R(tmp), Imm8(63 - 2));
OR(64, R(cr_val), R(tmp));
// LT
MOV(64, R(tmp), R(EAX));
AND(64, R(tmp), Imm8(CR_LT));
SHL(64, R(tmp), Imm8(62 - 3));
OR(64, R(cr_val), R(tmp));
MOV(64, M(&PowerPC::ppcState.cr_val[i]), R(cr_val));
}
}
gpr.UnlockAll();
gpr.UnlockAllX();
}
}
}
@@ -213,8 +402,8 @@ void Jit64::mcrf(UGeckoInstruction inst)
// USES_CR
if (inst.CRFS != inst.CRFD)
{
MOV(8, R(EAX), M(&PowerPC::ppcState.cr_fast[inst.CRFS]));
MOV(8, M(&PowerPC::ppcState.cr_fast[inst.CRFD]), R(EAX));
MOV(64, R(EAX), M(&PowerPC::ppcState.cr_val[inst.CRFS]));
MOV(64, M(&PowerPC::ppcState.cr_val[inst.CRFD]), R(EAX));
}
}
@@ -226,9 +415,41 @@ void Jit64::mcrxr(UGeckoInstruction inst)
// USES_CR
// Copy XER[0-3] into CR[inst.CRFD]
MOV(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_XER]));
SHR(32, R(EAX), Imm8(28));
MOV(8, M(&PowerPC::ppcState.cr_fast[inst.CRFD]), R(EAX));
MOVZX(64, 32, EAX, M(&PowerPC::ppcState.spr[SPR_XER]));
SHR(64, R(EAX), Imm8(28));
gpr.FlushLockX(ABI_PARAM1, ABI_PARAM2);
X64Reg cr_val = ABI_PARAM1;
X64Reg tmp = ABI_PARAM2;
MOV(64, R(cr_val), Imm64(1ull << 32));
// SO
MOV(64, R(tmp), R(EAX));
SHL(64, R(tmp), Imm8(63));
SHR(64, R(tmp), Imm8(63 - 61));
OR(64, R(cr_val), R(tmp));
// EQ
MOV(64, R(tmp), R(EAX));
AND(64, R(tmp), Imm8(0x2));
OR(64, R(cr_val), R(tmp));
// GT
MOV(64, R(tmp), R(EAX));
NOT(64, R(tmp));
AND(64, R(tmp), Imm8(0x4));
SHL(64, R(tmp), Imm8(63 - 2));
OR(64, R(cr_val), R(tmp));
// LT
MOV(64, R(tmp), R(EAX));
AND(64, R(tmp), Imm8(0x8));
SHL(64, R(tmp), Imm8(62 - 3));
OR(64, R(cr_val), R(tmp));
MOV(64, M(&PowerPC::ppcState.cr_val[inst.CRFD]), R(cr_val));
gpr.UnlockAllX();
// Clear XER[0-3]
AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(0x0FFFFFFF));
@@ -240,70 +461,59 @@ void Jit64::crXXX(UGeckoInstruction inst)
JITDISABLE(bJITSystemRegistersOff);
_dbg_assert_msg_(DYNA_REC, inst.OPCD == 19, "Invalid crXXX");
// TODO(delroth): Potential optimizations could be applied here. For
// instance, if the two CR bits being loaded are the same, two loads are
// not required.
// USES_CR
// Get bit CRBA in EAX aligned with bit CRBD
int shiftA = (inst.CRBD & 3) - (inst.CRBA & 3);
MOV(8, R(EAX), M(&PowerPC::ppcState.cr_fast[inst.CRBA >> 2]));
if (shiftA < 0)
SHL(8, R(EAX), Imm8(-shiftA));
else if (shiftA > 0)
SHR(8, R(EAX), Imm8(shiftA));
// Get bit CRBB in ECX aligned with bit CRBD
gpr.FlushLockX(ECX);
int shiftB = (inst.CRBD & 3) - (inst.CRBB & 3);
MOV(8, R(ECX), M(&PowerPC::ppcState.cr_fast[inst.CRBB >> 2]));
if (shiftB < 0)
SHL(8, R(ECX), Imm8(-shiftB));
else if (shiftB > 0)
SHR(8, R(ECX), Imm8(shiftB));
gpr.FlushLockX(ABI_PARAM1, ABI_PARAM2);
GetCRFieldBit(inst.CRBA >> 2, 3 - (inst.CRBA & 3), ABI_PARAM2);
GetCRFieldBit(inst.CRBB >> 2, 3 - (inst.CRBB & 3), EAX);
// Compute combined bit
switch (inst.SUBOP10)
{
case 33: // crnor
OR(8, R(EAX), R(ECX));
OR(8, R(EAX), R(ABI_PARAM2));
NOT(8, R(EAX));
break;
case 129: // crandc
NOT(8, R(ECX));
AND(8, R(EAX), R(ECX));
NOT(8, R(ABI_PARAM2));
AND(8, R(EAX), R(ABI_PARAM2));
break;
case 193: // crxor
XOR(8, R(EAX), R(ECX));
XOR(8, R(EAX), R(ABI_PARAM2));
break;
case 225: // crnand
AND(8, R(EAX), R(ECX));
AND(8, R(EAX), R(ABI_PARAM2));
NOT(8, R(EAX));
break;
case 257: // crand
AND(8, R(EAX), R(ECX));
AND(8, R(EAX), R(ABI_PARAM2));
break;
case 289: // creqv
XOR(8, R(EAX), R(ECX));
XOR(8, R(EAX), R(ABI_PARAM2));
NOT(8, R(EAX));
break;
case 417: // crorc
NOT(8, R(ECX));
OR(8, R(EAX), R(ECX));
NOT(8, R(ABI_PARAM2));
OR(8, R(EAX), R(ABI_PARAM2));
break;
case 449: // cror
OR(8, R(EAX), R(ECX));
OR(8, R(EAX), R(ABI_PARAM2));
break;
}
// Store result bit in CRBD
AND(8, R(EAX), Imm8(0x8 >> (inst.CRBD & 3)));
AND(8, M(&PowerPC::ppcState.cr_fast[inst.CRBD >> 2]), Imm8(~(0x8 >> (inst.CRBD & 3))));
OR(8, M(&PowerPC::ppcState.cr_fast[inst.CRBD >> 2]), R(EAX));
SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3), EAX);
gpr.UnlockAllX();
}
+196 -43
View File
@@ -85,7 +85,7 @@ static unsigned regReadUse(RegInfo& R, InstLoc I) {
return R.IInfo[I - R.FirstI] & 3;
}
static unsigned SlotSet[1000];
static u64 SlotSet[1000];
static u8 GC_ALIGNED16(FSlotSet[16*1000]);
static OpArg regLocForSlot(RegInfo& RI, unsigned slot) {
@@ -107,7 +107,7 @@ static void regSpill(RegInfo& RI, X64Reg reg) {
unsigned slot = regGetSpill(RI, RI.regs[reg]);
if (!slot) {
slot = regCreateSpill(RI, RI.regs[reg]);
RI.Jit->MOV(32, regLocForSlot(RI, slot), R(reg));
RI.Jit->MOV(64, regLocForSlot(RI, slot), R(reg));
}
RI.regs[reg] = nullptr;
}
@@ -550,6 +550,48 @@ static void regEmitICmpInst(RegInfo& RI, InstLoc I, CCFlags flag) {
regNormalRegClear(RI, I);
}
static void regEmitICmpCRInst(RegInfo& RI, InstLoc I) {
bool signed_compare = getOpcode(*I) == ICmpCRSigned;
X64Reg reg;
if (RI.IInfo[I - RI.FirstI] & 4)
{
reg = regEnsureInReg(RI, getOp1(I));
if (signed_compare)
RI.Jit->MOVSX(64, 32, reg, R(reg));
}
else
{
reg = regFindFreeReg(RI);
if (signed_compare)
RI.Jit->MOVSX(64, 32, reg, regLocForInst(RI, getOp1(I)));
else
RI.Jit->MOV(32, R(reg), regLocForInst(RI, getOp1(I)));
}
if (isImm(*getOp2(I)))
{
unsigned RHS = RI.Build->GetImmValue(getOp2(I));
if (!signed_compare && (RHS & 0x80000000U))
{
RI.Jit->MOV(32, R(EAX), Imm32(RHS));
RI.Jit->SUB(64, R(reg), R(RAX));
}
else if (RHS)
{
RI.Jit->SUB(64, R(reg), Imm32(RHS));
}
}
else
{
if (signed_compare)
RI.Jit->MOVSX(64, 32, RAX, regLocForInst(RI, getOp2(I)));
else
RI.Jit->MOV(32, R(EAX), regLocForInst(RI, getOp2(I)));
RI.Jit->SUB(64, R(reg), R(RAX));
}
RI.regs[reg] = I;
regNormalRegClear(RI, I);
}
static void regWriteExit(RegInfo& RI, InstLoc dest) {
if (isImm(*dest)) {
RI.exitNumber++;
@@ -621,6 +663,12 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) {
case FPDup1:
case FSNeg:
case FDNeg:
case ConvertFromFastCR:
case ConvertToFastCR:
case FastCRSOSet:
case FastCREQSet:
case FastCRGTSet:
case FastCRLTSet:
if (thisUsed)
regMarkUse(RI, I, getOp1(I), 1);
break;
@@ -715,9 +763,10 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) {
regMarkUse(RI, I, getOp1(getOp1(I)), 1);
break;
case BranchCond: {
if (isICmp(*getOp1(I)) &&
isImm(*getOp2(getOp1(I)))) {
if (isICmp(*getOp1(I))) {
regMarkUse(RI, I, getOp1(getOp1(I)), 1);
if (!isImm(*getOp2(getOp1(I))))
regMarkUse(RI, I, getOp2(getOp1(I)), 2);
} else {
regMarkUse(RI, I, getOp1(I), 1);
}
@@ -763,7 +812,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) {
if (!thisUsed) break;
X64Reg reg = regFindFreeReg(RI);
unsigned ppcreg = *I >> 8;
Jit->MOVZX(32, 8, reg, M(&PowerPC::ppcState.cr_fast[ppcreg]));
Jit->MOV(64, R(reg), M(&PowerPC::ppcState.cr_val[ppcreg]));
RI.regs[reg] = I;
break;
}
@@ -813,10 +862,9 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) {
break;
}
case StoreCR: {
Jit->MOV(32, R(ECX), regLocForInst(RI, getOp1(I)));
X64Reg reg = regEnsureInReg(RI, getOp1(I));
unsigned ppcreg = *I >> 16;
// CAUTION: uses 8-bit reg!
Jit->MOV(8, M(&PowerPC::ppcState.cr_fast[ppcreg]), R(ECX));
Jit->MOV(64, M(&PowerPC::ppcState.cr_val[ppcreg]), R(reg));
regNormalRegClear(RI, I);
break;
}
@@ -1076,40 +1124,138 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) {
regEmitICmpInst(RI, I, CC_LE);
break;
}
case ICmpCRUnsigned: {
case ICmpCRUnsigned:
{
if (!thisUsed) break;
regEmitCmp(RI, I);
X64Reg reg = regBinReg(RI, I);
FixupBranch pLesser = Jit->J_CC(CC_B);
FixupBranch pGreater = Jit->J_CC(CC_A);
Jit->MOV(32, R(reg), Imm32(0x2)); // _x86Reg == 0
FixupBranch continue1 = Jit->J();
Jit->SetJumpTarget(pGreater);
Jit->MOV(32, R(reg), Imm32(0x4)); // _x86Reg > 0
FixupBranch continue2 = Jit->J();
Jit->SetJumpTarget(pLesser);
Jit->MOV(32, R(reg), Imm32(0x8)); // _x86Reg < 0
Jit->SetJumpTarget(continue1);
Jit->SetJumpTarget(continue2);
regEmitICmpCRInst(RI, I);
break;
}
case ICmpCRSigned:
{
if (!thisUsed) break;
regEmitICmpCRInst(RI, I);
break;
}
case ConvertFromFastCR:
{
if (!thisUsed) break;
X64Reg cr_val = regUReg(RI, I);
Jit->MOV(64, R(cr_val), regLocForInst(RI, getOp1(I)));
Jit->XOR(32, R(EAX), R(EAX));
// SO: Bit 61 set.
Jit->MOV(64, R(RCX), R(cr_val));
Jit->SHR(64, R(RCX), Imm8(61));
Jit->AND(32, R(ECX), Imm8(1));
Jit->OR(32, R(EAX), R(ECX));
// EQ: Bits 31-0 == 0.
Jit->XOR(32, R(ECX), R(ECX));
Jit->TEST(32, R(cr_val), R(cr_val));
Jit->SETcc(CC_Z, R(ECX));
Jit->SHL(32, R(ECX), Imm8(1));
Jit->OR(32, R(EAX), R(ECX));
// GT: Value > 0.
Jit->XOR(32, R(ECX), R(ECX));
Jit->TEST(64, R(cr_val), R(cr_val));
Jit->SETcc(CC_G, R(ECX));
Jit->SHL(32, R(ECX), Imm8(2));
Jit->OR(32, R(EAX), R(ECX));
// LT: Bit 62 set.
Jit->MOV(64, R(ECX), R(cr_val));
Jit->SHR(64, R(ECX), Imm8(62 - 3));
Jit->AND(32, R(ECX), Imm8(0x8));
Jit->OR(32, R(EAX), R(ECX));
Jit->MOV(32, R(cr_val), R(EAX));
RI.regs[cr_val] = I;
regNormalRegClear(RI, I);
break;
}
case ConvertToFastCR:
{
if (!thisUsed) break;
X64Reg cr_val = regUReg(RI, I);
Jit->MOV(64, R(cr_val), regLocForInst(RI, getOp1(I)));
Jit->MOV(64, R(RCX), Imm64(1ull << 32));
// SO
Jit->MOV(64, R(RAX), R(cr_val));
Jit->SHL(64, R(RAX), Imm8(63));
Jit->SHR(64, R(RAX), Imm8(63 - 61));
Jit->OR(64, R(RCX), R(RAX));
// EQ
Jit->MOV(64, R(RAX), R(cr_val));
Jit->NOT(64, R(RAX));
Jit->AND(64, R(RAX), Imm8(CR_EQ));
Jit->OR(64, R(RCX), R(RAX));
// GT
Jit->MOV(64, R(RAX), R(cr_val));
Jit->NOT(64, R(RAX));
Jit->AND(64, R(RAX), Imm8(CR_GT));
Jit->SHL(64, R(RAX), Imm8(63 - 2));
Jit->OR(64, R(RCX), R(RAX));
// LT
Jit->MOV(64, R(RAX), R(cr_val));
Jit->AND(64, R(RAX), Imm8(CR_LT));
Jit->SHL(64, R(RAX), Imm8(62 - 3));
Jit->OR(64, R(RCX), R(RAX));
Jit->MOV(64, R(cr_val), R(RCX));
RI.regs[cr_val] = I;
regNormalRegClear(RI, I);
break;
}
case FastCRSOSet:
{
if (!thisUsed) break;
X64Reg reg = regUReg(RI, I);
Jit->MOV(64, R(RAX), Imm64(1ull << 61));
Jit->TEST(64, regLocForInst(RI, getOp1(I)), R(RAX));
Jit->SETcc(CC_NZ, R(AL));
Jit->MOVZX(32, 8, reg, R(AL));
RI.regs[reg] = I;
regNormalRegClear(RI, I);
break;
}
case ICmpCRSigned: {
case FastCREQSet:
{
if (!thisUsed) break;
regEmitCmp(RI, I);
X64Reg reg = regBinReg(RI, I);
FixupBranch pLesser = Jit->J_CC(CC_L);
FixupBranch pGreater = Jit->J_CC(CC_G);
Jit->MOV(32, R(reg), Imm32(0x2)); // _x86Reg == 0
FixupBranch continue1 = Jit->J();
Jit->SetJumpTarget(pGreater);
Jit->MOV(32, R(reg), Imm32(0x4)); // _x86Reg > 0
FixupBranch continue2 = Jit->J();
Jit->SetJumpTarget(pLesser);
Jit->MOV(32, R(reg), Imm32(0x8)); // _x86Reg < 0
Jit->SetJumpTarget(continue1);
Jit->SetJumpTarget(continue2);
X64Reg reg = regUReg(RI, I);
Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm32(0));
Jit->SETcc(CC_Z, R(AL));
Jit->MOVZX(32, 8, reg, R(AL));
RI.regs[reg] = I;
regNormalRegClear(RI, I);
break;
}
case FastCRGTSet:
{
if (!thisUsed) break;
X64Reg reg = regUReg(RI, I);
Jit->CMP(64, regLocForInst(RI, getOp1(I)), Imm8(0));
Jit->SETcc(CC_G, R(AL));
Jit->MOVZX(32, 8, reg, R(AL));
RI.regs[reg] = I;
regNormalRegClear(RI, I);
break;
}
case FastCRLTSet:
{
if (!thisUsed) break;
X64Reg reg = regUReg(RI, I);
Jit->MOV(64, R(RAX), Imm64(1ull << 62));
Jit->TEST(64, regLocForInst(RI, getOp1(I)), R(RAX));
Jit->SETcc(CC_NZ, R(AL));
Jit->MOVZX(32, 8, reg, R(AL));
RI.regs[reg] = I;
regNormalRegClear(RI, I);
break;
@@ -1538,7 +1684,13 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) {
case CInt16: {
if (!thisUsed) break;
X64Reg reg = regFindFreeReg(RI);
Jit->MOV(32, R(reg), Imm32(ibuild->GetImmValue(I)));
u64 val = ibuild->GetImmValue64(I);
if ((u32)val == val)
Jit->MOV(32, R(reg), Imm32(val));
else if ((s32)val == val)
Jit->MOV(64, R(reg), Imm32(val));
else
Jit->MOV(64, R(reg), Imm64(val));
RI.regs[reg] = I;
break;
}
@@ -1566,17 +1718,15 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) {
}
case BranchCond: {
if (isICmp(*getOp1(I)) &&
isImm(*getOp2(getOp1(I)))) {
Jit->CMP(32, regLocForInst(RI, getOp1(getOp1(I))),
Imm32(RI.Build->GetImmValue(getOp2(getOp1(I)))));
if (isICmp(*getOp1(I))) {
regEmitCmp(RI, getOp1(I));
CCFlags flag;
switch (getOpcode(*getOp1(I))) {
case ICmpEq: flag = CC_NE; break;
case ICmpNe: flag = CC_E; break;
case ICmpUgt: flag = CC_BE; break;
case ICmpUlt: flag = CC_AE; break;
case ICmpUge: flag = CC_L; break;
case ICmpUge: flag = CC_B; break;
case ICmpUle: flag = CC_A; break;
case ICmpSgt: flag = CC_LE; break;
case ICmpSlt: flag = CC_GE; break;
@@ -1589,7 +1739,10 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) {
Jit->SetJumpTarget(cont);
if (RI.IInfo[I - RI.FirstI] & 4)
regClearInst(RI, getOp1(getOp1(I)));
} else {
if (RI.IInfo[I - RI.FirstI] & 8)
regClearInst(RI, getOp2(getOp1(I)));
}
else {
Jit->CMP(32, regLocForInst(RI, getOp1(I)), Imm8(0));
FixupBranch cont = Jit->J_CC(CC_Z);
regWriteExit(RI, getOp2(I));
+3 -3
View File
@@ -477,9 +477,9 @@ void JitIL::Trace()
}
#endif
DEBUG_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3],
PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr,
DEBUG_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx%016lx%016lx%016lx%016lx%016lx%016lx%016lx FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.cr_val[0], PowerPC::ppcState.cr_val[1], PowerPC::ppcState.cr_val[2], PowerPC::ppcState.cr_val[3],
PowerPC::ppcState.cr_val[4], PowerPC::ppcState.cr_val[5], PowerPC::ppcState.cr_val[6], PowerPC::ppcState.cr_val[7], PowerPC::ppcState.fpscr,
PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str());
}
+6 -12
View File
@@ -233,31 +233,25 @@ void JitArm::SingleStep()
void JitArm::Trace()
{
char regs[500] = "";
char fregs[750] = "";
std::string regs;
std::string fregs;
#ifdef JIT_LOG_GPR
for (int i = 0; i < 32; i++)
{
char reg[50];
sprintf(reg, "r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
strncat(regs, reg, sizeof(regs) - 1);
regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
}
#endif
#ifdef JIT_LOG_FPR
for (int i = 0; i < 32; i++)
{
char reg[50];
sprintf(reg, "f%02d: %016x ", i, riPS0(i));
strncat(fregs, reg, sizeof(fregs) - 1);
fregs += StringFromFormat("f%02d: %016x ", i, riPS0(i));
}
#endif
DEBUG_LOG(DYNA_REC, "JITARM PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3],
PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr,
PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs);
DEBUG_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), fregs.c_str());
}
void JitArm::PrintDebug(UGeckoInstruction inst, u32 level)
+3 -14
View File
@@ -50,6 +50,8 @@ private:
void Helper_UpdateCR1(ARMReg fpscr, ARMReg temp);
void SetFPException(ARMReg Reg, u32 Exception);
FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set);
public:
JitArm() : code_buffer(32000) {}
~JitArm() {}
@@ -96,8 +98,7 @@ public:
void WriteCallInterpreter(UGeckoInstruction _inst);
void Cleanup();
void GenerateRC(int cr = 0);
void ComputeRC(int cr = 0);
void ComputeRC(ARMReg value, int cr = 0);
void ComputeRC(s32 value, int cr);
void ComputeCarry();
@@ -143,8 +144,6 @@ public:
void cntlzwx(UGeckoInstruction _inst);
void cmp (UGeckoInstruction _inst);
void cmpi(UGeckoInstruction _inst);
void cmpl(UGeckoInstruction _inst);
void cmpli(UGeckoInstruction _inst);
void negx(UGeckoInstruction _inst);
void mulhwux(UGeckoInstruction _inst);
void rlwimix(UGeckoInstruction _inst);
@@ -160,13 +159,9 @@ public:
void mtspr(UGeckoInstruction _inst);
void mfspr(UGeckoInstruction _inst);
void mftb(UGeckoInstruction _inst);
void crXXX(UGeckoInstruction _inst);
void mcrf(UGeckoInstruction _inst);
void mfcr(UGeckoInstruction _inst);
void mtcrf(UGeckoInstruction _inst);
void mtsr(UGeckoInstruction _inst);
void mfsr(UGeckoInstruction _inst);
void mcrxr(UGeckoInstruction _inst);
void twx(UGeckoInstruction _inst);
// LoadStore
@@ -193,8 +188,6 @@ public:
void fmaddx(UGeckoInstruction _inst);
void fctiwx(UGeckoInstruction _inst);
void fctiwzx(UGeckoInstruction _inst);
void fcmpo(UGeckoInstruction _inst);
void fcmpu(UGeckoInstruction _inst);
void fnmaddx(UGeckoInstruction _inst);
void fnmaddsx(UGeckoInstruction _inst);
void fresx(UGeckoInstruction _inst);
@@ -232,10 +225,6 @@ public:
void ps_nabs(UGeckoInstruction _inst);
void ps_rsqrte(UGeckoInstruction _inst);
void ps_sel(UGeckoInstruction _inst);
void ps_cmpu0(UGeckoInstruction _inst);
void ps_cmpu1(UGeckoInstruction _inst);
void ps_cmpo0(UGeckoInstruction _inst);
void ps_cmpo1(UGeckoInstruction _inst);
// LoadStore paired
void psq_l(UGeckoInstruction _inst);
@@ -16,15 +16,6 @@
// The branches are known good, or at least reasonably good.
// No need for a disable-mechanism.
// If defined, clears CR0 at blr and bl-s. If the assumption that
// flags never carry over between functions holds, then the task for
// an optimizer becomes much easier.
// #define ACID_TEST
// Zelda and many more games seem to pass the Acid Test.
using namespace ArmGen;
void JitArm::sc(UGeckoInstruction inst)
{
@@ -121,13 +112,7 @@ void JitArm::bx(UGeckoInstruction inst)
destination = SignExt26(inst.LI << 2);
else
destination = js.compilerPC + SignExt26(inst.LI << 2);
#ifdef ACID_TEST
if (inst.LK)
{
MOV(R14, 0);
STRB(R14, R9, PPCSTATE_OFF(cr_fast[0]));
}
#endif
if (destination == js.compilerPC)
{
//PanicAlert("Idle loop detected at %08x", destination);
@@ -168,15 +153,10 @@ void JitArm::bcx(UGeckoInstruction inst)
FixupBranch pConditionDontBranch;
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit
{
LDRB(rA, R9, PPCSTATE_OFF(cr_fast) + (inst.BI >> 2));
TST(rA, 8 >> (inst.BI & 3));
//TEST(8, M(&PowerPC::ppcState.cr_fast[inst.BI >> 2]), Imm8(8 >> (inst.BI & 3)));
if (inst.BO & BO_BRANCH_IF_TRUE) // Conditional branch
pConditionDontBranch = B_CC(CC_EQ); // Zero
else
pConditionDontBranch = B_CC(CC_NEQ); // Not Zero
pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3),
!(inst.BO_2 & BO_BRANCH_IF_TRUE));
}
if (inst.LK)
{
u32 Jumpto = js.compilerPC + 4;
@@ -240,20 +220,13 @@ void JitArm::bcctrx(UGeckoInstruction inst)
else
{
// Rare condition seen in (just some versions of?) Nintendo's NES Emulator
// BO_2 == 001zy -> b if false
// BO_2 == 011zy -> b if true
ARMReg rA = gpr.GetReg();
ARMReg rB = gpr.GetReg();
LDRB(rA, R9, PPCSTATE_OFF(cr_fast) + (inst.BI >> 2));
TST(rA, 8 >> (inst.BI & 3));
CCFlags branch;
if (inst.BO_2 & BO_BRANCH_IF_TRUE)
branch = CC_EQ;
else
branch = CC_NEQ;
FixupBranch b = B_CC(branch);
FixupBranch b = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3),
!(inst.BO_2 & BO_BRANCH_IF_TRUE));
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_CTR]));
BIC(rA, rA, 0x3);
@@ -304,25 +277,10 @@ void JitArm::bclrx(UGeckoInstruction inst)
FixupBranch pConditionDontBranch;
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit
{
LDRB(rA, R9, PPCSTATE_OFF(cr_fast) + (inst.BI >> 2));
TST(rA, 8 >> (inst.BI & 3));
//TEST(8, M(&PowerPC::ppcState.cr_fast[inst.BI >> 2]), Imm8(8 >> (inst.BI & 3)));
if (inst.BO & BO_BRANCH_IF_TRUE) // Conditional branch
pConditionDontBranch = B_CC(CC_EQ); // Zero
else
pConditionDontBranch = B_CC(CC_NEQ); // Not Zero
pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3),
!(inst.BO_2 & BO_BRANCH_IF_TRUE));
}
// This below line can be used to prove that blr "eats flags" in practice.
// This observation will let us do a lot of fun observations.
#ifdef ACID_TEST
if (inst.LK)
{
MOV(R14, 0);
STRB(R14, R9, PPCSTATE_OFF(cr_fast[0]));
}
#endif
//MOV(32, R(EAX), M(&LR));
//AND(32, R(EAX), Imm32(0xFFFFFFFC));
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
@@ -19,8 +19,6 @@
void JitArm::Helper_UpdateCR1(ARMReg fpscr, ARMReg temp)
{
UBFX(temp, fpscr, 28, 4);
STRB(temp, R9, PPCSTATE_OFF(cr_fast[1]));
}
void JitArm::fctiwx(UGeckoInstruction inst)
@@ -129,7 +127,6 @@ void JitArm::fctiwx(UGeckoInstruction inst)
fpr.Unlock(V2);
}
void JitArm::fctiwzx(UGeckoInstruction inst)
{
INSTRUCTION_START
@@ -210,136 +207,6 @@ void JitArm::fctiwzx(UGeckoInstruction inst)
fpr.Unlock(V2);
}
void JitArm::fcmpo(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITFloatingPointOff);
u32 a = inst.FA, b = inst.FB;
int cr = inst.CRFD;
ARMReg vA = fpr.R0(a);
ARMReg vB = fpr.R0(b);
ARMReg fpscrReg = gpr.GetReg();
ARMReg crReg = gpr.GetReg();
Operand2 FPRFMask(0x1F, 0xA); // 0x1F000
Operand2 LessThan(0x8, 0xA); // 0x8000
Operand2 GreaterThan(0x4, 0xA); // 0x4000
Operand2 EqualTo(0x2, 0xA); // 0x2000
Operand2 NANRes(0x1, 0xA); // 0x1000
FixupBranch Done1, Done2, Done3;
LDR(fpscrReg, R9, PPCSTATE_OFF(fpscr));
BIC(fpscrReg, fpscrReg, FPRFMask);
VCMPE(vA, vB);
VMRS(_PC);
SetCC(CC_LT);
ORR(fpscrReg, fpscrReg, LessThan);
MOV(crReg, 8);
Done1 = B();
SetCC(CC_GT);
ORR(fpscrReg, fpscrReg, GreaterThan);
MOV(crReg, 4);
Done2 = B();
SetCC(CC_EQ);
ORR(fpscrReg, fpscrReg, EqualTo);
MOV(crReg, 2);
Done3 = B();
SetCC();
ORR(fpscrReg, fpscrReg, NANRes);
MOV(crReg, 1);
VCMPE(vA, vA);
VMRS(_PC);
FixupBranch NanA = B_CC(CC_NEQ);
VCMPE(vB, vB);
VMRS(_PC);
FixupBranch NanB = B_CC(CC_NEQ);
SetFPException(fpscrReg, FPSCR_VXVC);
FixupBranch Done4 = B();
SetJumpTarget(NanA);
SetJumpTarget(NanB);
SetFPException(fpscrReg, FPSCR_VXSNAN);
TST(fpscrReg, VEMask);
FixupBranch noVXVC = B_CC(CC_NEQ);
SetFPException(fpscrReg, FPSCR_VXVC);
SetJumpTarget(noVXVC);
SetJumpTarget(Done1);
SetJumpTarget(Done2);
SetJumpTarget(Done3);
SetJumpTarget(Done4);
STRB(crReg, R9, PPCSTATE_OFF(cr_fast) + cr);
STR(fpscrReg, R9, PPCSTATE_OFF(fpscr));
gpr.Unlock(fpscrReg, crReg);
}
void JitArm::fcmpu(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITFloatingPointOff);
u32 a = inst.FA, b = inst.FB;
int cr = inst.CRFD;
ARMReg vA = fpr.R0(a);
ARMReg vB = fpr.R0(b);
ARMReg fpscrReg = gpr.GetReg();
ARMReg crReg = gpr.GetReg();
Operand2 FPRFMask(0x1F, 0xA); // 0x1F000
Operand2 LessThan(0x8, 0xA); // 0x8000
Operand2 GreaterThan(0x4, 0xA); // 0x4000
Operand2 EqualTo(0x2, 0xA); // 0x2000
Operand2 NANRes(0x1, 0xA); // 0x1000
FixupBranch Done1, Done2, Done3;
LDR(fpscrReg, R9, PPCSTATE_OFF(fpscr));
BIC(fpscrReg, fpscrReg, FPRFMask);
VCMPE(vA, vB);
VMRS(_PC);
SetCC(CC_LT);
ORR(fpscrReg, fpscrReg, LessThan);
MOV(crReg, 8);
Done1 = B();
SetCC(CC_GT);
ORR(fpscrReg, fpscrReg, GreaterThan);
MOV(crReg, 4);
Done2 = B();
SetCC(CC_EQ);
ORR(fpscrReg, fpscrReg, EqualTo);
MOV(crReg, 2);
Done3 = B();
SetCC();
ORR(fpscrReg, fpscrReg, NANRes);
MOV(crReg, 1);
VCMPE(vA, vA);
VMRS(_PC);
FixupBranch NanA = B_CC(CC_NEQ);
VCMPE(vB, vB);
VMRS(_PC);
FixupBranch NanB = B_CC(CC_NEQ);
FixupBranch Done4 = B();
SetJumpTarget(NanA);
SetJumpTarget(NanB);
SetFPException(fpscrReg, FPSCR_VXSNAN);
SetJumpTarget(Done1);
SetJumpTarget(Done2);
SetJumpTarget(Done3);
SetJumpTarget(Done4);
STRB(crReg, R9, PPCSTATE_OFF(cr_fast) + cr);
STR(fpscrReg, R9, PPCSTATE_OFF(fpscr));
gpr.Unlock(fpscrReg, crReg);
}
void JitArm::fabsx(UGeckoInstruction inst)
{
INSTRUCTION_START
@@ -14,42 +14,27 @@
#include "Core/PowerPC/JitArm32/JitAsm.h"
#include "Core/PowerPC/JitArm32/JitRegCache.h"
// Assumes that Sign and Zero flags were set by the last operation. Preserves all flags and registers.
// Jit64 ComputerRC is signed
// JIT64 GenerateRC is unsigned
void JitArm::GenerateRC(int cr) {
void JitArm::ComputeRC(ARMReg value, int cr) {
ARMReg rB = gpr.GetReg();
MOV(rB, 0x4); // Result > 0
SetCC(CC_EQ); MOV(rB, 0x2); // Result == 0
SetCC(CC_MI); MOV(rB, 0x8); // Result < 0
SetCC();
Operand2 ASRReg(value, ST_ASR, 31);
STRB(rB, R9, PPCSTATE_OFF(cr_fast) + cr);
gpr.Unlock(rB);
}
void JitArm::ComputeRC(int cr) {
ARMReg rB = gpr.GetReg();
STR(value, R9, PPCSTATE_OFF(cr_val[cr]));
MOV(rB, ASRReg);
STR(rB, R9, PPCSTATE_OFF(cr_val[cr]) + sizeof(u32));
MOV(rB, 0x2); // Result == 0
SetCC(CC_LT); MOV(rB, 0x8); // Result < 0
SetCC(CC_GT); MOV(rB, 0x4); // Result > 0
SetCC();
STRB(rB, R9, PPCSTATE_OFF(cr_fast) + cr);
gpr.Unlock(rB);
}
void JitArm::ComputeRC(s32 value, int cr) {
ARMReg rB = gpr.GetReg();
if (value < 0)
MOV(rB, 0x8);
else if (value > 0)
MOV(rB, 0x4);
else
MOV(rB, 0x2);
Operand2 ASRReg(rB, ST_ASR, 31);
MOVI2R(rB, value);
STR(rB, R9, PPCSTATE_OFF(cr_val[cr]));
MOV(rB, ASRReg);
STR(rB, R9, PPCSTATE_OFF(cr_val[cr]) + sizeof(u32));
STRB(rB, R9, PPCSTATE_OFF(cr_fast) + cr);
gpr.Unlock(rB);
}
@@ -195,7 +180,6 @@ void JitArm::arith(UGeckoInstruction inst)
u32 Imm[2] = {0, 0};
bool Rc = false;
bool carry = false;
bool isUnsigned = false;
bool shiftedImm = false;
switch (inst.OPCD)
@@ -306,7 +290,6 @@ void JitArm::arith(UGeckoInstruction inst)
case 522: // addcox
carry = true;
case 40: // subfx
isUnsigned = true;
case 235: // mullwx
case 266:
case 747: // mullwox
@@ -431,6 +414,8 @@ void JitArm::arith(UGeckoInstruction inst)
if (Rc) ComputeRC(gpr.GetImm(dest), 0);
return;
}
u32 dest = d;
// One or the other isn't a IMM
switch (inst.OPCD)
{
@@ -472,6 +457,7 @@ void JitArm::arith(UGeckoInstruction inst)
case 24:
case 25:
{
dest = a;
ARMReg rA = gpr.GetReg();
RS = gpr.R(s);
RA = gpr.R(a);
@@ -483,6 +469,7 @@ void JitArm::arith(UGeckoInstruction inst)
case 26:
case 27:
{
dest = a;
ARMReg rA = gpr.GetReg();
RS = gpr.R(s);
RA = gpr.R(a);
@@ -495,6 +482,7 @@ void JitArm::arith(UGeckoInstruction inst)
case 28:
case 29:
{
dest = a;
ARMReg rA = gpr.GetReg();
RS = gpr.R(s);
RA = gpr.R(a);
@@ -507,12 +495,14 @@ void JitArm::arith(UGeckoInstruction inst)
switch (inst.SUBOP10)
{
case 24:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
LSLS(RA, RS, RB);
break;
case 28:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
@@ -525,12 +515,14 @@ void JitArm::arith(UGeckoInstruction inst)
SUBS(RD, RB, RA);
break;
case 60:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
BICS(RA, RS, RB);
break;
case 124:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
@@ -545,6 +537,7 @@ void JitArm::arith(UGeckoInstruction inst)
MULS(RD, RA, RB);
break;
case 284:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
@@ -552,6 +545,7 @@ void JitArm::arith(UGeckoInstruction inst)
MVNS(RA, RA);
break;
case 316:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
@@ -559,6 +553,7 @@ void JitArm::arith(UGeckoInstruction inst)
break;
case 412:
{
dest = a;
ARMReg rA = gpr.GetReg();
RA = gpr.R(a);
RS = gpr.R(s);
@@ -569,12 +564,14 @@ void JitArm::arith(UGeckoInstruction inst)
}
break;
case 444:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
ORRS(RA, RS, RB);
break;
case 476:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
@@ -582,12 +579,14 @@ void JitArm::arith(UGeckoInstruction inst)
MVNS(RA, RA);
break;
case 536:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
LSRS(RA, RS, RB);
break;
case 792:
dest = a;
RA = gpr.R(a);
RS = gpr.R(s);
RB = gpr.R(b);
@@ -605,7 +604,7 @@ void JitArm::arith(UGeckoInstruction inst)
break;
}
if (carry) ComputeCarry();
if (Rc) isUnsigned ? GenerateRC() : ComputeRC();
if (Rc) ComputeRC(gpr.R(dest));
}
void JitArm::addex(UGeckoInstruction inst)
@@ -624,7 +623,7 @@ void JitArm::addex(UGeckoInstruction inst)
GetCarryAndClear(rA);
ADDS(RD, RA, RB);
FinalizeCarry(rA);
if (inst.Rc) ComputeRC();
if (inst.Rc) ComputeRC(RD);
gpr.Unlock(rA);
}
@@ -638,10 +637,7 @@ void JitArm::cntlzwx(UGeckoInstruction inst)
ARMReg RS = gpr.R(s);
CLZ(RA, RS);
if (inst.Rc)
{
CMP(RA, 0);
ComputeRC();
}
ComputeRC(RA);
}
void JitArm::mulhwux(UGeckoInstruction inst)
@@ -655,8 +651,8 @@ void JitArm::mulhwux(UGeckoInstruction inst)
ARMReg RB = gpr.R(b);
ARMReg RD = gpr.R(d);
ARMReg rA = gpr.GetReg(false);
UMULLS(rA, RD, RA, RB);
if (inst.Rc) ComputeRC();
UMULL(rA, RD, RA, RB);
if (inst.Rc) ComputeRC(RD);
}
void JitArm::extshx(UGeckoInstruction inst)
@@ -674,10 +670,8 @@ void JitArm::extshx(UGeckoInstruction inst)
ARMReg rA = gpr.R(a);
ARMReg rS = gpr.R(s);
SXTH(rA, rS);
if (inst.Rc){
CMP(rA, 0);
ComputeRC();
}
if (inst.Rc)
ComputeRC(rA);
}
void JitArm::extsbx(UGeckoInstruction inst)
{
@@ -694,10 +688,8 @@ void JitArm::extsbx(UGeckoInstruction inst)
ARMReg rA = gpr.R(a);
ARMReg rS = gpr.R(s);
SXTB(rA, rS);
if (inst.Rc){
CMP(rA, 0);
ComputeRC();
}
if (inst.Rc)
ComputeRC(rA);
}
void JitArm::cmp (UGeckoInstruction inst)
{
@@ -713,11 +705,7 @@ void JitArm::cmp (UGeckoInstruction inst)
return;
}
ARMReg RA = gpr.R(a);
ARMReg RB = gpr.R(b);
CMP(RA, RB);
ComputeRC(crf);
FALLBACK_IF(true);
}
void JitArm::cmpi(UGeckoInstruction inst)
{
@@ -726,71 +714,12 @@ void JitArm::cmpi(UGeckoInstruction inst)
u32 a = inst.RA;
int crf = inst.CRFD;
if (gpr.IsImm(a))
{
ComputeRC((s32)gpr.GetImm(a) - inst.SIMM_16, crf);
else
{
ARMReg RA = gpr.R(a);
if (inst.SIMM_16 >= 0 && inst.SIMM_16 < 256)
CMP(RA, inst.SIMM_16);
else
{
ARMReg rA = gpr.GetReg();
MOVI2R(rA, inst.SIMM_16);
CMP(RA, rA);
gpr.Unlock(rA);
}
ComputeRC(crf);
return;
}
}
void JitArm::cmpl(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
ARMReg RA = gpr.R(inst.RA);
ARMReg RB = gpr.R(inst.RB);
ARMReg rA = gpr.GetReg();
int crf = inst.CRFD;
CMP(RA, RB);
// Unsigned GenerateRC()
MOV(rA, 0x2); // Result == 0
SetCC(CC_LO); MOV(rA, 0x8); // Result < 0
SetCC(CC_HI); MOV(rA, 0x4); // Result > 0
SetCC();
STRB(rA, R9, PPCSTATE_OFF(cr_fast) + crf);
gpr.Unlock(rA);
}
void JitArm::cmpli(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(bJITIntegerOff);
ARMReg RA = gpr.R(inst.RA);
ARMReg rA = gpr.GetReg();
int crf = inst.CRFD;
u32 uimm = (u32)inst.UIMM;
if (uimm < 256)
{
CMP(RA, uimm);
}
else
{
MOVI2R(rA, (u32)inst.UIMM);
CMP(RA, rA);
}
// Unsigned GenerateRC()
MOV(rA, 0x2); // Result == 0
SetCC(CC_LO); MOV(rA, 0x8); // Result < 0
SetCC(CC_HI); MOV(rA, 0x4); // Result > 0
SetCC();
STRB(rA, R9, PPCSTATE_OFF(cr_fast) + crf);
gpr.Unlock(rA);
FALLBACK_IF(true);
}
void JitArm::negx(UGeckoInstruction inst)
@@ -801,11 +730,10 @@ void JitArm::negx(UGeckoInstruction inst)
ARMReg RA = gpr.R(inst.RA);
ARMReg RD = gpr.R(inst.RD);
RSBS(RD, RA, 0);
RSB(RD, RA, 0);
if (inst.Rc)
{
GenerateRC();
}
ComputeRC(RD);
if (inst.OE)
{
BKPT(0x333);
@@ -825,19 +753,12 @@ void JitArm::rlwimix(UGeckoInstruction inst)
MOVI2R(rA, mask);
Operand2 Shift(RS, ST_ROR, 32 - inst.SH); // This rotates left, while ARM has only rotate right, so swap it.
BIC (rB, RA, rA); // RA & ~mask
AND (rA, rA, Shift);
ORR(RA, rB, rA);
if (inst.Rc)
{
BIC (rB, RA, rA); // RA & ~mask
AND (rA, rA, Shift);
ORRS(RA, rB, rA);
GenerateRC();
}
else
{
BIC (rB, RA, rA); // RA & ~mask
AND (rA, rA, Shift);
ORR(RA, rB, rA);
}
ComputeRC(RA);
gpr.Unlock(rA, rB);
}
@@ -853,13 +774,10 @@ void JitArm::rlwinmx(UGeckoInstruction inst)
MOVI2R(rA, mask);
Operand2 Shift(RS, ST_ROR, 32 - inst.SH); // This rotates left, while ARM has only rotate right, so swap it.
AND(RA, rA, Shift);
if (inst.Rc)
{
ANDS(RA, rA, Shift);
GenerateRC();
}
else
AND (RA, rA, Shift);
ComputeRC(RA);
gpr.Unlock(rA);
//m_GPR[inst.RA] = _rotl(m_GPR[inst.RS],inst.SH) & mask;
@@ -882,13 +800,10 @@ void JitArm::rlwnmx(UGeckoInstruction inst)
SUB(rB, rB, RB);
Operand2 Shift(RS, ST_ROR, rB); // Register shifted register
AND(RA, rA, Shift);
if (inst.Rc)
{
ANDS(RA, rA, Shift);
GenerateRC();
}
else
AND (RA, rA, Shift);
ComputeRC(RA);
gpr.Unlock(rA, rB);
}
@@ -908,9 +823,9 @@ void JitArm::srawix(UGeckoInstruction inst)
Operand2 mask = Operand2(2, 2); // XER_CA_MASK
MOV(tmp, RS);
ASRS(RA, RS, amount);
ASR(RA, RS, amount);
if (inst.Rc)
GenerateRC();
ComputeRC(RA);
LSL(tmp, tmp, 32 - amount);
TST(tmp, RA);

Some files were not shown because too many files have changed in this diff Show More