rsx/fp: Use CFG to decompile fragment programs

This commit is contained in:
kd-11 2025-11-23 21:12:44 +03:00 committed by kd-11
parent cb7650240c
commit 5c187f5cda
2 changed files with 44 additions and 63 deletions

View file

@ -234,7 +234,8 @@ std::string FragmentProgramDecompiler::AddCond()
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;
if (auto found = m_constant_offsets.find(constant_id);
@ -249,9 +250,6 @@ std::string FragmentProgramDecompiler::AddConst()
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 "_fetch_constant(" + std::to_string(index) + ")";
}
@ -1317,37 +1315,52 @@ std::string FragmentProgramDecompiler::Decompile()
for (const auto &block : graph.blocks)
{
// 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 (auto found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
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++;
}
m_instruction = &inst;
dst.HEX = inst.bytecode[0];
src0.HEX = inst.bytecode[1];
src1.HEX = inst.bytecode[2];
src2.HEX = inst.bytecode[3];
m_offset = 4 * sizeof(u32);
opflags = 0;
const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6);
@ -1373,43 +1386,14 @@ std::string FragmentProgramDecompiler::Decompile()
break;
case RSX_FP_OPCODE_IFE:
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;
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) {} //-> %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",
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++;
m_end_offsets.push_back(src2.end_offset << 2);
AddCode("{");
m_code_level++;
}
break;
case RSX_FP_OPCODE_REP:
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) {} //-> %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",
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++;
m_end_offsets.push_back(src2.end_offset << 2);
AddCode("{");
m_code_level++;
}
break;
case RSX_FP_OPCODE_RET:
AddFlowOp("return");
@ -1447,9 +1431,7 @@ std::string FragmentProgramDecompiler::Decompile()
break;
}
m_size += m_offset;
ensure((m_offset & 15) == 0); // Must be aligned to 16 bytes
m_size += m_instruction->length * 4;
if (dst.end) break;
}

View file

@ -41,17 +41,16 @@ class FragmentProgramDecompiler
SRC2 src2;
u32 opflags;
const rsx::assembler::Instruction* m_instruction;
std::string main;
u32& m_size;
u32 m_const_index = 0;
u32 m_offset;
u32 m_location = 0;
bool m_is_valid_ucode = true;
u32 m_loop_count;
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::array<rsx::MixedPrecisionRegister, 64> temp_registers;