From ed397c5d67ceac1435b3d713382e75627bf6ff10 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 30 Nov 2025 23:14:40 +0300 Subject: [PATCH] rsx/asm: Add support for more opcodes and add tests for mixed block IO --- rpcs3/Emu/RSX/Program/Assembler/FPASM.cpp | 58 ++++++++++++----------- rpcs3/tests/test_rsx_fp_asm.cpp | 32 ++++++++++++- 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/rpcs3/Emu/RSX/Program/Assembler/FPASM.cpp b/rpcs3/Emu/RSX/Program/Assembler/FPASM.cpp index d1ef30b695..da3f47e940 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/FPASM.cpp +++ b/rpcs3/Emu/RSX/Program/Assembler/FPASM.cpp @@ -8,6 +8,32 @@ namespace rsx::assembler { + static std::unordered_map s_opcode_lookup + { + // Arithmetic + { "NOP", RSX_FP_OPCODE_NOP }, + { "MOV", RSX_FP_OPCODE_MOV }, + { "ADD", RSX_FP_OPCODE_ADD }, + { "MAD", RSX_FP_OPCODE_MAD }, + { "FMA", RSX_FP_OPCODE_MAD }, + { "DP3", RSX_FP_OPCODE_DP3 }, + { "DP4", RSX_FP_OPCODE_DP4 }, + + // Pack-unpack operations are great for testing dependencies + { "PKH", RSX_FP_OPCODE_PK2 }, + { "UPH", RSX_FP_OPCODE_UP2 }, + { "PK16U", RSX_FP_OPCODE_PK16 }, + { "UP16U", RSX_FP_OPCODE_UP16 }, + { "PK8U", RSX_FP_OPCODE_PKB }, + { "UP8U", RSX_FP_OPCODE_UPB }, + { "PK8G", RSX_FP_OPCODE_PKG }, + { "UP8G", RSX_FP_OPCODE_UPG }, + { "PK8S", RSX_FP_OPCODE_PK4 }, + { "UP8S", RSX_FP_OPCODE_UP4 }, + // TODO: Add more + + }; + Instruction* FPIR::load(const RegisterRef& ref, int operand, Instruction* prev) { Instruction* target = prev; @@ -233,39 +259,15 @@ namespace rsx::assembler inst->bytecode[1] = s0.HEX; \ } while (0) - if (op == "MOV") + const auto found = s_opcode_lookup.find(op); + if (found == s_opcode_lookup.end()) { - SET_OPCODE(RSX_FP_OPCODE_MOV); - return; + fmt::throw_exception("Unhandled instruction '%s'", op); } - if (op == "ADD") - { - SET_OPCODE(RSX_FP_OPCODE_ADD); - return; - } - - if (op == "MAD" || op == "FMA") - { - SET_OPCODE(RSX_FP_OPCODE_MAD); - return; - } - - if (op == "UP4S") - { - SET_OPCODE(RSX_FP_OPCODE_UP4); - return; - } - - if (op == "PK4S") - { - SET_OPCODE(RSX_FP_OPCODE_PK4); - return; - } + SET_OPCODE(found->second); #undef SET_OPCODE - - fmt::throw_exception("Unhandled instruction '%s'", op); }; std::string op, dst; diff --git a/rpcs3/tests/test_rsx_fp_asm.cpp b/rpcs3/tests/test_rsx_fp_asm.cpp index 9ae23fa81c..b09088c80c 100644 --- a/rpcs3/tests/test_rsx_fp_asm.cpp +++ b/rpcs3/tests/test_rsx_fp_asm.cpp @@ -74,7 +74,7 @@ namespace rsx::assembler TEST(TestFPIR, RegisterAnnotationPass) { - // Code snippet reads from R0 and R2, clobbers R0, R1, H0 + // Code snippet reads from R0, R1 and H4, clobbers R1, H0 auto graph = CFG_from_source(R"( ADD R1, R0, R1; MOV H0, H4; @@ -99,4 +99,34 @@ namespace rsx::assembler EXPECT_EQ(block.input_list[1].reg, R0); EXPECT_EQ(block.input_list[2].reg, R1); } + + TEST(TestFPIR, RegisterAnnotationPass_MixedIO) + { + // Code snippet reads from R0, R1, clobbers R0, R1, H0. + // The H2 read does not count because R1 is clobbered. + auto graph = CFG_from_source(R"( + ADD R1, R0, R1; + PK8U R0, R1; + MOV H0, H2; + )"); + + ASSERT_EQ(graph.blocks.size(), 1); + ASSERT_EQ(graph.blocks.front().instructions.size(), 3); + + auto& block = graph.blocks.front(); + RSXFragmentProgram prog{}; + FP::RegisterAnnotationPass annotation_pass(prog); + + annotation_pass.run(graph); + + ASSERT_EQ(block.clobber_list.size(), 3); + ASSERT_EQ(block.input_list.size(), 2); + + EXPECT_EQ(block.clobber_list[0].reg, H0); + EXPECT_EQ(block.clobber_list[1].reg, R0); + EXPECT_EQ(block.clobber_list[2].reg, R1); + + EXPECT_EQ(block.input_list[0].reg, R0); + EXPECT_EQ(block.input_list[1].reg, R1); + } }