From aa88d94755e4621e1bcc95d97faf65118a44697c Mon Sep 17 00:00:00 2001 From: nmzik Date: Tue, 4 Aug 2026 23:12:47 +0200 Subject: [PATCH] shader: implement V_SUB_NC_U32 --- .../recompiler/decompiler/VectorAluOps.cpp | 2 +- tests/ShaderRecompilerComputeTests.cpp | 44 +++++++++++++++++++ tests/shaderCfgTests.cpp | 6 +++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp b/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp index 664dacad3..d00a81c43 100644 --- a/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp @@ -834,7 +834,7 @@ constexpr Vop2SdwaRule VOP2_SDWA_RULES[] = { {Opcode::VXorB32, SdwaSelWords() | SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), true, false}, {Opcode::VXnorB32, SdwaSelWords() | SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), true, false}, {Opcode::VAddNcU32, SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), false, false}, - {Opcode::VSubNcU32, SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), false, false}, + {Opcode::VSubNcU32, SdwaSelAll(), SdwaSelAll(), SdwaSelAll(), true, false}, {Opcode::VSubrevNcU32, SdwaSelFull(), SdwaSelAll(), SdwaSelAll(), false, false}, }; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 981acd8ee..8f0fb494b 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -10116,6 +10116,48 @@ TestCase VectorIntegerOps() { O::VCndmaskB32, O::BufferStoreDword, O::SEndpgm}}; } +TestCase Vop2SdwaSubNcExactByte2Destination() { + using O = ShaderOpcode; + + std::vector code; + AppendVMovU32(&code, 11, 2); + code.push_back(0x4c1616f9u); + code.push_back(0x0686128du); + AppendStoreVgpr(&code, 11, 0); + AppendEnd(&code); + + TestCase test; + test.name = "Vop2SdwaSubNcExactByte2Destination"; + test.code = code; + test.expected = {0x000b0002u}; + test.opcodes = {O::VMovB32, O::VSubNcU32, O::BufferStoreDword, O::SEndpgm}; + test.required_spirv = {"OpISub", "OpShiftLeftLogical", "OpBitwiseOr"}; + return test; +} + +TestCase Vop2SdwaSubNcPreservesByteAndWordDestinations() { + using O = ShaderOpcode; + + std::vector code; + AppendVMovU32(&code, 0, 3); + for (u32 dst = 10; dst <= 15; dst++) { + AppendVMovLiteral(&code, dst, 0xa1b2c3d4u); + } + for (u32 sel = 0; sel <= 5; sel++) { + code.push_back(EncodeVop2(0x26, 10 + sel, 249, 0)); + code.push_back(EncodeVop2Sdwa(InlineU32(20), sel, 2, 6, 6, 0, 0, 0, 0, 0, 0, 1)); + AppendStoreVgpr(&code, 10 + sel, sel); + } + AppendEnd(&code); + + return {"Vop2SdwaSubNcPreservesByteAndWordDestinations", + code, + {}, + {0xa1b2c311u, 0xa1b211d4u, 0xa111c3d4u, 0x11b2c3d4u, 0xa1b20011u, + 0x0011c3d4u}, + {O::VMovB32, O::VSubNcU32, O::BufferStoreDword, O::SEndpgm}}; +} + TestCase VectorShiftCountsMaskLowBits() { using O = ShaderOpcode; @@ -15050,6 +15092,8 @@ std::vector MakeCases() { AddCase(VectorMoves); AddCase(VectorVop3MoveAppliesFloatSourceModifiers); AddCase(VectorIntegerOps); + AddCase(Vop2SdwaSubNcExactByte2Destination); + AddCase(Vop2SdwaSubNcPreservesByteAndWordDestinations); AddCase(VectorShiftCountsMaskLowBits); AddCase(VectorVop3IntegerOps); AddCase(VectorBfeI32ArithmeticShiftMasksField); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 5b58f733b..15eb520e1 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -2417,6 +2417,8 @@ void TestNewShaderRecompilerBootB16PackedAndSdwaOpcodes() { 0x0c860688u, // v_add_nc_u32 v5, 8, sign-extended v4.lo 0x4a0c0cf9u, 0x0d860688u, // v_add_nc_u32 v6, 8, sign-extended v6.hi + 0x4c1616f9u, + 0x0686128du, // v_sub_nc_u32 v11.byte2, 13, v11; preserve other destination bytes 0xbf810000u, }; @@ -2465,6 +2467,8 @@ void TestNewShaderRecompilerBootB16PackedAndSdwaOpcodes() { Check(Common::ContainsStr(result.decoded_dump, "v_add_nc_u32 v6") && Common::ContainsStr(result.decoded_dump, "v6.sdwa(sel=5,sext=1"), "new decoder did not decode V_ADD_NC_U32 SDWA sign-extended high word"); + Check(Common::ContainsStr(result.decoded_dump, "v_sub_nc_u32 v11.sdwa(sel=2"), + "new decoder did not decode V_SUB_NC_U32 SDWA byte-2 destination"); Check(!Common::ContainsStr(result.decoded_dump, "unsupported family=VOP2 opcode=0x00"), "literal/SDWA extension words were decoded as phantom VOP2 instructions"); Check(!Common::ContainsStr(result.decoded_dump, @@ -2498,6 +2502,8 @@ void TestNewShaderRecompilerBootB16PackedAndSdwaOpcodes() { Check(Common::ContainsStr(result.ir_dump, "IAddU32 v6") && Common::ContainsStr(result.ir_dump, "v6.sdwa(sel=5,sext=1"), "V_ADD_NC_U32 SDWA sign-extended high word did not lower to IR"); + Check(Common::ContainsStr(result.ir_dump, "ISubU32 v11.sdwa(sel=2"), + "V_SUB_NC_U32 SDWA byte-2 destination did not lower to IR"); Check(SpirvContainsOpcode(result.spirv, 128), "SPIR-V binary does not contain OpIAdd for U16 operations"); Check(SpirvContainsOpcode(result.spirv, 202),