SPU/PPU DisAsm: Implement more constant formation patterns

This commit is contained in:
Eladash 2021-10-17 13:15:58 +03:00 committed by GitHub
parent a4bd1755cf
commit 12efd29121
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 19 deletions

View file

@ -1278,6 +1278,12 @@ void PPUDisAsm::ADDI(ppu_opcode_t op)
else
{
DisAsm_R2_IMM("addi", op.rd, op.ra, op.simm16);
if (auto [is_const, value] = try_get_const_gpr_value(op.ra); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value + op.simm16);
}
}
}
@ -1290,6 +1296,12 @@ void PPUDisAsm::ADDIS(ppu_opcode_t op)
else
{
DisAsm_R2_IMM("addis", op.rd, op.ra, op.simm16);
if (auto [is_const, value] = try_get_const_gpr_value(op.ra); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value + op.simm16 * 65536);
}
}
}
@ -1601,16 +1613,34 @@ void PPUDisAsm::ORIS(ppu_opcode_t op)
{
if (op.rs == 0 && op.ra == 0 && op.uimm16 == 0) { last_opcode += "nop"; return; }
DisAsm_R2_IMM("oris", op.ra, op.rs, op.uimm16);
if (auto [is_const, value] = try_get_const_gpr_value(op.rs); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value | (op.uimm16 << 16));
}
}
void PPUDisAsm::XORI(ppu_opcode_t op)
{
DisAsm_R2_IMM("xori", op.ra, op.rs, op.uimm16);
if (auto [is_const, value] = try_get_const_gpr_value(op.rs); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value ^ op.uimm16);
}
}
void PPUDisAsm::XORIS(ppu_opcode_t op)
{
DisAsm_R2_IMM("xoris", op.ra, op.rs, op.uimm16);
if (auto [is_const, value] = try_get_const_gpr_value(op.rs); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value ^ (op.uimm16 << 16));
}
}
void PPUDisAsm::ANDI(ppu_opcode_t op)

View file

@ -347,27 +347,12 @@ void SPUDisAsm::IOHL(spu_opcode_t op)
{
DisAsm("iohl", spu_reg_name[op.rt], op.i16);
const auto [is_const, value] = try_get_const_value(op.rt);
u32 val0 = value._u32[0];
const auto [is_const, value] = try_get_const_equal_value_array<u32>(op.rt);
// Only print constant for a 4 equal 32-bit constants array
if (is_const && value == v128::from32p(val0))
if (is_const)
{
// Fixup value
val0 |= op.i16;
// Test if potentially a CELL error
if ((val0 >> 28) == 0x8u)
{
// Comment as CELL error
fmt::append(last_opcode, " #%s (0x%x)", CellError{val0}, val0);
}
else
{
// Comment constant formation
fmt::append(last_opcode, " #0x%x", val0);
}
comment_constant(last_opcode, value | op.i16);
}
}

View file

@ -2,8 +2,8 @@
#include "PPCDisAsm.h"
#include "SPUOpcodes.h"
#include "util/v128.hpp"
union v128;
enum spu_stop_syscall : u32;
static constexpr const char* spu_reg_name[128] =
@ -74,6 +74,8 @@ namespace utils
class shm;
}
void comment_constant(std::string& last_opocde, u64 value);
class SPUDisAsm final : public PPCDisAsm
{
std::shared_ptr<utils::shm> m_shm;
@ -186,6 +188,35 @@ public:
std::unique_ptr<CPUDisAsm> copy_type_erased() const override;
std::pair<bool, v128> try_get_const_value(u32 reg, u32 pc = -1, u32 TTL = 10) const;
// Get constant value if the original array is made of only repetitions of the same value
template <typename T> requires (sizeof(T) < sizeof(v128) && !(sizeof(v128) % sizeof(T)))
std::pair<bool, T> try_get_const_equal_value_array(u32 reg, u32 pc = -1, u32 TTL = 10) const
{
auto [ok, res] = try_get_const_value(reg, pc, TTL);
if (!ok)
{
return {};
}
v128 test_value{};
T sample{};
std::memcpy(&sample, res._bytes, sizeof(T));
for (u32 i = 0; i < sizeof(v128); i += sizeof(T))
{
std::memcpy(test_value._bytes + i, &sample, sizeof(T));
}
if (test_value != res)
{
return {};
}
return {ok, sample};
}
struct insert_mask_info
{
u32 type_size;
@ -860,6 +891,12 @@ public:
}
DisAsm("ori", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
if (auto [is_const, value] = try_get_const_equal_value_array<u32>(+op.ra); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value | static_cast<u32>(op.si10));
}
}
void ORHI(spu_opcode_t op)
{
@ -892,6 +929,12 @@ public:
void AI(spu_opcode_t op)
{
DisAsm("ai", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
if (auto [is_const, value] = try_get_const_equal_value_array<u32>(op.ra); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value + static_cast<u32>(op.si10));
}
}
void AHI(spu_opcode_t op)
{
@ -908,6 +951,12 @@ public:
void XORI(spu_opcode_t op)
{
DisAsm("xori", spu_reg_name[op.rt], spu_reg_name[op.ra], op.si10);
if (auto [is_const, value] = try_get_const_equal_value_array<u32>(op.ra); is_const)
{
// Comment constant formation
comment_constant(last_opcode, value ^ static_cast<u32>(op.si10));
}
}
void XORHI(spu_opcode_t op)
{