mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-12-16 04:09:07 +00:00
rsx/fp: Use CFG for fragment program
This commit is contained in:
parent
9d92e190eb
commit
cb7650240c
@ -1297,7 +1297,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
|
|||||||
|
|
||||||
std::string FragmentProgramDecompiler::Decompile()
|
std::string FragmentProgramDecompiler::Decompile()
|
||||||
{
|
{
|
||||||
auto data = static_cast<be_t<u32>*>(m_prog.get_data());
|
const auto graph = rsx::assembler::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;
|
||||||
@ -1314,141 +1314,146 @@ std::string FragmentProgramDecompiler::Decompile()
|
|||||||
|
|
||||||
int forced_unit = FORCE_NONE;
|
int forced_unit = FORCE_NONE;
|
||||||
|
|
||||||
while (true)
|
for (const auto &block : graph.blocks)
|
||||||
{
|
{
|
||||||
for (auto found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
|
// TODO: Handle block prologue if any
|
||||||
found != m_end_offsets.end();
|
|
||||||
found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size))
|
for (const auto& inst : block.instructions)
|
||||||
{
|
{
|
||||||
m_end_offsets.erase(found);
|
for (auto found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
|
||||||
m_code_level--;
|
found != m_end_offsets.end();
|
||||||
AddCode("}");
|
found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size))
|
||||||
m_loop_count--;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size);
|
|
||||||
found != m_else_offsets.end();
|
|
||||||
found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size))
|
|
||||||
{
|
|
||||||
m_else_offsets.erase(found);
|
|
||||||
m_code_level--;
|
|
||||||
AddCode("}");
|
|
||||||
AddCode("else");
|
|
||||||
AddCode("{");
|
|
||||||
m_code_level++;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst.HEX = GetData(data[0]);
|
|
||||||
src0.HEX = GetData(data[1]);
|
|
||||||
src1.HEX = GetData(data[2]);
|
|
||||||
src2.HEX = GetData(data[3]);
|
|
||||||
|
|
||||||
m_offset = 4 * sizeof(u32);
|
|
||||||
opflags = 0;
|
|
||||||
|
|
||||||
const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6);
|
|
||||||
|
|
||||||
auto SIP = [&]()
|
|
||||||
{
|
|
||||||
switch (opcode)
|
|
||||||
{
|
{
|
||||||
case RSX_FP_OPCODE_BRK:
|
m_end_offsets.erase(found);
|
||||||
if (m_loop_count) AddFlowOp("break");
|
m_code_level--;
|
||||||
else rsx_log.error("BRK opcode found outside of a loop");
|
AddCode("}");
|
||||||
break;
|
m_loop_count--;
|
||||||
case RSX_FP_OPCODE_CAL:
|
|
||||||
rsx_log.error("Unimplemented SIP instruction: CAL");
|
|
||||||
break;
|
|
||||||
case RSX_FP_OPCODE_FENCT:
|
|
||||||
AddCode("//FENCT");
|
|
||||||
forced_unit = FORCE_SCT;
|
|
||||||
break;
|
|
||||||
case RSX_FP_OPCODE_FENCB:
|
|
||||||
AddCode("//FENCB");
|
|
||||||
forced_unit = FORCE_SCB;
|
|
||||||
break;
|
|
||||||
case RSX_FP_OPCODE_IFE:
|
|
||||||
AddCode("if($cond)");
|
|
||||||
if (src2.end_offset != src1.else_offset)
|
|
||||||
m_else_offsets.push_back(src1.else_offset << 2);
|
|
||||||
m_end_offsets.push_back(src2.end_offset << 2);
|
|
||||||
AddCode("{");
|
|
||||||
m_code_level++;
|
|
||||||
break;
|
|
||||||
case RSX_FP_OPCODE_LOOP:
|
|
||||||
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
|
||||||
{
|
|
||||||
AddCode(fmt::format("//$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP",
|
|
||||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddCode(fmt::format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
|
|
||||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
|
||||||
m_loop_count++;
|
|
||||||
m_end_offsets.push_back(src2.end_offset << 2);
|
|
||||||
AddCode("{");
|
|
||||||
m_code_level++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RSX_FP_OPCODE_REP:
|
|
||||||
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
|
||||||
{
|
|
||||||
AddCode(fmt::format("//$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP",
|
|
||||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddCode(fmt::format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
|
|
||||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
|
||||||
m_loop_count++;
|
|
||||||
m_end_offsets.push_back(src2.end_offset << 2);
|
|
||||||
AddCode("{");
|
|
||||||
m_code_level++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RSX_FP_OPCODE_RET:
|
|
||||||
AddFlowOp("return");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
for (auto found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size);
|
||||||
};
|
found != m_else_offsets.end();
|
||||||
|
found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size))
|
||||||
|
{
|
||||||
|
m_else_offsets.erase(found);
|
||||||
|
m_code_level--;
|
||||||
|
AddCode("}");
|
||||||
|
AddCode("else");
|
||||||
|
AddCode("{");
|
||||||
|
m_code_level++;
|
||||||
|
}
|
||||||
|
|
||||||
switch (opcode)
|
dst.HEX = inst.bytecode[0];
|
||||||
{
|
src0.HEX = inst.bytecode[1];
|
||||||
case RSX_FP_OPCODE_NOP:
|
src1.HEX = inst.bytecode[2];
|
||||||
break;
|
src2.HEX = inst.bytecode[3];
|
||||||
case RSX_FP_OPCODE_KIL:
|
|
||||||
properties.has_discard_op = true;
|
|
||||||
AddFlowOp("_kill()");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
int prev_force_unit = forced_unit;
|
|
||||||
|
|
||||||
// Some instructions do not respect forced unit
|
m_offset = 4 * sizeof(u32);
|
||||||
// Tested with Tales of Vesperia
|
opflags = 0;
|
||||||
if (SIP()) break;
|
|
||||||
if (handle_tex_srb(opcode)) break;
|
|
||||||
|
|
||||||
// FENCT/FENCB do not actually reject instructions if they dont match the forced unit
|
const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6);
|
||||||
// Looks like they are optimization hints and not hard-coded forced paths
|
|
||||||
if (handle_sct_scb(opcode)) break;
|
|
||||||
forced_unit = FORCE_NONE;
|
|
||||||
|
|
||||||
rsx_log.error("Unknown/illegal instruction: 0x%x (forced unit %d)", opcode, prev_force_unit);
|
auto SIP = [&]()
|
||||||
break;
|
{
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case RSX_FP_OPCODE_BRK:
|
||||||
|
if (m_loop_count) AddFlowOp("break");
|
||||||
|
else rsx_log.error("BRK opcode found outside of a loop");
|
||||||
|
break;
|
||||||
|
case RSX_FP_OPCODE_CAL:
|
||||||
|
rsx_log.error("Unimplemented SIP instruction: CAL");
|
||||||
|
break;
|
||||||
|
case RSX_FP_OPCODE_FENCT:
|
||||||
|
AddCode("//FENCT");
|
||||||
|
forced_unit = FORCE_SCT;
|
||||||
|
break;
|
||||||
|
case RSX_FP_OPCODE_FENCB:
|
||||||
|
AddCode("//FENCB");
|
||||||
|
forced_unit = FORCE_SCB;
|
||||||
|
break;
|
||||||
|
case RSX_FP_OPCODE_IFE:
|
||||||
|
AddCode("if($cond)");
|
||||||
|
if (src2.end_offset != src1.else_offset)
|
||||||
|
m_else_offsets.push_back(src1.else_offset << 2);
|
||||||
|
m_end_offsets.push_back(src2.end_offset << 2);
|
||||||
|
AddCode("{");
|
||||||
|
m_code_level++;
|
||||||
|
break;
|
||||||
|
case RSX_FP_OPCODE_LOOP:
|
||||||
|
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
||||||
|
{
|
||||||
|
AddCode(fmt::format("//$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP",
|
||||||
|
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddCode(fmt::format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
|
||||||
|
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
||||||
|
m_loop_count++;
|
||||||
|
m_end_offsets.push_back(src2.end_offset << 2);
|
||||||
|
AddCode("{");
|
||||||
|
m_code_level++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RSX_FP_OPCODE_REP:
|
||||||
|
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
||||||
|
{
|
||||||
|
AddCode(fmt::format("//$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP",
|
||||||
|
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddCode(fmt::format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
|
||||||
|
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
||||||
|
m_loop_count++;
|
||||||
|
m_end_offsets.push_back(src2.end_offset << 2);
|
||||||
|
AddCode("{");
|
||||||
|
m_code_level++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RSX_FP_OPCODE_RET:
|
||||||
|
AddFlowOp("return");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case RSX_FP_OPCODE_NOP:
|
||||||
|
break;
|
||||||
|
case RSX_FP_OPCODE_KIL:
|
||||||
|
properties.has_discard_op = true;
|
||||||
|
AddFlowOp("_kill()");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
int prev_force_unit = forced_unit;
|
||||||
|
|
||||||
|
// Some instructions do not respect forced unit
|
||||||
|
// Tested with Tales of Vesperia
|
||||||
|
if (SIP()) break;
|
||||||
|
if (handle_tex_srb(opcode)) break;
|
||||||
|
|
||||||
|
// FENCT/FENCB do not actually reject instructions if they dont match the forced unit
|
||||||
|
// Looks like they are optimization hints and not hard-coded forced paths
|
||||||
|
if (handle_sct_scb(opcode)) break;
|
||||||
|
forced_unit = FORCE_NONE;
|
||||||
|
|
||||||
|
rsx_log.error("Unknown/illegal instruction: 0x%x (forced unit %d)", opcode, prev_force_unit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_size += m_offset;
|
||||||
|
ensure((m_offset & 15) == 0); // Must be aligned to 16 bytes
|
||||||
|
|
||||||
|
if (dst.end) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_size += m_offset;
|
// TODO: Handle block epilogue if needed
|
||||||
|
|
||||||
if (dst.end) break;
|
|
||||||
|
|
||||||
ensure(m_offset % sizeof(u32) == 0);
|
|
||||||
data += m_offset / sizeof(u32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (m_code_level > 1)
|
while (m_code_level > 1)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user