From d890bb190cb0fa6d96de39b13e7bce096e185d46 Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 4 Oct 2026 01:59:45 +0400 Subject: [PATCH] shader: decode RDNA2 bit-reverse SDWA source selectors Co-authored-by: TheCruZ --- .../frontend/decode/VectorAluOps.cpp | 1 + tests/ShaderRecompilerComputeTests.cpp | 32 +++++++++++++++++++ tests/shaderCfgTests.cpp | 22 +++++++++++++ 3 files changed, 55 insertions(+) diff --git a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp index 9bcdf7532..fbc4ac981 100644 --- a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp @@ -551,6 +551,7 @@ constexpr Vop1SdwaRule VOP1_SDWA_RULES[] = { // partial destination may combine with any source selector. {Opcode::V_NOT_B32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), SdwaSelBytes() | SdwaSelWords(), SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), false}, + {Opcode::V_BFREV_B32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), 0, 0, false}, {Opcode::V_FFBL_B32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), 0, 0, false}, {Opcode::V_FFBH_U32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), 0, 0, false}, {Opcode::V_CVT_F32_F16, SdwaSelWords() | SdwaSelFull(), 0, 0, true}, diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 173b2a1ae..706b0611c 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -20361,6 +20361,36 @@ TestCase VectorFfbhI32NativeAndVop3OnGpu() { return test; } +TestCase Vop1SdwaBfrevSourceSelectors() { + using O = ShaderOpcode; + constexpr u32 expected[2][7] = { + {0x8f000000u, 0xd5000000u, 0x21000000u, 0x49000000u, + 0x8fd50000u, 0x21490000u, 0x8fd52149u}, + {0x8fffffffu, 0xd5ffffffu, 0x21ffffffu, 0x49ffffffu, + 0x8fd5ffffu, 0x2149ffffu, 0x8fd52149u}}; + TestCase test; + test.name = "Vop1SdwaBfrevSourceSelectors"; + for (u32 sext = 0; sext < 2; sext++) { + for (u32 selector = 0; selector < 7; selector++) { + const u32 index = static_cast(test.initial.size()); + AppendVMovU32(&test.code, 30, index * 4u); + AppendBufferLoadDword(&test.code, 0, 30); + // selector=4, sext=0 reproduces captured words 7e0070f9, 00040600. + test.code.insert(test.code.end(), + {0x7e0070f9u, EncodeVop1Sdwa(0, 6, 0, selector, sext)}); + AppendStoreVgpr(&test.code, 0, index); + test.initial.push_back(0x9284abf1u); + test.expected.push_back(expected[sext][selector]); + } + } + AppendEnd(&test.code); + test.opcodes = {O::V_MOV_B32, O::BUFFER_LOAD_DWORD, O::V_BFREV_B32, + O::BUFFER_STORE_DWORD, O::S_ENDPGM}; + test.decoded_counts = {{"V_BFREV_B32 v0, v0.sdwa(sel=4,sext=0)", 1}}; + test.required_spirv = {"OpBitFieldUExtract", "OpBitFieldSExtract", "OpBitReverse"}; + return test; +} + TestCase Vop1SdwaFfbhCapturedScalarLowWordSource() { using O = ShaderOpcode; @@ -32274,6 +32304,7 @@ std::vector MakeCases() { AddCase(VectorVop3MoveAppliesFloatSourceModifiers); AddCase(VectorIntegerOps); AddCase(VectorFfbhI32NativeAndVop3OnGpu); + AddCase(Vop1SdwaBfrevSourceSelectors); AddCase(Vop1SdwaFfbhCapturedScalarLowWordSource); AddCase(Vop1SdwaFfblCapturedHighWordSource); AddCase(Vop1SdwaNotCapturedByte0Source); @@ -37751,6 +37782,7 @@ int main(int argc, char **argv) { } if (argc == 2 && std::strcmp(argv[1], "--sdwa-ffbh-only") == 0) { VulkanHarness vulkan; + RunCase(&vulkan, Vop1SdwaBfrevSourceSelectors()); RunCase(&vulkan, Vop1SdwaFfbhCapturedScalarLowWordSource()); RunCase(&vulkan, VectorFfbhI32NativeAndVop3OnGpu()); RunCase(&vulkan, Vop1SdwaFfblCapturedHighWordSource()); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 023cfa644..2d0bf0031 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -3579,6 +3579,27 @@ void TestNewShaderRecompilerCapturedVop1SdwaByteConvert() { "V_CVT_F16_U16 accepted unimplemented SDWA byte sign extension"); } +void TestNewShaderRecompilerVop1SdwaBfrev() { + using namespace ShaderRecompiler::Decoder; + const uint32_t captured[] = {0x7e0070f9u, 0x00040600u}; + Instruction decoded; + DecodeInstruction(captured, 0, decoded); + Check(decoded.opcode == Opcode::V_BFREV_B32 && decoded.word_count == 2 && + decoded.dst.kind == OperandKind::Vgpr && decoded.dst.reg == 0 && + decoded.dst.sdwa_sel == 6 && decoded.src0.kind == OperandKind::Vgpr && + decoded.src0.reg == 0 && decoded.src0.sdwa_sel == 4 && + !decoded.src0.sdwa_sext, + "captured V_BFREV_B32 SDWA source metadata is incorrect"); + for (const uint32_t modifier : {0x00070600u, 0x00140600u, 0x00240600u, + 0x00042600u, 0x00044600u, 0x00040400u, + 0x00041e00u}) { + const uint32_t invalid[] = {captured[0], modifier}; + DecodeInstruction(invalid, 0, decoded); + Check(decoded.word_count == 2 && decoded.opcode == Opcode::UNSUPPORTED, + "V_BFREV_B32 SDWA accepted unsupported selectors or modifiers"); + } +} + void TestNewShaderRecompilerVop1SdwaNotDestination() { auto options = MakeCompileOptions(ShaderType::Pixel); @@ -14546,6 +14567,7 @@ int main() { TestNewShaderRecompilerDsReadWrite2Translation(); TestNewShaderRecompilerDsWideAndAtomicTranslation(); TestNewShaderRecompilerCapturedVop1SdwaByteConvert(); + TestNewShaderRecompilerVop1SdwaBfrev(); TestNewShaderRecompilerVop1SdwaNotDestination(); TestNewShaderRecompilerScalarMemoryBindingDomains(); // Opcode semantics and optimized SPIR-V are exercised by