From 0df20eb300f0b996063f2d4baac1e2edddb40eb2 Mon Sep 17 00:00:00 2001 From: nmzik Date: Sat, 15 Aug 2026 22:39:26 +0200 Subject: [PATCH] fix opcode regression --- .../frontend/decode/VectorAluOps.cpp | 7 ++--- tests/ShaderRecompilerComputeTests.cpp | 31 +++++++++++++++++-- tests/shaderCfgTests.cpp | 16 +++++----- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp index 6400346..b650d07 100644 --- a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp @@ -1738,14 +1738,13 @@ bool DecodeVop3p(uint32_t pc, std::span code, uint32_t word_inde const uint32_t vdst = word0 & 0xffu; const uint32_t neg_hi = (word0 >> 8u) & 0x7u; const uint32_t op_sel = (word0 >> 11u) & 0x7u; - const uint32_t op_sel_hi_0 = (word0 >> 14u) & 0x1u; + const uint32_t op_sel_hi_2 = (word0 >> 14u) & 0x1u; const uint32_t clamp = (word0 >> 15u) & 0x1u; const uint32_t src0 = word1 & 0x1ffu; const uint32_t src1 = (word1 >> 9u) & 0x1ffu; const uint32_t src2 = (word1 >> 18u) & 0x1ffu; - const uint32_t op_sel_hi = - op_sel_hi_0 | (((word1 >> 28u) & 0x1u) << 1u) | (((word1 >> 27u) & 0x1u) << 2u); - const uint32_t neg = (word1 >> 29u) & 0x7u; + const uint32_t op_sel_hi = ((word1 >> 27u) & 0x3u) | (op_sel_hi_2 << 2u); + const uint32_t neg = (word1 >> 29u) & 0x7u; inst.pc = pc; inst.word = word0; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 2ea7ac9..86632f5 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -505,15 +505,14 @@ constexpr u32 EncodeVop3pWord0(u32 opcode, u32 dst, u32 op_sel_hi = 0, u32 op_sel = 0, u32 neg_hi = 0, bool clamp = false) { return (0x33u << 26u) | ((opcode & 0x7fu) << 16u) | ((neg_hi & 0x7u) << 8u) | - ((op_sel & 0x7u) << 11u) | ((op_sel_hi & 0x1u) << 14u) | + ((op_sel & 0x7u) << 11u) | (((op_sel_hi >> 2u) & 0x1u) << 14u) | (clamp ? (1u << 15u) : 0u) | (dst & 0xffu); } constexpr u32 EncodeVop3pWord1(u32 src0, u32 src1, u32 src2 = 0, u32 op_sel_hi = 0, u32 neg = 0) { return (src0 & 0x1ffu) | ((src1 & 0x1ffu) << 9u) | ((src2 & 0x1ffu) << 18u) | - (((op_sel_hi >> 2u) & 0x1u) << 27u) | - (((op_sel_hi >> 1u) & 0x1u) << 28u) | ((neg & 0x7u) << 29u); + ((op_sel_hi & 0x3u) << 27u) | ((neg & 0x7u) << 29u); } constexpr u32 EncodeVopc(u32 opcode, u32 src0, u32 src1) { @@ -12013,6 +12012,31 @@ TestCase VectorLaneAndPackedOps() { O::VCvtPkU16U32, O::BufferStoreDword, O::SEndpgm}}; } +TestCase Vop3pOpselHiUsesArchitecturalSourceBits() { + using O = ShaderOpcode; + + std::vector code; + AppendVMovLiteral(&code, 0, 0x42003c00u); // low=1.0h, high=3.0h + AppendVMovLiteral(&code, 1, 0x48004400u); // low=4.0h, high=8.0h + AppendVMovLiteral(&code, 2, 0x50004c00u); // low=16.0h, high=32.0h + + // Raw V_PK_FMA_F16 words keep this test independent of the encoders above. + code.insert(code.end(), {0xcc0e000au, 0x0c0a0300u}); // src0 high: 3*4+16=28 + code.insert(code.end(), {0xcc0e000bu, 0x140a0300u}); // src1 high: 1*8+16=24 + code.insert(code.end(), {0xcc0e400cu, 0x040a0300u}); // src2 high: 1*4+32=36 + + for (u32 i = 0; i < 3; i++) { + AppendStoreVgpr(&code, 10 + i, i); + } + AppendEnd(&code); + + return {"Vop3pOpselHiUsesArchitecturalSourceBits", + code, + {}, + {0x4f004d00u, 0x4e004d00u, 0x50804d00u}, + {O::VMovB32, O::VPkFmaF16, O::BufferStoreDword, O::SEndpgm}}; +} + TestCase CvtPkU8F32PacksSelectedByte() { using O = ShaderOpcode; @@ -16957,6 +16981,7 @@ std::vector MakeCases() { AddCase(VectorVop3BSubCoU32UsesRdna2Opcode310); AddCase(VectorMadU64U32UnsignedCarryOut); AddCase(VectorLaneAndPackedOps); + AddCase(Vop3pOpselHiUsesArchitecturalSourceBits); AddCase(CvtPkU8F32PacksSelectedByte); AddCase(CvtPkrtzF16F32SubnormalRoundsTowardZero); AddCase(PackedMinMaxF16NanAndSignedZeroEdges); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index ee425b9..bd726d4 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -834,14 +834,13 @@ constexpr uint32_t EncodeVop3pWord0(uint32_t opcode, uint32_t dst, uint32_t neg_hi = 0, bool clamp = false) { return (0x33u << 26u) | ((opcode & 0x7fu) << 16u) | (dst & 0xffu) | ((neg_hi & 0x7u) << 8u) | ((op_sel & 0x7u) << 11u) | - ((op_sel_hi & 0x1u) << 14u) | (clamp ? (1u << 15u) : 0u); + (((op_sel_hi >> 2u) & 0x1u) << 14u) | (clamp ? (1u << 15u) : 0u); } constexpr uint32_t EncodeVop3pWord1(uint32_t src0, uint32_t src1, uint32_t src2, uint32_t op_sel_hi = 0, uint32_t neg = 0) { return (src0 & 0x1ffu) | ((src1 & 0x1ffu) << 9u) | ((src2 & 0x1ffu) << 18u) | - (((op_sel_hi >> 2u) & 0x1u) << 27u) | - (((op_sel_hi >> 1u) & 0x1u) << 28u) | ((neg & 0x7u) << 29u); + ((op_sel_hi & 0x3u) << 27u) | ((neg & 0x7u) << 29u); } constexpr uint32_t EncodeSmem0(uint32_t opcode, uint32_t dst, uint32_t sbase) { @@ -3375,12 +3374,13 @@ void TestNewShaderDecoderArchitecture() { Check(boot.opcode == Opcode::DsSwizzleB32 && boot.offset == 0xc480u, "DS decoder rejected a captured boot-shader instruction"); + constexpr uint32_t packed_source_selectors[][2] = { + {0xcc0e0000u, 0x0c0a0300u}, // Source 0: instruction bit 59. + {0xcc0e0000u, 0x140a0300u}, // Source 1: instruction bit 60. + {0xcc0e4000u, 0x040a0300u}, // Source 2: instruction bit 14. + }; for (uint32_t source = 0; source < 3u; source++) { - const uint32_t op_sel_hi = 1u << source; - const uint32_t packed[] = { - EncodeVop3pWord0(0x0e, 0, 0, op_sel_hi), - EncodeVop3pWord1(256, 257, 258, op_sel_hi), - }; + const auto &packed = packed_source_selectors[source]; Instruction packed_inst; Check(DecodeInstruction(packed, 0u, packed_inst, &error), error.c_str()); Check(packed_inst.src0.op_sel_hi == (source == 0u) &&