diff --git a/rpcs3/Emu/RSX/Program/Assembler/FPToCFG.cpp b/rpcs3/Emu/RSX/Program/Assembler/FPToCFG.cpp index 234a0e5450..4433af29a2 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/FPToCFG.cpp +++ b/rpcs3/Emu/RSX/Program/Assembler/FPToCFG.cpp @@ -1,17 +1,14 @@ #include "stdafx.h" -#pragma optimize("", off) - #include "CFG.h" #include "Emu/RSX/Common/simple_array.hpp" #include "Emu/RSX/Program/RSXFragmentProgram.h" -#include "Emu/RSX/Program/ProgramStateCache.h" #include +#include #include -using namespace program_hash_util; namespace rsx::assembler { @@ -75,6 +72,13 @@ namespace rsx::assembler return graph.push(parent, id, edge_type); }; + auto includes_literal_constant = [&]() + { + return src0.reg_type == RSX_FP_REGISTER_TYPE_CONSTANT || + src1.reg_type == RSX_FP_REGISTER_TYPE_CONSTANT || + src2.reg_type == RSX_FP_REGISTER_TYPE_CONSTANT; + }; + while (!end) { BasicBlock** found = end_blocks.find_if(FN(x->id == pc)); @@ -110,13 +114,21 @@ namespace rsx::assembler bb->instructions.push_back({}); auto& ir_inst = bb->instructions.back(); std::memcpy(ir_inst.bytecode, &decoded._u32[0], 16); + ir_inst.length = 4; + ir_inst.addr = pc * 16; switch (opcode) { + case RSX_FP_OPCODE_BRK: + break; case RSX_FP_OPCODE_CAL: // Unimplemented. Also unused by the RSX compiler fmt::throw_exception("Unimplemented FP CAL instruction."); break; + case RSX_FP_OPCODE_FENCT: + break; + case RSX_FP_OPCODE_FENCB: + break; case RSX_FP_OPCODE_RET: // Outside a subroutine, this doesn't mean much. The main block can conditionally return to stop execution early. // This will not alter flow control. @@ -143,8 +155,13 @@ namespace rsx::assembler break; } default: - if (fragment_program_utils::is_any_src_constant(decoded)) + if (includes_literal_constant()) { + const v128 constant_literal = v128::loadu(data, pc); + v128 decoded_literal = decode_instruction(constant_literal); + + std::memcpy(ir_inst.bytecode + 4, &decoded_literal._u32[0], 16); + ir_inst.length += 4; pc++; } } @@ -152,6 +169,14 @@ namespace rsx::assembler pc++; } + // Sort edges for each block by distance + for (auto& block : graph.blocks) + { + std::sort(block.pred.begin(), block.pred.end(), FN(x.from->id > y.from->id)); + std::sort(block.succ.begin(), block.succ.end(), FN(x.to->id < y.to->id)); + } + + // Sort block nodes by distance graph.blocks.sort(FN(x.id < y.id)); return graph; } diff --git a/rpcs3/Emu/RSX/Program/Assembler/IR.h b/rpcs3/Emu/RSX/Program/Assembler/IR.h index 3ff8eb1a3a..1f1c1d81d8 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/IR.h +++ b/rpcs3/Emu/RSX/Program/Assembler/IR.h @@ -33,11 +33,20 @@ namespace rsx::assembler struct Instruction { - // Raw data. Every instruction is max 128 bits - u32 bytecode[4]; + // Raw data. Every instruction is max 128 bits. + // Each instruction can also have 128 bits of literal/embedded data. + u32 bytecode[8]{ {} }; + u32 addr = 0; // Decoded u32 opcode = 0; + u8 length = 4; // Length in dwords + + // Padding + u8 reserved0 = 0; + u16 reserved1 = 0; + + // References std::vector srcs; std::vector dsts; }; @@ -49,7 +58,7 @@ namespace rsx::assembler ELSE, ENDIF, LOOP, - ENDLOOP + ENDLOOP, }; struct FlowEdge @@ -78,7 +87,7 @@ namespace rsx::assembler FlowEdge* insert_pred(BasicBlock* b, EdgeType type = EdgeType::NONE) { - FlowEdge e{ .type = type, .from = this, .to = b }; + FlowEdge e{ .type = type, .from = b, .to = this }; pred.push_back(e); return &pred.back(); } diff --git a/rpcs3/tests/test_rsx_cfg.cpp b/rpcs3/tests/test_rsx_cfg.cpp index 532721fc95..b5969081d9 100644 --- a/rpcs3/tests/test_rsx_cfg.cpp +++ b/rpcs3/tests/test_rsx_cfg.cpp @@ -1,4 +1,3 @@ -#pragma optimize("", off) #include #include "Emu/RSX/Common/simple_array.hpp" @@ -72,6 +71,8 @@ namespace rsx::assembler EXPECT_EQ(graph.blocks.size(), 1); EXPECT_EQ(graph.blocks.front().instructions.size(), 2); + EXPECT_EQ(graph.blocks.front().instructions.front().length, 4); + EXPECT_NE(graph.blocks.front().instructions.front().addr, 0); } TEST(CFG, FpToCFG_IF) @@ -184,6 +185,13 @@ namespace rsx::assembler EXPECT_EQ(it->id, expected.first); EXPECT_EQ(it->instructions.size(), expected.second); } + + // Predecessors must be ordered, closest first + ASSERT_EQ(std::find_if(graph.blocks.begin(), graph.blocks.end(), FN(x.id == 6))->pred.size(), 2); + EXPECT_EQ(std::find_if(graph.blocks.begin(), graph.blocks.end(), FN(x.id == 6))->pred[0].type, EdgeType::ENDIF); + EXPECT_EQ(std::find_if(graph.blocks.begin(), graph.blocks.end(), FN(x.id == 6))->pred[0].from->id, 3); + EXPECT_EQ(std::find_if(graph.blocks.begin(), graph.blocks.end(), FN(x.id == 6))->pred[1].type, EdgeType::ENDIF); + EXPECT_EQ(std::find_if(graph.blocks.begin(), graph.blocks.end(), FN(x.id == 6))->pred[1].from->id, 0); } TEST(CFG, FpToCFG_IF_ELSE)