Skip to content

Commit bd1b46b

Browse files
committed
rsx/fp: Use CFG to decompile fragment programs
1 parent 26556d5 commit bd1b46b

File tree

2 files changed

+43
-62
lines changed

2 files changed

+43
-62
lines changed

rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp

Lines changed: 41 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@ std::string FragmentProgramDecompiler::AddCond()
234234

235235
std::string FragmentProgramDecompiler::AddConst()
236236
{
237-
const u32 constant_id = m_size + (4 * sizeof(u32));
237+
ensure(m_instruction->length == 8);
238+
const u32 constant_id = m_instruction->addr + 16;
238239
u32 index = umax;
239240

240241
if (auto found = m_constant_offsets.find(constant_id);
@@ -249,9 +250,6 @@ std::string FragmentProgramDecompiler::AddConst()
249250
m_constant_offsets[constant_id] = index;
250251
}
251252

252-
// Skip next instruction, its just a literal
253-
m_offset = 2 * 4 * sizeof(u32);
254-
255253
// Return the next offset index
256254
return "_fetch_constant(" + std::to_string(index) + ")";
257255
}
@@ -1317,37 +1315,52 @@ std::string FragmentProgramDecompiler::Decompile()
13171315
for (const auto &block : graph.blocks)
13181316
{
13191317
// TODO: Handle block prologue if any
1320-
1321-
for (const auto& inst : block.instructions)
1318+
if (!block.pred.empty())
13221319
{
1323-
for (auto found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
1324-
found != m_end_offsets.end();
1325-
found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size))
1320+
// CFG guarantees predecessors are sorted, closest one first
1321+
for (const auto& pred : block.pred)
13261322
{
1327-
m_end_offsets.erase(found);
1328-
m_code_level--;
1329-
AddCode("}");
1330-
m_loop_count--;
1323+
switch (pred.type)
1324+
{
1325+
case rsx::assembler::EdgeType::ENDLOOP:
1326+
m_loop_count--;
1327+
[[ fallthrough ]];
1328+
case rsx::assembler::EdgeType::ENDIF:
1329+
m_code_level--;
1330+
AddCode("}");
1331+
break;
1332+
case rsx::assembler::EdgeType::LOOP:
1333+
m_loop_count++;
1334+
[[ fallthrough ]];
1335+
case rsx::assembler::EdgeType::IF:
1336+
// Instruction will be inserted by the SIP decoder
1337+
AddCode("{");
1338+
m_code_level++;
1339+
break;
1340+
case rsx::assembler::EdgeType::ELSE:
1341+
// This one needs more testing
1342+
m_code_level--;
1343+
AddCode("}");
1344+
AddCode("else");
1345+
AddCode("{");
1346+
m_code_level++;
1347+
break;
1348+
default:
1349+
// Start a new block anyway
1350+
fmt::throw_exception("Unexpected block found");
1351+
}
13311352
}
1353+
}
13321354

1333-
for (auto found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size);
1334-
found != m_else_offsets.end();
1335-
found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size))
1336-
{
1337-
m_else_offsets.erase(found);
1338-
m_code_level--;
1339-
AddCode("}");
1340-
AddCode("else");
1341-
AddCode("{");
1342-
m_code_level++;
1343-
}
1355+
for (const auto& inst : block.instructions)
1356+
{
1357+
m_instruction = &inst;
13441358

13451359
dst.HEX = inst.bytecode[0];
13461360
src0.HEX = inst.bytecode[1];
13471361
src1.HEX = inst.bytecode[2];
13481362
src2.HEX = inst.bytecode[3];
13491363

1350-
m_offset = 4 * sizeof(u32);
13511364
opflags = 0;
13521365

13531366
const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6);
@@ -1373,43 +1386,14 @@ std::string FragmentProgramDecompiler::Decompile()
13731386
break;
13741387
case RSX_FP_OPCODE_IFE:
13751388
AddCode("if($cond)");
1376-
if (src2.end_offset != src1.else_offset)
1377-
m_else_offsets.push_back(src1.else_offset << 2);
1378-
m_end_offsets.push_back(src2.end_offset << 2);
1379-
AddCode("{");
1380-
m_code_level++;
13811389
break;
13821390
case RSX_FP_OPCODE_LOOP:
1383-
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
1384-
{
1385-
AddCode(fmt::format("//$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP",
1386-
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
1387-
}
1388-
else
1389-
{
1390-
AddCode(fmt::format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
1391+
AddCode(fmt::format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
13911392
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
1392-
m_loop_count++;
1393-
m_end_offsets.push_back(src2.end_offset << 2);
1394-
AddCode("{");
1395-
m_code_level++;
1396-
}
13971393
break;
13981394
case RSX_FP_OPCODE_REP:
1399-
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
1400-
{
1401-
AddCode(fmt::format("//$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP",
1402-
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
1403-
}
1404-
else
1405-
{
1406-
AddCode(fmt::format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
1395+
AddCode(fmt::format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
14071396
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
1408-
m_loop_count++;
1409-
m_end_offsets.push_back(src2.end_offset << 2);
1410-
AddCode("{");
1411-
m_code_level++;
1412-
}
14131397
break;
14141398
case RSX_FP_OPCODE_RET:
14151399
AddFlowOp("return");
@@ -1447,9 +1431,7 @@ std::string FragmentProgramDecompiler::Decompile()
14471431
break;
14481432
}
14491433

1450-
m_size += m_offset;
1451-
ensure((m_offset & 15) == 0); // Must be aligned to 16 bytes
1452-
1434+
m_size += m_instruction->length * 4;
14531435
if (dst.end) break;
14541436
}
14551437

rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,16 @@ class FragmentProgramDecompiler
4141
SRC2 src2;
4242
u32 opflags;
4343

44+
const rsx::assembler::Instruction* m_instruction;
45+
4446
std::string main;
4547
u32& m_size;
4648
u32 m_const_index = 0;
47-
u32 m_offset;
4849
u32 m_location = 0;
4950
bool m_is_valid_ucode = true;
5051

5152
u32 m_loop_count;
5253
int m_code_level;
53-
std::vector<u32> m_end_offsets;
54-
std::vector<u32> m_else_offsets;
5554
std::unordered_map<u32, u32> m_constant_offsets;
5655

5756
std::array<rsx::MixedPrecisionRegister, 64> temp_registers;

0 commit comments

Comments
 (0)