mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-06 07:12:28 +01:00
rsx/fp: Use CFG to decompile fragment programs
This commit is contained in:
parent
cb7650240c
commit
5c187f5cda
|
|
@ -234,7 +234,8 @@ std::string FragmentProgramDecompiler::AddCond()
|
||||||
|
|
||||||
std::string FragmentProgramDecompiler::AddConst()
|
std::string FragmentProgramDecompiler::AddConst()
|
||||||
{
|
{
|
||||||
const u32 constant_id = m_size + (4 * sizeof(u32));
|
ensure(m_instruction->length == 8);
|
||||||
|
const u32 constant_id = m_instruction->addr + 16;
|
||||||
u32 index = umax;
|
u32 index = umax;
|
||||||
|
|
||||||
if (auto found = m_constant_offsets.find(constant_id);
|
if (auto found = m_constant_offsets.find(constant_id);
|
||||||
|
|
@ -249,9 +250,6 @@ std::string FragmentProgramDecompiler::AddConst()
|
||||||
m_constant_offsets[constant_id] = index;
|
m_constant_offsets[constant_id] = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip next instruction, its just a literal
|
|
||||||
m_offset = 2 * 4 * sizeof(u32);
|
|
||||||
|
|
||||||
// Return the next offset index
|
// Return the next offset index
|
||||||
return "_fetch_constant(" + std::to_string(index) + ")";
|
return "_fetch_constant(" + std::to_string(index) + ")";
|
||||||
}
|
}
|
||||||
|
|
@ -1317,37 +1315,52 @@ std::string FragmentProgramDecompiler::Decompile()
|
||||||
for (const auto &block : graph.blocks)
|
for (const auto &block : graph.blocks)
|
||||||
{
|
{
|
||||||
// TODO: Handle block prologue if any
|
// TODO: Handle block prologue if any
|
||||||
|
if (!block.pred.empty())
|
||||||
|
{
|
||||||
|
// CFG guarantees predecessors are sorted, closest one first
|
||||||
|
for (const auto& pred : block.pred)
|
||||||
|
{
|
||||||
|
switch (pred.type)
|
||||||
|
{
|
||||||
|
case rsx::assembler::EdgeType::ENDLOOP:
|
||||||
|
m_loop_count--;
|
||||||
|
[[ fallthrough ]];
|
||||||
|
case rsx::assembler::EdgeType::ENDIF:
|
||||||
|
m_code_level--;
|
||||||
|
AddCode("}");
|
||||||
|
break;
|
||||||
|
case rsx::assembler::EdgeType::LOOP:
|
||||||
|
m_loop_count++;
|
||||||
|
[[ fallthrough ]];
|
||||||
|
case rsx::assembler::EdgeType::IF:
|
||||||
|
// Instruction will be inserted by the SIP decoder
|
||||||
|
AddCode("{");
|
||||||
|
m_code_level++;
|
||||||
|
break;
|
||||||
|
case rsx::assembler::EdgeType::ELSE:
|
||||||
|
// This one needs more testing
|
||||||
|
m_code_level--;
|
||||||
|
AddCode("}");
|
||||||
|
AddCode("else");
|
||||||
|
AddCode("{");
|
||||||
|
m_code_level++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Start a new block anyway
|
||||||
|
fmt::throw_exception("Unexpected block found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& inst : block.instructions)
|
for (const auto& inst : block.instructions)
|
||||||
{
|
{
|
||||||
for (auto found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
|
m_instruction = &inst;
|
||||||
found != m_end_offsets.end();
|
|
||||||
found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size))
|
|
||||||
{
|
|
||||||
m_end_offsets.erase(found);
|
|
||||||
m_code_level--;
|
|
||||||
AddCode("}");
|
|
||||||
m_loop_count--;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size);
|
|
||||||
found != m_else_offsets.end();
|
|
||||||
found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size))
|
|
||||||
{
|
|
||||||
m_else_offsets.erase(found);
|
|
||||||
m_code_level--;
|
|
||||||
AddCode("}");
|
|
||||||
AddCode("else");
|
|
||||||
AddCode("{");
|
|
||||||
m_code_level++;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst.HEX = inst.bytecode[0];
|
dst.HEX = inst.bytecode[0];
|
||||||
src0.HEX = inst.bytecode[1];
|
src0.HEX = inst.bytecode[1];
|
||||||
src1.HEX = inst.bytecode[2];
|
src1.HEX = inst.bytecode[2];
|
||||||
src2.HEX = inst.bytecode[3];
|
src2.HEX = inst.bytecode[3];
|
||||||
|
|
||||||
m_offset = 4 * sizeof(u32);
|
|
||||||
opflags = 0;
|
opflags = 0;
|
||||||
|
|
||||||
const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6);
|
const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6);
|
||||||
|
|
@ -1373,43 +1386,14 @@ std::string FragmentProgramDecompiler::Decompile()
|
||||||
break;
|
break;
|
||||||
case RSX_FP_OPCODE_IFE:
|
case RSX_FP_OPCODE_IFE:
|
||||||
AddCode("if($cond)");
|
AddCode("if($cond)");
|
||||||
if (src2.end_offset != src1.else_offset)
|
|
||||||
m_else_offsets.push_back(src1.else_offset << 2);
|
|
||||||
m_end_offsets.push_back(src2.end_offset << 2);
|
|
||||||
AddCode("{");
|
|
||||||
m_code_level++;
|
|
||||||
break;
|
break;
|
||||||
case RSX_FP_OPCODE_LOOP:
|
case RSX_FP_OPCODE_LOOP:
|
||||||
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
AddCode(fmt::format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
|
||||||
{
|
|
||||||
AddCode(fmt::format("//$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP",
|
|
||||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddCode(fmt::format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
|
|
||||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
||||||
m_loop_count++;
|
|
||||||
m_end_offsets.push_back(src2.end_offset << 2);
|
|
||||||
AddCode("{");
|
|
||||||
m_code_level++;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case RSX_FP_OPCODE_REP:
|
case RSX_FP_OPCODE_REP:
|
||||||
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
AddCode(fmt::format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
|
||||||
{
|
|
||||||
AddCode(fmt::format("//$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP",
|
|
||||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddCode(fmt::format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
|
|
||||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
||||||
m_loop_count++;
|
|
||||||
m_end_offsets.push_back(src2.end_offset << 2);
|
|
||||||
AddCode("{");
|
|
||||||
m_code_level++;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case RSX_FP_OPCODE_RET:
|
case RSX_FP_OPCODE_RET:
|
||||||
AddFlowOp("return");
|
AddFlowOp("return");
|
||||||
|
|
@ -1447,9 +1431,7 @@ std::string FragmentProgramDecompiler::Decompile()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_size += m_offset;
|
m_size += m_instruction->length * 4;
|
||||||
ensure((m_offset & 15) == 0); // Must be aligned to 16 bytes
|
|
||||||
|
|
||||||
if (dst.end) break;
|
if (dst.end) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,17 +41,16 @@ class FragmentProgramDecompiler
|
||||||
SRC2 src2;
|
SRC2 src2;
|
||||||
u32 opflags;
|
u32 opflags;
|
||||||
|
|
||||||
|
const rsx::assembler::Instruction* m_instruction;
|
||||||
|
|
||||||
std::string main;
|
std::string main;
|
||||||
u32& m_size;
|
u32& m_size;
|
||||||
u32 m_const_index = 0;
|
u32 m_const_index = 0;
|
||||||
u32 m_offset;
|
|
||||||
u32 m_location = 0;
|
u32 m_location = 0;
|
||||||
bool m_is_valid_ucode = true;
|
bool m_is_valid_ucode = true;
|
||||||
|
|
||||||
u32 m_loop_count;
|
u32 m_loop_count;
|
||||||
int m_code_level;
|
int m_code_level;
|
||||||
std::vector<u32> m_end_offsets;
|
|
||||||
std::vector<u32> m_else_offsets;
|
|
||||||
std::unordered_map<u32, u32> m_constant_offsets;
|
std::unordered_map<u32, u32> m_constant_offsets;
|
||||||
|
|
||||||
std::array<rsx::MixedPrecisionRegister, 64> temp_registers;
|
std::array<rsx::MixedPrecisionRegister, 64> temp_registers;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue