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;
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
Write8(0x70 + conditionCode);
Write8((u8)(s8)distance);
@ -407,7 +408,9 @@ void XEmitter::SetJumpTarget(const FixupBranch &branch)
{
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)
{

View File

@ -194,6 +194,8 @@ const u8 *DSPEmitter::Compile(int start_addr) {
SetJumpTarget(rLoopCounterExit);
}
blockSize[start_addr]++;
// End the block if we're at a loop end.
if (opcode->branch ||
(DSPAnalyzer::code_flags[addr] & DSPAnalyzer::CODE_LOOP_END) ||
@ -201,8 +203,6 @@ const u8 *DSPEmitter::Compile(int start_addr) {
break;
}
addr += opcode->size;
blockSize[start_addr]++;
}
// ABI_RestoreStack(0);
@ -210,6 +210,13 @@ const u8 *DSPEmitter::Compile(int start_addr) {
RET();
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;
}

View File

@ -117,6 +117,8 @@ private:
DISALLOW_COPY_AND_ASSIGN(DSPEmitter);
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.
// 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]
// EDX = g_dsp.r[DSP_REG_WR0 + 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));
ToMask(EDI);
// if ((tmp & tmb) == tmb)
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);
dsp_increment_one(EAX, EDX, EDI);
// g_dsp.r[reg] = tmp;
MOV(16, M(&g_dsp.r[reg]), R(EAX));
}
// 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]
// EDX = g_dsp.r[DSP_REG_WR0 + 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));
ToMask(EDI);
//compute min from EDI and EAX
// 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);
dsp_decrement_one(EAX, EDX, EDI);
// g_dsp.r[reg] = tmp;
MOV(16, M(&g_dsp.r[reg]), R(EAX));
@ -125,56 +135,50 @@ void DSPEmitter::decrement_addr_reg(int reg)
// EDI = tomask(EDX)
void DSPEmitter::increase_addr_reg(int reg)
{
MOV(16, R(ECX), M(&g_dsp.r[DSP_REG_IX0 + reg]));
//IX0 == 0, bail out
MOVZX(32, 16, ECX, M(&g_dsp.r[DSP_REG_IX0 + reg]));
// IX0 == 0, bail out
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(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));
ToMask(EDI);
//dsp_increment
JumpTarget loop_pos = GetCodePtr();
// 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);
// 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);
// tmp ^= wr_reg
XOR(16, R(EAX), R(EDX));
FixupBranch pos_eq = J();
SetJumpTarget(pos_neq);
// else tmp++
ADD(16, R(EAX), Imm16(1));
SetJumpTarget(pos_eq);
JumpTarget loop_pos = GetCodePtr();
// dsp_increment
dsp_increment_one(EAX, EDX, EDI);
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
J_CC(CC_G, loop_pos);
FixupBranch end_pos = J();
//else, IX0 < 0
// else, IX0 < 0
SetJumpTarget(neg);
JumpTarget loop_neg = GetCodePtr();
//dsp_decrement
// if ((tmp & wr_reg) == 0)
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);
// dsp_decrement
dsp_decrement_one(EAX, EDX, EDI);
ADD(16, R(ECX), Imm16(1)); // value++
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)
{
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));
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(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);
JumpTarget loop_pos = GetCodePtr();
//dsp_decrement
// if ((tmp & wr_reg) == 0)
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);
// dsp_decrement
dsp_decrement_one(EAX, EDX, EDI);
SUB(16, R(ECX), Imm16(1)); // value--
CMP(16, R(ECX), Imm16(0)); // value > 0
J_CC(CC_G, loop_pos);
FixupBranch end_pos = J();
//else, IX0 < 0
// else, IX0 < 0
SetJumpTarget(neg);
//ToMask(WR0), calculating it into EDI
MOV(16, R(EDI), R(EDX));
ToMask(EDI);
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
XOR(16, R(EAX), R(EDX));
FixupBranch pos_eq = J();
SetJumpTarget(pos_neq);
// else tmp++
ADD(16, R(EAX), Imm16(1));
SetJumpTarget(pos_eq);
// dsp_increment
dsp_increment_one(EAX, EDX, EDI);
ADD(16, R(ECX), Imm16(1)); // value++
CMP(16, R(ECX), Imm16(0)); // value < 0