rsx/fp: Fix issues with FP decompiler using new CFG system

This commit is contained in:
kd-11 2025-12-06 14:01:54 +03:00 committed by kd-11
parent a7f5514913
commit e8e2d4b93d
3 changed files with 57 additions and 17 deletions

View File

@ -100,15 +100,16 @@ namespace rsx::assembler
if (found) if (found)
{ {
if (!bb->pred.empty()) auto front_edge = std::find_if(bb->pred.begin(), bb->pred.end(), FN(x.type != EdgeType::ENDIF && x.type != EdgeType::ENDLOOP));
if (front_edge != bb->pred.end())
{ {
switch (bb->pred.back().type) auto parent = ensure(front_edge->from);
switch (front_edge->type)
{ {
case EdgeType::IF: case EdgeType::IF:
case EdgeType::ELSE: case EdgeType::ELSE:
{ {
// Find the merge node from the parent // Find the merge node from the parent
auto parent = bb->pred.back().from;
auto succ = std::find_if(parent->succ.begin(), parent->succ.end(), FN(x.type == EdgeType::ENDIF)); auto succ = std::find_if(parent->succ.begin(), parent->succ.end(), FN(x.type == EdgeType::ENDIF));
ensure(succ != parent->succ.end(), "CFG: Broken IF linkage. Please report to developers."); ensure(succ != parent->succ.end(), "CFG: Broken IF linkage. Please report to developers.");
bb->insert_succ(succ->to, EdgeType::ENDIF); bb->insert_succ(succ->to, EdgeType::ENDIF);
@ -118,7 +119,6 @@ namespace rsx::assembler
case EdgeType::LOOP: case EdgeType::LOOP:
{ {
// Find the merge node from the parent // Find the merge node from the parent
auto parent = bb->pred.back().from;
auto succ = std::find_if(parent->succ.begin(), parent->succ.end(), FN(x.type == EdgeType::ENDLOOP)); auto succ = std::find_if(parent->succ.begin(), parent->succ.end(), FN(x.type == EdgeType::ENDLOOP));
ensure(succ != parent->succ.end(), "CFG: Broken LOOP linkage. Please report to developers."); ensure(succ != parent->succ.end(), "CFG: Broken LOOP linkage. Please report to developers.");
bb->insert_succ(succ->to, EdgeType::ENDLOOP); bb->insert_succ(succ->to, EdgeType::ENDLOOP);
@ -130,7 +130,7 @@ namespace rsx::assembler
rsx_log.error("CFG: Unexpected block exit. Report to developers."); rsx_log.error("CFG: Unexpected block exit. Report to developers.");
} }
} }
else else if (bb->pred.empty())
{ {
// Impossible situation. // Impossible situation.
rsx_log.error("CFG: Child block has no parent but has successor! Report to developers."); rsx_log.error("CFG: Child block has no parent but has successor! Report to developers.");

View File

@ -114,5 +114,25 @@ namespace rsx::assembler
pred.push_back(e); pred.push_back(e);
return &pred.back(); return &pred.back();
} }
bool is_of_type(EdgeType type) const
{
return pred.size() == 1 &&
pred.front().type == type;
}
bool has_sibling_of_type(EdgeType type) const
{
if (pred.size() != 1)
{
return false;
}
auto source_node = pred.front().from;
return std::find_if(
source_node->succ.begin(),
source_node->succ.end(),
FN(x.type == type)) != source_node->succ.end();
}
}; };
} }

View File

@ -21,6 +21,7 @@ namespace rsx
} }
using namespace rsx::fragment_program; using namespace rsx::fragment_program;
using namespace rsx::assembler;
// SIMD vector lanes // SIMD vector lanes
enum VectorLane : u8 enum VectorLane : u8
@ -1295,7 +1296,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
std::string FragmentProgramDecompiler::Decompile() std::string FragmentProgramDecompiler::Decompile()
{ {
const auto graph = rsx::assembler::deconstruct_fragment_program(m_prog); const auto graph = deconstruct_fragment_program(m_prog);
m_size = 0; m_size = 0;
m_location = 0; m_location = 0;
m_loop_count = 0; m_loop_count = 0;
@ -1322,22 +1323,41 @@ std::string FragmentProgramDecompiler::Decompile()
{ {
switch (pred.type) switch (pred.type)
{ {
case rsx::assembler::EdgeType::ENDLOOP: case EdgeType::ENDLOOP:
m_loop_count--; // Because of succession rules, endloop is seen twice.
[[ fallthrough ]]; // Once from the the for statement at the end of the parent
case rsx::assembler::EdgeType::ENDIF: // and again at the end of the child block.
m_code_level--; if (pred.from->is_of_type(EdgeType::LOOP))
AddCode("}"); {
m_loop_count--;
m_code_level--;
AddCode("}");
}
break; break;
case rsx::assembler::EdgeType::LOOP: case EdgeType::ENDIF:
{
// Same thing happens with ENDIF
// Once for the IF statement itself
// And again for the child blocks with code for the IF and ELSE paths.
const bool is_else_end = pred.from->is_of_type(EdgeType::ELSE);
const bool is_if_end = pred.from->is_of_type(EdgeType::IF) &&
!pred.from->has_sibling_of_type(EdgeType::ELSE); // Avoid double-counting if the IF has an ELSE sibling
if (is_else_end || is_if_end)
{
m_code_level--;
AddCode("}");
}
break;
}
case EdgeType::LOOP:
m_loop_count++; m_loop_count++;
[[ fallthrough ]]; [[ fallthrough ]];
case rsx::assembler::EdgeType::IF: case EdgeType::IF:
// Instruction will be inserted by the SIP decoder // Instruction will be inserted by the SIP decoder
AddCode("{"); AddCode("{");
m_code_level++; m_code_level++;
break; break;
case rsx::assembler::EdgeType::ELSE: case EdgeType::ELSE:
// This one needs more testing // This one needs more testing
m_code_level--; m_code_level--;
AddCode("}"); AddCode("}");
@ -1440,8 +1460,8 @@ std::string FragmentProgramDecompiler::Decompile()
while (m_code_level > 1) while (m_code_level > 1)
{ {
rsx_log.error("Hanging block found at end of shader. Malformed shader?"); // Happens if the last block was hanging (no merge)
// FIXME: We must always have a merge block on exit to resolve dependencies on outputs
m_code_level--; m_code_level--;
AddCode("}"); AddCode("}");
} }