From 12efd29121173ab305e1cc578079860faf8fb6b2 Mon Sep 17 00:00:00 2001 From: Eladash Date: Sun, 17 Oct 2021 13:15:58 +0300 Subject: [PATCH] SPU/PPU DisAsm: Implement more constant formation patterns --- rpcs3/Emu/Cell/PPUDisAsm.cpp | 30 +++++++++++++++++++++ rpcs3/Emu/Cell/SPUDisAsm.cpp | 21 +++------------ rpcs3/Emu/Cell/SPUDisAsm.h | 51 +++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 19 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUDisAsm.cpp b/rpcs3/Emu/Cell/PPUDisAsm.cpp index 1ae59885e5..b088f3e9fc 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.cpp +++ b/rpcs3/Emu/Cell/PPUDisAsm.cpp @@ -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) diff --git a/rpcs3/Emu/Cell/SPUDisAsm.cpp b/rpcs3/Emu/Cell/SPUDisAsm.cpp index 21a8bc16f2..135bb2ab14 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.cpp +++ b/rpcs3/Emu/Cell/SPUDisAsm.cpp @@ -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(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); } } diff --git a/rpcs3/Emu/Cell/SPUDisAsm.h b/rpcs3/Emu/Cell/SPUDisAsm.h index 59db41ac5d..09b1b8633a 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.h +++ b/rpcs3/Emu/Cell/SPUDisAsm.h @@ -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 m_shm; @@ -186,6 +188,35 @@ public: std::unique_ptr copy_type_erased() const override; std::pair 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 requires (sizeof(T) < sizeof(v128) && !(sizeof(v128) % sizeof(T))) + std::pair 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(+op.ra); is_const) + { + // Comment constant formation + comment_constant(last_opcode, value | static_cast(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(op.ra); is_const) + { + // Comment constant formation + comment_constant(last_opcode, value + static_cast(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(op.ra); is_const) + { + // Comment constant formation + comment_constant(last_opcode, value ^ static_cast(op.si10)); + } } void XORHI(spu_opcode_t op) {