rsx: Add flow information to flow edges

This commit is contained in:
kd-11 2025-11-23 19:25:07 +03:00 committed by kd-11
parent f300832edb
commit 42d9065c11
4 changed files with 40 additions and 19 deletions

View file

@ -13,7 +13,7 @@ namespace rsx::assembler
{
std::list<BasicBlock> 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;

View file

@ -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:

View file

@ -42,8 +42,19 @@ namespace rsx::assembler
std::vector<RegisterRef> 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<Instruction> instructions;
std::vector<Instruction> instructions; // Program instructions for the RSX processor
std::vector<FlowEdge> succ; // [0] = if/loop, [1] = else
std::vector<FlowEdge> pred; // Back edge.
void insert_succ(BasicBlock* b)
std::vector<Instruction> prologue; // Prologue, created by passes
std::vector<Instruction> 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();
}
};
}

View file

@ -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)