mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-26 04:32:35 +01:00
PPU Analyzer: Fixup greedy instruction search
This commit is contained in:
parent
53ba38e98d
commit
a02c168a0d
@ -587,6 +587,23 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
return false;
|
||||
};
|
||||
|
||||
auto can_trap_continue = [](ppu_opcode_t op, ppu_itype::type type)
|
||||
{
|
||||
if ((op.bo & 0x1c) == 0x1c || (op.bo & 0x7) == 0x7)
|
||||
{
|
||||
// All signed or unsigned <=>, must be true
|
||||
return false;
|
||||
}
|
||||
|
||||
if (op.simm16 == 0 && (type == ppu_itype::TWI || type == ppu_itype::TDI) && (op.bo & 0x5) == 0x5)
|
||||
{
|
||||
// Logically greater or equal to 0
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Register new function
|
||||
auto add_func = [&](u32 addr, u32 toc, u32 caller) -> ppu_function&
|
||||
{
|
||||
@ -1395,9 +1412,9 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
block.second = _ptr.addr() - block.first;
|
||||
break;
|
||||
}
|
||||
else if (type & ppu_itype::trap)
|
||||
else if (type & ppu_itype::trap && op.bo)
|
||||
{
|
||||
if (op.bo != 31)
|
||||
if (can_trap_continue(op, type))
|
||||
{
|
||||
add_block(_ptr.addr());
|
||||
}
|
||||
@ -1782,7 +1799,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
case ppu_itype::TDI:
|
||||
case ppu_itype::TWI:
|
||||
{
|
||||
if (op.ra == 1u || op.ra == 13u || op.ra == 2u)
|
||||
if (op.bo && (op.ra == 1u || op.ra == 13u || op.ra == 2u))
|
||||
{
|
||||
// Non-user registers, checking them against a constant value makes no sense
|
||||
is_good = false;
|
||||
@ -1793,16 +1810,36 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
}
|
||||
case ppu_itype::TD:
|
||||
case ppu_itype::TW:
|
||||
{
|
||||
if (!op.bo)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!can_trap_continue(op, type))
|
||||
{
|
||||
is_fallback = false;
|
||||
}
|
||||
|
||||
[[fallthrough]];
|
||||
}
|
||||
case ppu_itype::B:
|
||||
case ppu_itype::BC:
|
||||
{
|
||||
if (type == ppu_itype::B)
|
||||
if (type == ppu_itype::B || (type == ppu_itype::BC && (op.bo & 0x14) == 0x14))
|
||||
{
|
||||
is_fallback = false;
|
||||
}
|
||||
|
||||
if (type == ppu_itype::B || type == ppu_itype::BC)
|
||||
{
|
||||
if (type == ppu_itype::BC && (op.bo & 0x14) == 0x14 && op.bo & 0xd)
|
||||
{
|
||||
// Invalid form
|
||||
is_good = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (entry == 0 && op.aa)
|
||||
{
|
||||
// Ignore absolute branches in PIC (PRX)
|
||||
@ -1829,7 +1866,12 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
}
|
||||
|
||||
// Test another instruction just in case (testing more is unlikely to improve results by much)
|
||||
if (!(type0 & ppu_itype::branch))
|
||||
|
||||
if (type0 == ppu_itype::SC || (type0 & ppu_itype::trap && !can_trap_continue(test_op, type0)))
|
||||
{
|
||||
// May not be followed by a valid instruction
|
||||
}
|
||||
else if (!(type0 & ppu_itype::branch))
|
||||
{
|
||||
if (target + 4 >= segs[0].addr + segs[0].size)
|
||||
{
|
||||
@ -1845,8 +1887,8 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (u32 target0 = (test_op.aa ? 0 : target) + (type == ppu_itype::B ? +test_op.bt24 : +test_op.bt14);
|
||||
target0 < segs[0].addr || target0 >= segs[0].addr + segs[0].size)
|
||||
else if (u32 target0 = (test_op.aa ? 0 : target) + (type0 == ppu_itype::B ? +test_op.bt24 : +test_op.bt14);
|
||||
(type0 == ppu_itype::B || ppu_itype::BC) && target0 < segs[0].addr || target0 >= segs[0].addr + segs[0].size)
|
||||
{
|
||||
// Sanity check
|
||||
is_good = false;
|
||||
@ -1855,7 +1897,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
|
||||
if (target != i_pos && !fmap.contains(target))
|
||||
{
|
||||
if (block_set.count(target) == 0 && std::count(block_edges, block_edges + edge_count, target) == 0)
|
||||
if (block_set.count(target) == 0)
|
||||
{
|
||||
ppu_log.trace("Block target found: 0x%x (i_pos=0x%x)", target, i_pos);
|
||||
block_queue.emplace_back(target, 0);
|
||||
@ -1870,7 +1912,7 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
case ppu_itype::BCLR:
|
||||
case ppu_itype::SC:
|
||||
{
|
||||
if (type == ppu_itype::SC && op.opcode != ppu_instructions::SC(0))
|
||||
if (type == ppu_itype::SC && op.opcode != ppu_instructions::SC(0) && op.opcode != ppu_instructions::SC(1))
|
||||
{
|
||||
// Strict garbage filter
|
||||
is_good = false;
|
||||
@ -1891,13 +1933,19 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, const std::b
|
||||
break;
|
||||
}
|
||||
|
||||
if ((type & ppu_itype::branch && op.lk) || type & ppu_itype::trap || type == ppu_itype::BC)
|
||||
if (type == ppu_itype::BCCTR || type == ppu_itype::BCLR)
|
||||
{
|
||||
is_fallback = false;
|
||||
}
|
||||
|
||||
if ((type & ppu_itype::branch && op.lk) || is_fallback)
|
||||
{
|
||||
// if farther instructions are valid: register all blocks
|
||||
// Otherwise, register none (all or nothing)
|
||||
if (edge_count < std::size(block_edges))
|
||||
if (edge_count < std::size(block_edges) && i_pos + 4 < lim)
|
||||
{
|
||||
block_edges[edge_count++] = i_pos + 4;
|
||||
is_fallback = true; // Reset value
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user