Fix a bug in DSP Jit where branches had a blockSize of zero.

Add some useful checking to J_CC/SetJumpTarget.
Refactor increment/decrement and reuse code with increase/decrease.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5816 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
j4ck.fr0st 2010-06-30 16:17:20 +00:00
parent 599a4c974d
commit 89c4068663
4 changed files with 109 additions and 109 deletions

View File

@ -389,7 +389,8 @@ void XEmitter::J_CC(CCFlags conditionCode, const u8 * addr, bool force5Bytes)
u64 fn = (u64)addr; u64 fn = (u64)addr;
if (!force5Bytes) if (!force5Bytes)
{ {
s32 distance = (s32)(fn - ((u64)code + 2)); //TODO - sanity check s32 distance = (s32)(fn - ((u64)code + 2));
_assert_msg_(DYNA_REC, distance < 0x80, "Jump target too far away, needs force5Bytes = true");
//8 bits will do //8 bits will do
Write8(0x70 + conditionCode); Write8(0x70 + conditionCode);
Write8((u8)(s8)distance); Write8((u8)(s8)distance);
@ -407,7 +408,9 @@ void XEmitter::SetJumpTarget(const FixupBranch &branch)
{ {
if (branch.type == 0) if (branch.type == 0)
{ {
branch.ptr[-1] = (u8)(s8)(code - branch.ptr); s32 distance = (s32)(code - branch.ptr);
_assert_msg_(DYNA_REC, distance < 0x80, "Jump target too far away, needs force5Bytes = true");
branch.ptr[-1] = (u8)(s8)distance;
} }
else if (branch.type == 1) else if (branch.type == 1)
{ {

View File

@ -194,6 +194,8 @@ const u8 *DSPEmitter::Compile(int start_addr) {
SetJumpTarget(rLoopCounterExit); SetJumpTarget(rLoopCounterExit);
} }
blockSize[start_addr]++;
// End the block if we're at a loop end. // End the block if we're at a loop end.
if (opcode->branch || if (opcode->branch ||
(DSPAnalyzer::code_flags[addr] & DSPAnalyzer::CODE_LOOP_END) || (DSPAnalyzer::code_flags[addr] & DSPAnalyzer::CODE_LOOP_END) ||
@ -201,8 +203,6 @@ const u8 *DSPEmitter::Compile(int start_addr) {
break; break;
} }
addr += opcode->size; addr += opcode->size;
blockSize[start_addr]++;
} }
// ABI_RestoreStack(0); // ABI_RestoreStack(0);
@ -210,6 +210,13 @@ const u8 *DSPEmitter::Compile(int start_addr) {
RET(); RET();
blocks[start_addr] = (CompiledCode)entryPoint; blocks[start_addr] = (CompiledCode)entryPoint;
if (blockSize[start_addr] == 0)
{
// just a safeguard, should never happen anymore.
// if it does we might get stuck over in RunForCycles.
ERROR_LOG(DSPLLE, "Block at 0x%04x has zero size", start_addr);
blockSize[start_addr] = 1;
}
return entryPoint; return entryPoint;
} }

View File

@ -117,6 +117,8 @@ private:
DISALLOW_COPY_AND_ASSIGN(DSPEmitter); DISALLOW_COPY_AND_ASSIGN(DSPEmitter);
void ToMask(Gen::X64Reg value_reg = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI); void ToMask(Gen::X64Reg value_reg = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI);
void dsp_increment_one(Gen::X64Reg ar = Gen::EAX, Gen::X64Reg wr = Gen::EDX, Gen::X64Reg wr_pow = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI);
void dsp_decrement_one(Gen::X64Reg ar = Gen::EAX, Gen::X64Reg wr = Gen::EDX, Gen::X64Reg wr_pow = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI);
}; };

View File

@ -45,6 +45,25 @@ void DSPEmitter::ToMask(X64Reg value_reg, X64Reg temp_reg)
// HORRIBLE UGLINESS, someone please fix. // HORRIBLE UGLINESS, someone please fix.
// See http://code.google.com/p/dolphin-emu/source/detail?r=3125 // See http://code.google.com/p/dolphin-emu/source/detail?r=3125
void DSPEmitter::dsp_increment_one(X64Reg ar, X64Reg wr, X64Reg wr_pow, X64Reg temp_reg)
{
// if ((tmp & tmb) == tmb)
MOV(16, R(temp_reg), R(ar));
AND(16, R(temp_reg), R(wr_pow));
CMP(16, R(temp_reg), R(wr_pow));
FixupBranch not_equal = J_CC(CC_NE);
// tmp -= wr_reg
SUB(16, R(ar), R(wr));
FixupBranch end = J();
SetJumpTarget(not_equal);
// else tmp++
ADD(16, R(ar), Imm16(1));
SetJumpTarget(end);
}
// EAX = g_dsp.r[reg] // EAX = g_dsp.r[reg]
// EDX = g_dsp.r[DSP_REG_WR0 + reg] // EDX = g_dsp.r[DSP_REG_WR0 + reg]
void DSPEmitter::increment_addr_reg(int reg) void DSPEmitter::increment_addr_reg(int reg)
@ -57,27 +76,40 @@ void DSPEmitter::increment_addr_reg(int reg)
MOV(16, R(EDI), R(EDX)); MOV(16, R(EDI), R(EDX));
ToMask(EDI); ToMask(EDI);
// if ((tmp & tmb) == tmb) dsp_increment_one(EAX, EDX, EDI);
MOV(16, R(ESI), R(EAX));
AND(16, R(ESI), R(EDI));
CMP(16, R(ESI), R(EDI));
FixupBranch not_equal = J_CC(CC_NE);
// tmp -= wr_reg
SUB(16, R(EAX), R(EDX));
FixupBranch end = J();
SetJumpTarget(not_equal);
// else tmp++
ADD(16, R(EAX), Imm16(1));
SetJumpTarget(end);
// g_dsp.r[reg] = tmp; // g_dsp.r[reg] = tmp;
MOV(16, M(&g_dsp.r[reg]), R(EAX)); MOV(16, M(&g_dsp.r[reg]), R(EAX));
} }
// See http://code.google.com/p/dolphin-emu/source/detail?r=3125 // See http://code.google.com/p/dolphin-emu/source/detail?r=3125
void DSPEmitter::dsp_decrement_one(X64Reg ar, X64Reg wr, X64Reg wr_pow, X64Reg temp_reg)
{
// compute min from wr_pow and ar
// min = (tmb+1-ar)&tmb;
LEA(16, temp_reg, MDisp(wr_pow, 1));
SUB(16, R(temp_reg), R(ar));
AND(16, R(temp_reg), R(wr_pow));
// wr < min
CMP(16, R(wr), R(temp_reg));
FixupBranch wr_lt_min = J_CC(CC_B);
// !min
TEST(16, R(temp_reg), R(temp_reg));
FixupBranch min_zero = J_CC(CC_Z);
// ar--;
SUB(16, R(ar), Imm16(1));
FixupBranch end = J();
// ar += wr;
SetJumpTarget(wr_lt_min);
SetJumpTarget(min_zero);
ADD(16, R(ar), R(wr));
SetJumpTarget(end);
}
// EAX = g_dsp.r[reg] // EAX = g_dsp.r[reg]
// EDX = g_dsp.r[DSP_REG_WR0 + reg] // EDX = g_dsp.r[DSP_REG_WR0 + reg]
void DSPEmitter::decrement_addr_reg(int reg) void DSPEmitter::decrement_addr_reg(int reg)
@ -90,29 +122,7 @@ void DSPEmitter::decrement_addr_reg(int reg)
MOV(16, R(EDI), R(EDX)); MOV(16, R(EDI), R(EDX));
ToMask(EDI); ToMask(EDI);
//compute min from EDI and EAX dsp_decrement_one(EAX, EDX, EDI);
// min = (tmb+1-ar)&tmb;
LEA(16, ESI, MDisp(EDI, 1));
SUB(16, R(ESI), R(EAX));
AND(16, R(ESI), R(EDI));
// wr < min
CMP(16, R(EDX), R(ESI));
FixupBranch wr_lt_min = J_CC(CC_B);
// !min
TEST(16, R(ESI), R(ESI));
FixupBranch min_zero = J_CC(CC_Z);
// ar--;
SUB(16, R(EAX), Imm16(1));
FixupBranch end = J();
// ar += wr;
SetJumpTarget(wr_lt_min);
SetJumpTarget(min_zero);
ADD(16, R(EAX), R(EDX));
SetJumpTarget(end);
// g_dsp.r[reg] = tmp; // g_dsp.r[reg] = tmp;
MOV(16, M(&g_dsp.r[reg]), R(EAX)); MOV(16, M(&g_dsp.r[reg]), R(EAX));
@ -125,56 +135,50 @@ void DSPEmitter::decrement_addr_reg(int reg)
// EDI = tomask(EDX) // EDI = tomask(EDX)
void DSPEmitter::increase_addr_reg(int reg) void DSPEmitter::increase_addr_reg(int reg)
{ {
MOV(16, R(ECX), M(&g_dsp.r[DSP_REG_IX0 + reg])); MOVZX(32, 16, ECX, M(&g_dsp.r[DSP_REG_IX0 + reg]));
//IX0 == 0, bail out // IX0 == 0, bail out
TEST(16, R(ECX), R(ECX)); TEST(16, R(ECX), R(ECX));
FixupBranch end = J_CC(CC_Z); // code too long for a 5-byte jump
// TODO: optimize a bit, maybe merge loops?
FixupBranch end = J_CC(CC_Z, true);
MOV(16, R(EAX), M(&g_dsp.r[reg])); MOV(16, R(EAX), M(&g_dsp.r[reg]));
MOV(16, R(EDX), M(&g_dsp.r[DSP_REG_WR0 + reg])); MOV(16, R(EDX), M(&g_dsp.r[DSP_REG_WR0 + reg]));
//IX0 > 0
FixupBranch neg = J_CC(CC_L);
//ToMask(WR0), calculating it into EDI // ToMask(WR0), calculating it into EDI
MOV(16, R(EDI), R(EDX)); MOV(16, R(EDI), R(EDX));
ToMask(EDI); ToMask(EDI);
//dsp_increment // IX0 > 0
JumpTarget loop_pos = GetCodePtr(); // TODO: ToMask flushes flags set by TEST,
// if ((tmp & tmb) == tmb) // needs another CMP here.
MOV(16, R(ESI), R(EAX)); CMP(16, R(ECX), Imm16(0));
AND(16, R(ESI), R(EDI)); FixupBranch neg = J_CC(CC_L);
CMP(16, R(ESI), R(EDI));
FixupBranch pos_neq = J_CC(CC_NE);
// tmp ^= wr_reg JumpTarget loop_pos = GetCodePtr();
XOR(16, R(EAX), R(EDX));
FixupBranch pos_eq = J(); // dsp_increment
SetJumpTarget(pos_neq); dsp_increment_one(EAX, EDX, EDI);
// else tmp++
ADD(16, R(EAX), Imm16(1));
SetJumpTarget(pos_eq);
SUB(16, R(ECX), Imm16(1)); // value-- SUB(16, R(ECX), Imm16(1)); // value--
CMP(16, M(&g_dsp.r[DSP_REG_IX0 + reg]), Imm16(127));
FixupBranch dbg = J_CC(CC_NE);
CMP(16, R(ECX), Imm16(1));
FixupBranch dbg2 = J_CC(CC_NE);
INT3();
SetJumpTarget(dbg2);
SetJumpTarget(dbg);
CMP(16, R(ECX), Imm16(0)); // value > 0 CMP(16, R(ECX), Imm16(0)); // value > 0
J_CC(CC_G, loop_pos); J_CC(CC_G, loop_pos);
FixupBranch end_pos = J(); FixupBranch end_pos = J();
//else, IX0 < 0 // else, IX0 < 0
SetJumpTarget(neg); SetJumpTarget(neg);
JumpTarget loop_neg = GetCodePtr(); JumpTarget loop_neg = GetCodePtr();
//dsp_decrement
// if ((tmp & wr_reg) == 0)
TEST(16, R(EAX), R(EDX));
FixupBranch neg_nz = J_CC(CC_NZ); // dsp_decrement
// tmp |= wr_reg; dsp_decrement_one(EAX, EDX, EDI);
OR(16, R(EAX), R(EDX));
FixupBranch neg_z = J();
SetJumpTarget(neg_nz);
// else tmp--
SUB(16, R(EAX), Imm16(1));
SetJumpTarget(neg_z);
ADD(16, R(ECX), Imm16(1)); // value++ ADD(16, R(ECX), Imm16(1)); // value++
CMP(16, R(ECX), Imm16(0)); // value < 0 CMP(16, R(ECX), Imm16(0)); // value < 0
@ -196,57 +200,41 @@ void DSPEmitter::increase_addr_reg(int reg)
void DSPEmitter::decrease_addr_reg(int reg) void DSPEmitter::decrease_addr_reg(int reg)
{ {
MOV(16, R(ECX), M(&g_dsp.r[DSP_REG_IX0 + reg])); MOV(16, R(ECX), M(&g_dsp.r[DSP_REG_IX0 + reg]));
//IX0 == 0, bail out // IX0 == 0, bail out
TEST(16, R(ECX), R(ECX)); TEST(16, R(ECX), R(ECX));
FixupBranch end = J_CC(CC_Z); // code too long for a 5-byte jump
// TODO: optimize a bit, maybe merge loops?
FixupBranch end = J_CC(CC_Z, true);
MOV(16, R(EAX), M(&g_dsp.r[reg])); MOV(16, R(EAX), M(&g_dsp.r[reg]));
MOV(16, R(EDX), M(&g_dsp.r[DSP_REG_WR0 + reg])); MOV(16, R(EDX), M(&g_dsp.r[DSP_REG_WR0 + reg]));
//IX0 > 0
// ToMask(WR0), calculating it into EDI
MOV(16, R(EDI), R(EDX));
ToMask(EDI);
// IX0 > 0
// TODO: ToMask flushes flags set by TEST,
// needs another CMP here.
CMP(16, R(ECX), Imm16(0));
FixupBranch neg = J_CC(CC_L); FixupBranch neg = J_CC(CC_L);
JumpTarget loop_pos = GetCodePtr(); JumpTarget loop_pos = GetCodePtr();
//dsp_decrement // dsp_decrement
// if ((tmp & wr_reg) == 0) dsp_decrement_one(EAX, EDX, EDI);
TEST(16, R(EAX), R(EDX));
FixupBranch neg_nz = J_CC(CC_NZ);
// tmp |= wr_reg;
OR(16, R(EAX), R(EDX));
FixupBranch neg_z = J();
SetJumpTarget(neg_nz);
// else tmp--
SUB(16, R(EAX), Imm16(1));
SetJumpTarget(neg_z);
SUB(16, R(ECX), Imm16(1)); // value-- SUB(16, R(ECX), Imm16(1)); // value--
CMP(16, R(ECX), Imm16(0)); // value > 0 CMP(16, R(ECX), Imm16(0)); // value > 0
J_CC(CC_G, loop_pos); J_CC(CC_G, loop_pos);
FixupBranch end_pos = J(); FixupBranch end_pos = J();
//else, IX0 < 0 // else, IX0 < 0
SetJumpTarget(neg); SetJumpTarget(neg);
//ToMask(WR0), calculating it into EDI
MOV(16, R(EDI), R(EDX));
ToMask(EDI);
JumpTarget loop_neg = GetCodePtr(); JumpTarget loop_neg = GetCodePtr();
//dsp_increment
// if ((tmp & tmb) == tmb)
MOV(16, R(ESI), R(EAX));
AND(16, R(ESI), R(EDI));
CMP(16, R(ESI), R(EDI));
FixupBranch pos_neq = J_CC(CC_NE);
// tmp ^= wr_reg // dsp_increment
XOR(16, R(EAX), R(EDX)); dsp_increment_one(EAX, EDX, EDI);
FixupBranch pos_eq = J();
SetJumpTarget(pos_neq);
// else tmp++
ADD(16, R(EAX), Imm16(1));
SetJumpTarget(pos_eq);
ADD(16, R(ECX), Imm16(1)); // value++ ADD(16, R(ECX), Imm16(1)); // value++
CMP(16, R(ECX), Imm16(0)); // value < 0 CMP(16, R(ECX), Imm16(0)); // value < 0