mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-16 04:09:07 +00:00
rsx/cfg: Handle nested IF/LOOP blocks falling out to unsuitable nodes (ELSE).
- In that case, find the node's END node and link to that instead. ELSE nodes are not reachable from children of the preceding IF. - ELSE nodes are special this way, all other types of nodes are reachable by adjacency.
This commit is contained in:
parent
26fd0510ab
commit
d23ea4760b
@ -74,8 +74,19 @@ namespace rsx::assembler
|
||||
{
|
||||
if (auto found = find_block_for_pc(id))
|
||||
{
|
||||
parent->insert_succ(found, edge_type);
|
||||
found->insert_pred(parent, edge_type);
|
||||
auto succ = found;
|
||||
if (found->is_of_type(EdgeType::ELSE) &&
|
||||
(edge_type == EdgeType::ENDIF || edge_type == EdgeType::ENDLOOP))
|
||||
{
|
||||
// If we landed on an "ELSE" node, link to its "ENDIF" counterpart
|
||||
auto if_parent = found->pred.front().from;
|
||||
auto endif_edge = std::find_if(if_parent->succ.begin(), if_parent->succ.end(), FN(x.type == EdgeType::ENDIF));
|
||||
ensure(endif_edge != if_parent->succ.end(), "CFG: Invalid ELSE node");
|
||||
succ = endif_edge->to;
|
||||
}
|
||||
|
||||
parent->insert_succ(succ, edge_type);
|
||||
succ->insert_pred(parent, edge_type);
|
||||
return found;
|
||||
}
|
||||
|
||||
@ -109,7 +120,7 @@ namespace rsx::assembler
|
||||
case EdgeType::IF:
|
||||
case EdgeType::ELSE:
|
||||
{
|
||||
// Find the merge node from the parent
|
||||
// Find the merge node from the parent.
|
||||
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.");
|
||||
bb->insert_succ(succ->to, EdgeType::ENDIF);
|
||||
|
||||
@ -91,6 +91,7 @@ namespace rsx::assembler
|
||||
struct BasicBlock
|
||||
{
|
||||
u32 id = 0;
|
||||
|
||||
std::vector<Instruction> instructions; // Program instructions for the RSX processor
|
||||
std::vector<FlowEdge> succ; // Forward edges. Sorted closest first.
|
||||
std::vector<FlowEdge> pred; // Back edges. Sorted closest first.
|
||||
|
||||
@ -404,4 +404,72 @@ namespace rsx::assembler
|
||||
EXPECT_EQ(SRC0{ .HEX = bb1->epilogue[1].bytecode[1] }.swizzle_x, 2);
|
||||
EXPECT_EQ(SRC0{ .HEX = bb1->epilogue[1].bytecode[1] }.swizzle_y, 3);
|
||||
}
|
||||
|
||||
|
||||
TEST(TestFPIR, RegisterDependencyPass_Complex_IF_ELSE_Simpsons)
|
||||
{
|
||||
// Complex IF-ELSE nest observed in Simpson's game. Rewritten for simplicity.
|
||||
// There is no tail block. No epilogues should be injected in this scenario since H4 (the trigger) is defined on all branches.
|
||||
// R2 is indeed clobbered but the outer ELSE branch should not be able to see the inner IF-ELSE blocks as predecessors.
|
||||
auto ir = FPIR::from_source(R"(
|
||||
MOV R2, #{ 0.25 };
|
||||
IF.GT;
|
||||
SLT R4, H2, #{ 0.125 };
|
||||
IF.GT;
|
||||
ADD H2, H0, H3;
|
||||
FMA H4, R2, H2, H3;
|
||||
ELSE;
|
||||
MOV H2, #{ 0.125 };
|
||||
ADD H0, H0, H2;
|
||||
FMA H4, R2, H2, H3;
|
||||
ENDIF;
|
||||
ELSE;
|
||||
FMA H4, R2, H2, H3;
|
||||
MOV H0, H4;
|
||||
ENDIF;
|
||||
)");
|
||||
|
||||
auto bytecode = ir.compile();
|
||||
|
||||
RSXFragmentProgram prog{};
|
||||
prog.data = bytecode.data();
|
||||
auto graph = deconstruct_fragment_program(prog);
|
||||
|
||||
ASSERT_EQ(graph.blocks.size(), 6);
|
||||
|
||||
FP::RegisterAnnotationPass annotation_pass{ prog };
|
||||
FP::RegisterDependencyPass deps_pass{};
|
||||
|
||||
annotation_pass.run(graph);
|
||||
deps_pass.run(graph);
|
||||
|
||||
const BasicBlock
|
||||
*bb0 = get_graph_block(graph, 0),
|
||||
*bb1 = get_graph_block(graph, 1),
|
||||
*bb2 = get_graph_block(graph, 2),
|
||||
*bb3 = get_graph_block(graph, 3),
|
||||
*bb4 = get_graph_block(graph, 4),
|
||||
*bb5 = get_graph_block(graph, 5);
|
||||
|
||||
// Sanity
|
||||
EXPECT_EQ(bb0->instructions.size(), 2);
|
||||
EXPECT_EQ(bb1->instructions.size(), 2);
|
||||
EXPECT_EQ(bb2->instructions.size(), 2);
|
||||
EXPECT_EQ(bb3->instructions.size(), 3);
|
||||
EXPECT_EQ(bb4->instructions.size(), 2);
|
||||
EXPECT_EQ(bb5->instructions.size(), 0); // Phi/Merge only.
|
||||
|
||||
// Nested children must recursively fall out to the closest ENDIF
|
||||
ASSERT_EQ(bb4->pred.size(), 1);
|
||||
EXPECT_EQ(bb4->pred.front().type, EdgeType::ELSE);
|
||||
EXPECT_EQ(bb5->pred.size(), 4); // 2 IF and 2 ELSE paths exist
|
||||
|
||||
// Check that we get no epilogues
|
||||
EXPECT_EQ(bb0->epilogue.size(), 0);
|
||||
EXPECT_EQ(bb1->epilogue.size(), 0);
|
||||
EXPECT_EQ(bb2->epilogue.size(), 0);
|
||||
EXPECT_EQ(bb3->epilogue.size(), 0);
|
||||
EXPECT_EQ(bb4->epilogue.size(), 0);
|
||||
EXPECT_EQ(bb5->epilogue.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user