diff --git a/rpcs3/Emu/RSX/Program/Assembler/CFG.h b/rpcs3/Emu/RSX/Program/Assembler/CFG.h index b2d4ad75a8..9bc44a22d1 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/CFG.h +++ b/rpcs3/Emu/RSX/Program/Assembler/CFG.h @@ -13,7 +13,7 @@ namespace rsx::assembler { std::list blocks; - BasicBlock* push(BasicBlock* parent = nullptr, u32 pc = 0) + BasicBlock* push(BasicBlock* parent = nullptr, u32 pc = 0, EdgeType edge_type = EdgeType::NONE) { if (!parent && !blocks.empty()) { @@ -25,8 +25,8 @@ namespace rsx::assembler if (parent) { - parent->insert_succ(new_block); - new_block->insert_pred(parent); + parent->insert_succ(new_block, edge_type); + new_block->insert_pred(parent, edge_type); } new_block->id = pc; diff --git a/rpcs3/Emu/RSX/Program/Assembler/FPToCFG.cpp b/rpcs3/Emu/RSX/Program/Assembler/FPToCFG.cpp index 0f8cd2ea91..234a0e5450 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/FPToCFG.cpp +++ b/rpcs3/Emu/RSX/Program/Assembler/FPToCFG.cpp @@ -63,16 +63,16 @@ namespace rsx::assembler return nullptr; }; - auto safe_insert_block = [&](BasicBlock* parent, u32 id) -> BasicBlock* + auto safe_insert_block = [&](BasicBlock* parent, u32 id, EdgeType edge_type) -> BasicBlock* { if (auto found = find_block_for_pc(id)) { - parent->insert_succ(found); - found->insert_pred(parent); + parent->insert_succ(found, edge_type); + found->insert_pred(parent, edge_type); return found; } - return graph.push(parent, id); + return graph.push(parent, id, edge_type); }; while (!end) @@ -125,12 +125,12 @@ namespace rsx::assembler { // Inserts if and else and end blocks auto parent = bb; - bb = safe_insert_block(parent, pc + 1); + bb = safe_insert_block(parent, pc + 1, EdgeType::IF); if (src2.end_offset != src1.else_offset) { - else_blocks.push_back(safe_insert_block(parent, src1.else_offset >> 2)); + else_blocks.push_back(safe_insert_block(parent, src1.else_offset >> 2, EdgeType::ELSE)); } - end_blocks.push_back(safe_insert_block(parent, src2.end_offset >> 2)); + end_blocks.push_back(safe_insert_block(parent, src2.end_offset >> 2, EdgeType::ENDIF)); break; } case RSX_FP_OPCODE_LOOP: @@ -138,8 +138,8 @@ namespace rsx::assembler { // Inserts for and end blocks auto parent = bb; - bb = safe_insert_block(parent, pc + 1); - end_blocks.push_back(safe_insert_block(parent, src2.end_offset >> 2)); + bb = safe_insert_block(parent, pc + 1, EdgeType::LOOP); + end_blocks.push_back(safe_insert_block(parent, src2.end_offset >> 2, EdgeType::ENDLOOP)); break; } default: diff --git a/rpcs3/Emu/RSX/Program/Assembler/IR.h b/rpcs3/Emu/RSX/Program/Assembler/IR.h index 53d6080a11..3ff8eb1a3a 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/IR.h +++ b/rpcs3/Emu/RSX/Program/Assembler/IR.h @@ -42,8 +42,19 @@ namespace rsx::assembler std::vector dsts; }; + enum class EdgeType + { + NONE, + IF, + ELSE, + ENDIF, + LOOP, + ENDLOOP + }; + struct FlowEdge { + EdgeType type = EdgeType::NONE; BasicBlock* from = nullptr; BasicBlock* to = nullptr; }; @@ -51,20 +62,25 @@ namespace rsx::assembler struct BasicBlock { u32 id = 0; - std::vector instructions; - std::vector succ; // [0] = if/loop, [1] = else - std::vector pred; // Back edge. + std::vector instructions; // Program instructions for the RSX processor + std::vector succ; // [0] = if/loop, [1] = else + std::vector pred; // Back edge. - void insert_succ(BasicBlock* b) + std::vector prologue; // Prologue, created by passes + std::vector epilogue; // Epilogue, created by passes + + FlowEdge* insert_succ(BasicBlock* b, EdgeType type = EdgeType::NONE) { - FlowEdge e{ .from = this, .to = b }; + FlowEdge e{ .type = type, .from = this, .to = b }; succ.push_back(e); + return &succ.back(); } - void insert_pred(BasicBlock* b) + FlowEdge* insert_pred(BasicBlock* b, EdgeType type = EdgeType::NONE) { - FlowEdge e{ .from = this, .to = b }; + FlowEdge e{ .type = type, .from = this, .to = b }; pred.push_back(e); + return &pred.back(); } }; } diff --git a/rpcs3/tests/test_rsx_cfg.cpp b/rpcs3/tests/test_rsx_cfg.cpp index f868965515..532721fc95 100644 --- a/rpcs3/tests/test_rsx_cfg.cpp +++ b/rpcs3/tests/test_rsx_cfg.cpp @@ -104,6 +104,11 @@ namespace rsx::assembler EXPECT_EQ(it->id, expected.first); EXPECT_EQ(it->instructions.size(), expected.second); } + + // Check edges + EXPECT_EQ(std::find_if(graph.blocks.begin(), graph.blocks.end(), FN(x.id == 3))->pred[0].type, EdgeType::IF); + EXPECT_EQ(std::find_if(graph.blocks.begin(), graph.blocks.end(), FN(x.id == 0))->succ[0].type, EdgeType::IF); + EXPECT_EQ(std::find_if(graph.blocks.begin(), graph.blocks.end(), FN(x.id == 4))->pred[0].type, EdgeType::ENDIF); } TEST(CFG, FpToCFG_NestedIF)