From 7e90590146dcc836575c19c17fe1f09d2de9de69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Franch?= Date: Sun, 4 Oct 2026 13:50:46 +0200 Subject: [PATCH] feat(shader): accept every SDWA selector on VOP2 float ops Co-Authored-By: Claude --- .../tests/execution/SdwaFloatSelectors.cpp | 218 ++++++++++++++++++ .../RdnaDecoder/src/RdnaVectorOpDecoder.cpp | 29 +-- 2 files changed, 234 insertions(+), 13 deletions(-) create mode 100644 core/libs/prx/libSceAgcDriver/tests/execution/SdwaFloatSelectors.cpp diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/SdwaFloatSelectors.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/SdwaFloatSelectors.cpp new file mode 100644 index 000000000..10863bc09 --- /dev/null +++ b/core/libs/prx/libSceAgcDriver/tests/execution/SdwaFloatSelectors.cpp @@ -0,0 +1,218 @@ +#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp" +#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp" +#include "Recompiler.hpp" +#include "VulkanTestDevice.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using AgcDriver::Graphics::Require; +using ShaderRecompiler::ShaderStage; + +constexpr std::uint32_t Threads = 32; +constexpr std::uint32_t Inputs = 4; +constexpr std::uint32_t Results = 16; +alignas(256) std::array Input{}; +alignas(256) std::array Output{}; + +alignas(256) constexpr std::array Code{ + 0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0x06140af9, 0x06000604, 0x7e160307, + 0x08160af9, 0x05061504, 0x0a180af9, 0x06142a04, 0x101a0af9, 0x03260404, 0x0e1c0af9, 0x06010604, + 0x1e1e0af9, 0x160a0604, 0x7e200307, 0x20200af9, 0x08061104, 0x20220af9, 0x060d2604, 0x64240af9, + 0x05010004, 0x66260af9, 0x02150d04, 0x7e280307, 0x68280af9, 0x24031304, 0x6a2a0af9, 0x00040604, + 0x7e2c0307, 0x742c0af9, 0x05081404, 0x722e0af9, 0x19050204, 0x06300af9, 0x06052b04, 0x6a320af9, + 0x06020904, 0xe0781000, 0x80010a03, 0xe0781010, 0x80010e03, 0xe0781020, 0x80011203, 0xe0781030, + 0x80011603, 0xbf810000, +}; + +constexpr std::uint32_t Rows[32][4] = { + {0x00000000u, 0x00000000u, 0x40404040u, 0x8b2af49fu}, + {0x00000000u, 0x10663f9du, 0x8b35e743u, 0x7d7d9db4u}, + {0x0008dbf2u, 0x47004700u, 0x3c000000u, 0x80000000u}, + {0x05c21fabu, 0x00470047u, 0x80000000u, 0x47004700u}, + {0x1a0e7cdeu, 0x00000000u, 0xefc2742bu, 0xcd8d3db8u}, + {0xc4de998au, 0xaf1fba34u, 0x0000bc00u, 0xbc00bc00u}, + {0x00000000u, 0x00470047u, 0xc2c2c2c2u, 0xfda0095du}, + {0x3c000000u, 0x80808080u, 0x5960b098u, 0xadd5eff7u}, + {0xbc00bc00u, 0x00000000u, 0x42a502c0u, 0x3c000000u}, + {0x80808080u, 0x1a64a58eu, 0xfe242714u, 0x3c003c00u}, + {0x00000000u, 0x7c007c00u, 0x7f7f7f7fu, 0x3c003c00u}, + {0x00470047u, 0x00000000u, 0x3468787du, 0x7e7103e1u}, + {0x00470047u, 0x80000000u, 0x702bd672u, 0x47004700u}, + {0x00000000u, 0x00800080u, 0x4659ff82u, 0xc2c2c2c2u}, + {0x7f800000u, 0x00000000u, 0x01000100u, 0x1b1c3f27u}, + {0x80000000u, 0x00800080u, 0xbf800000u, 0x829ea49cu}, + {0x00000000u, 0x0000bc00u, 0x3343e632u, 0x13e60ef5u}, + {0x00000000u, 0x00470047u, 0xb5a54b0bu, 0x6769ec45u}, + {0x00000000u, 0x00800080u, 0xa2e7068bu, 0x871c3c9cu}, + {0x00000000u, 0x00800080u, 0xafe5c4b5u, 0x3c003c00u}, + {0x00000000u, 0x00ff00ffu, 0x0000bc00u, 0x40404040u}, + {0x00000000u, 0x00ff00ffu, 0x7f800000u, 0x00ff00ffu}, + {0x00000000u, 0x00ff00ffu, 0xb4ad5866u, 0xe4ea7accu}, + {0x00000000u, 0x00ff00ffu, 0xd03c7dbeu, 0x5de25876u}, + {0x00000000u, 0x01000100u, 0x52eff50fu, 0x00000000u}, + {0x00000000u, 0x182f8e4au, 0xe117e1fau, 0x0000bc00u}, + {0x00000000u, 0x20d8e2bcu, 0xe73074b1u, 0xbf800000u}, + {0x00000000u, 0x2333ad9cu, 0x00800080u, 0x3f800000u}, + {0x00000000u, 0x24f70eabu, 0xfdb88e95u, 0x17e6487au}, + {0x00000000u, 0x2a778095u, 0x00470047u, 0x7c007c00u}, + {0x00000000u, 0x2b119b05u, 0x0000bc00u, 0x4ce5144fu}, + {0x00000000u, 0x2b5d55fdu, 0x03f55439u, 0x7f7f7f7fu} +}; +constexpr std::uint32_t Expected[32][16] = { + {0x00000000u, 0x0000f49fu, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x8b2a009fu, 0x00000000u, 0x00000000u, 0x80000000u, 0x002af49fu, 0x00000000u, 0x8b2a0000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x10663f9du, 0x10669db4u, 0xff9d0000u, 0x00000000u, 0x00000000u, 0x90663f9du, 0x7d7d00b4u, 0x10663f9du, 0x00000066u, 0x80660000u, 0x9d7d9db4u, 0x00000000u, 0x7d7d0000u, 0x00000000u, 0x9d000000u, 0x00000000u}, + {0x47004700u, 0x94f20000u, 0x00000000u, 0x00000000u, 0x006dbcbdu, 0xc7004700u, 0x8000f200u, 0x3f800000u, 0x00000000u, 0x80080000u, 0x00000000u, 0x00008000u, 0x80004700u, 0x00080000u, 0x00000000u, 0x00003800u}, + {0x004700f2u, 0x1fab4700u, 0xfff20000u, 0x00000000u, 0x00000000u, 0x80470047u, 0x4700ab00u, 0x00470047u, 0x00000066u, 0x86090000u, 0x42004700u, 0x00000001u, 0x47000047u, 0x00c20000u, 0x09000000u, 0x00000000u}, + {0x000000deu, 0x7cde3db8u, 0xffde0000u, 0x00000000u, 0x00000000u, 0x80000000u, 0xcd8ddeb8u, 0x00001a0eu, 0x0000007cu, 0x9a0e0000u, 0x1a8d3db8u, 0x00007edeu, 0xcd8d0000u, 0x000e0000u, 0x0e000000u, 0x00000000u}, + {0xaf1fba34u, 0x998abc00u, 0x00000000u, 0x0000c158u, 0x80000000u, 0x2f1fba34u, 0xbc003400u, 0x00000000u, 0x0000001fu, 0x44de0000u, 0x3400bc00u, 0x00008000u, 0xbc00af1fu, 0x00de0000u, 0x00000000u, 0xffffac00u}, + {0x00470047u, 0x0047095du, 0x00470000u, 0x00000000u, 0x00000000u, 0x80470047u, 0xfda0475du, 0x00470047u, 0x00000047u, 0x80470000u, 0x47a0095du, 0x00000000u, 0xfda00000u, 0x00000000u, 0x47000000u, 0x00000000u}, + {0x80808080u, 0x0000eff7u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0xadd500f7u, 0x00003c00u, 0x00000080u, 0xbc000000u, 0x44d5eff7u, 0x00000000u, 0xadd58080u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x00000000u, 0xbc000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x3c000000u, 0x00000000u, 0x000000bcu, 0x3c000000u, 0xbc000000u, 0x00008000u, 0x3c000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x1a64a58eu, 0x9ae43c00u, 0xff8e0000u, 0x00000000u, 0x00000000u, 0x9a64a58eu, 0x3c008000u, 0x1a64a58eu, 0x00000068u, 0x001c0000u, 0x8e003c00u, 0x00008000u, 0x3c001a64u, 0x00800000u, 0x8e000000u, 0x00000300u}, + {0x7c007c00u, 0x7c003c00u, 0x00000000u, 0x00000000u, 0x00000000u, 0xfc007c00u, 0x3c000000u, 0x3f800000u, 0x00000000u, 0x80000000u, 0x00003c00u, 0x00000000u, 0x3c000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x00000047u, 0x004703e1u, 0x00470000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x7e7147e1u, 0x00000047u, 0x00000000u, 0x80470000u, 0x007103e1u, 0x00000000u, 0x7e710000u, 0x00470000u, 0x47000000u, 0x00000000u}, + {0x00000047u, 0x80474700u, 0x00470000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x47004700u, 0x00000047u, 0x00000000u, 0x80470000u, 0x00004700u, 0x00000000u, 0x47008000u, 0x00470000u, 0x47000000u, 0x00000000u}, + {0x00800080u, 0x0080c2c2u, 0xff800000u, 0x00000000u, 0x00000000u, 0x80800080u, 0xc2c200c2u, 0x00800080u, 0x00000080u, 0x80800000u, 0x80c2c2c2u, 0x00000000u, 0xc2c20000u, 0x00000000u, 0x80000000u, 0x00000000u}, + {0x00000000u, 0x00003f27u, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x1b1c0027u, 0x00007f80u, 0x00000000u, 0xff800000u, 0x7f1c3f27u, 0x00000000u, 0x1b1c0000u, 0x00000000u, 0x80000000u, 0x00000000u}, + {0x00800080u, 0x0080a49cu, 0xff800000u, 0x00000000u, 0x00000000u, 0x80800080u, 0x829e009cu, 0x00800080u, 0x00000080u, 0x80800000u, 0x009ea49cu, 0x00000000u, 0x829e0000u, 0x00000000u, 0x80000000u, 0x00000000u}, + {0x0000bc00u, 0x00000ef5u, 0x00000000u, 0x00000000u, 0x00000000u, 0x8000bc00u, 0x13e600f5u, 0x0000bc00u, 0x00000000u, 0x80000000u, 0x00e60ef5u, 0x00000000u, 0x13e60000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x00470047u, 0x0047ec45u, 0x00470000u, 0x00000000u, 0x00000000u, 0x80470047u, 0x67694745u, 0x00470047u, 0x00000047u, 0x80470000u, 0x4769ec45u, 0x00000000u, 0x67690000u, 0x00000000u, 0x47000000u, 0x00000000u}, + {0x00800080u, 0x00803c9cu, 0xff800000u, 0x00000000u, 0x00000000u, 0x80800080u, 0x871c009cu, 0x00800080u, 0x00000080u, 0x80800000u, 0x801c3c9cu, 0x00000000u, 0x871c0000u, 0x00000000u, 0x80000000u, 0x00000000u}, + {0x00800080u, 0x00803c00u, 0xff800000u, 0x00000000u, 0x00000000u, 0x80800080u, 0x3c000000u, 0x00800080u, 0x00000080u, 0x80800000u, 0x80003c00u, 0x00000000u, 0x3c000000u, 0x00000000u, 0x80000000u, 0x00000000u}, + {0x00ff00ffu, 0x00ff4040u, 0xffff0000u, 0x00000000u, 0x00000000u, 0x80ff00ffu, 0x40400040u, 0x00ff00ffu, 0x000000ffu, 0x80ff0000u, 0xff404040u, 0x00000000u, 0x40400000u, 0x00000000u, 0xff000000u, 0x00000000u}, + {0x00ff00ffu, 0x00ff00ffu, 0xffff0000u, 0x00000000u, 0x00000000u, 0x80ff00ffu, 0x00ff00ffu, 0x00ff00ffu, 0x000000ffu, 0x80ff0000u, 0xffff00ffu, 0x00000000u, 0x00ff0000u, 0x00000000u, 0xff000000u, 0x00000000u}, + {0x00ff00ffu, 0x00ff7accu, 0xffff0000u, 0x00000000u, 0x00000000u, 0x80ff00ffu, 0xe4ea00ccu, 0x00ff00ffu, 0x000000ffu, 0x80ff0000u, 0xffea7accu, 0x00000000u, 0xe4ea0000u, 0x00000000u, 0xff000000u, 0x00000000u}, + {0x00ff00ffu, 0x00ff5876u, 0xffff0000u, 0x00000000u, 0x00000000u, 0x80ff00ffu, 0x5de20076u, 0x00ff00ffu, 0x000000ffu, 0x80ff0000u, 0xffe25876u, 0x00000000u, 0x5de20000u, 0x00000000u, 0xff000000u, 0x00000000u}, + {0x01000100u, 0x01000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x81000100u, 0x00000000u, 0x01000100u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x182f8e4au, 0x182fbc00u, 0x004a0000u, 0x00000000u, 0x00000000u, 0x982f8e4au, 0x00004a00u, 0x182f8e4au, 0x0000002fu, 0x802f0000u, 0x4a00bc00u, 0x00000000u, 0x00000000u, 0x00000000u, 0x4a000000u, 0x00000000u}, + {0x20d8e2bcu, 0x20d80000u, 0xffbc0000u, 0x00000000u, 0x00000000u, 0xa0d8e2bcu, 0xbf800000u, 0x20d8e2bcu, 0x000000d8u, 0x80d80000u, 0xbc800000u, 0x00000000u, 0xbf800000u, 0x00000000u, 0xbc000000u, 0x00000000u}, + {0x2333ad9cu, 0x23330000u, 0xff9c0000u, 0x00000000u, 0x00000000u, 0xa333ad9cu, 0x3f800000u, 0x2333ad9cu, 0x00000033u, 0x80330000u, 0x9c800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x9c000000u, 0x00000000u}, + {0x24f70eabu, 0x24f7487au, 0xffab0000u, 0x00000000u, 0x00000000u, 0xa4f70eabu, 0x17e6007au, 0x24f70eabu, 0x000000f7u, 0x80f70000u, 0xabe6487au, 0x00000000u, 0x17e60000u, 0x00000000u, 0xab000000u, 0x00000000u}, + {0x2a778095u, 0x2a777c00u, 0xff950000u, 0x00000000u, 0x00000000u, 0xaa778095u, 0x7c000000u, 0x2a778095u, 0x00000077u, 0x80770000u, 0x95007c00u, 0x00000000u, 0x7c000000u, 0x00000000u, 0x95000000u, 0x00000000u}, + {0x2b119b05u, 0x2b11144fu, 0x00050000u, 0x00000000u, 0x00000000u, 0xab119b05u, 0x4ce5054fu, 0x2b119b05u, 0x00000011u, 0x80110000u, 0x05e5144fu, 0x00000000u, 0x4ce50000u, 0x00000000u, 0x05000000u, 0x00000000u}, + {0x2b5d55fdu, 0x2b5d7f7fu, 0xfffd0000u, 0x00000000u, 0x00000000u, 0xab5d55fdu, 0x7f7f007fu, 0x2b5d55fdu, 0x0000005du, 0x805d0000u, 0xfd7f7f7fu, 0x00000000u, 0x7f7f0000u, 0x00000000u, 0xfd000000u, 0x00000000u} +}; +constexpr std::uint32_t Checked[32] = {0xffffu, 0xfdfdu, 0x5dadu, 0xa05au, 0xb27au, 0x7fa7u, 0xb818u, 0xea77u, 0xfaffu, 0x5cfdu, 0x7ffdu, 0x9d38u, 0x9d38u, 0xf8fdu, 0xb977u, 0xfcfdu, 0xff5eu, 0xb818u, 0xf8fdu, 0xf8fdu, 0xf8fdu, 0xf8fdu, 0xf8fdu, 0xf8fdu, 0xfffdu, 0xfdbdu, 0xfdfdu, 0xfdfdu, 0xfdfdu, 0xf9fdu, 0xfdbdu, 0xfdfdu}; +constexpr const char* Names[16] = { + "add_f32 BYTE_0/DWORD -> DWORD", + "sub_f32 DWORD/WORD_1 -> WORD_1", + "subrev_f32 WORD_0/DWORD -> BYTE_2", + "mul_f32 DWORD/BYTE_3 -> WORD_0", + "mul_legacy_f32 BYTE_1/DWORD -> DWORD", + "min_f32 BYTE_2/DWORD -> DWORD", + "max_f32 DWORD/BYTE_0 -> BYTE_1", + "max_f32 WORD_1/DWORD -> DWORD", + "add_f16 BYTE_1/WORD_1 -> BYTE_0", + "sub_f16 WORD_1/BYTE_2 -> WORD_1", + "subrev_f16 BYTE_3/WORD_0 -> BYTE_3", + "mul_f16 WORD_0/BYTE_0 -> DWORD", + "min_f16 BYTE_0/WORD_1 -> WORD_0", + "max_f16 WORD_1/BYTE_1 -> BYTE_2", + "add_f32 WORD_1/DWORD -> BYTE_3", + "mul_f16 BYTE_2/DWORD -> BYTE_1", +}; + +void Fill(std::uint32_t tid, std::uint32_t* words) { + std::copy(std::begin(Rows[tid]), std::end(Rows[tid]), words); +} + +std::array BufferDescriptor(const void* data, std::uint32_t bytes) { + const auto address = reinterpret_cast(data); + return {static_cast(address), static_cast((address >> 32u) & 0xffffu), bytes, 0x01016facu}; +} + +std::string Hex(std::uint32_t value) { + char text[16]; + std::snprintf(text, sizeof(text), "0x%08x", value); + return text; +} + +void Expect(std::uint32_t tid, std::uint32_t actual, std::uint32_t expected, const char* name) { + Require(actual == expected, std::string("sdwa float selectors: lane ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected)); +} + +ShaderRecompiler::RecompileResult Compile(AgcDriver::VulkanDevice& device, std::span code) { + std::vector userData(8, 0u); + const auto input = BufferDescriptor(Input.data(), static_cast(Input.size() * 4u)); + const auto output = BufferDescriptor(Output.data(), static_cast(Output.size() * 4u)); + std::copy(input.begin(), input.end(), userData.begin()); + std::copy(output.begin(), output.end(), userData.begin() + 4); + const std::array memory{{{reinterpret_cast(code.data()), std::as_bytes(code)}}}; + const ShaderRecompiler::ShaderComputeStageInfo compute{{Threads, 1, 1}, 0u, {false, false, false}, false, 1}; + ShaderRecompiler::RecompileRequest request{ + {ShaderStage::Compute, reinterpret_cast(code.data()), code, 0, {}}, + {32, 0, userData, compute, std::nullopt, std::nullopt, memory}, + device.Target(), + {0, 0, 0, 128} + }; + request.useCache = false; + return ShaderRecompiler::Recompile(request); +} + +void Run(AgcDriver::VulkanDevice& device) { + for (std::uint32_t tid = 0; tid < Threads; ++tid) Fill(tid, &Input[tid * Inputs]); + Output.fill(0xdeadbeefu); + const std::span code(Code); + const auto result = Compile(device, code); + device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast(code.data())); + device.WaitIdle(); +} + +void CheckByteSelectorClampRefused(AgcDriver::VulkanDevice& device) { + constexpr std::array, 6> forms{{ + {0x640a0cf9u, 0x04052004u}, + {0x660a0cf9u, 0x04022504u}, + {0x680a0cf9u, 0x03042604u}, + {0x6a0a0cf9u, 0x05043304u}, + {0x740a0cf9u, 0x06012404u}, + {0x720a0cf9u, 0x00062604u}, + }}; + for (const auto& form : forms) { + alignas(256) const std::array code{form[0], form[1], 0xbf810000u}; + std::string refusal; + try { + static_cast(Compile(device, code)); + } catch (const std::exception& error) { + refusal = error.what(); + } + Require(refusal.find("VOP2 SDWA clamp with byte selectors is not implemented") != std::string::npos, "f16 SDWA form " + Hex(form[0]) + " " + Hex(form[1]) + " with clamp was not refused"); + } +} + +void Check() { + for (std::uint32_t tid = 0; tid < Threads; ++tid) { + const std::uint32_t* in = &Input[tid * Inputs]; + const std::uint32_t* out = &Output[tid * Results]; + for (std::uint32_t i = 0; i < 16; ++i) { + if ((Checked[tid] >> i) & 1u) { + Expect(tid, out[i], Expected[tid][i], Names[i]); + } + } + } +} + +} + +int main() { + try { + const auto device = OpenVulkanTestDevice(); + if (!device) return VulkanTestSkipped; + Run(*device); + Check(); + CheckByteSelectorClampRefused(*device); + std::puts("sdwa float selectors tests passed"); + return 0; + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp index f91cfbcd5..4a94c8482 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp @@ -23,10 +23,9 @@ struct VectorOpcodeInfo { enum class Vop2SdwaProfile { None, - Float32, - Float16, - PackedFloat16, + Float, Integer, + Float16, }; struct Vop2OpcodeInfo { @@ -44,17 +43,17 @@ struct VopcOpcodeInfo { constexpr Vop2OpcodeInfo vop2Opcodes[] = { {0x01u, RdnaOpcode::VCndmaskB32, Vop2SdwaProfile::Integer}, {0x02u, RdnaOpcode::VDot2cF32F16}, - {0x03u, RdnaOpcode::VAddF32, Vop2SdwaProfile::Float32}, - {0x04u, RdnaOpcode::VSubF32, Vop2SdwaProfile::Float32}, - {0x05u, RdnaOpcode::VSubrevF32}, - {0x08u, RdnaOpcode::VMulF32, Vop2SdwaProfile::Float32}, + {0x03u, RdnaOpcode::VAddF32, Vop2SdwaProfile::Float}, + {0x04u, RdnaOpcode::VSubF32, Vop2SdwaProfile::Float}, + {0x05u, RdnaOpcode::VSubrevF32, Vop2SdwaProfile::Float}, + {0x08u, RdnaOpcode::VMulF32, Vop2SdwaProfile::Float}, {0x09u, RdnaOpcode::VMulI32I24, Vop2SdwaProfile::Integer}, {0x0au, RdnaOpcode::VMulHiI32I24, Vop2SdwaProfile::Integer}, {0x0bu, RdnaOpcode::VMulU32U24, Vop2SdwaProfile::Integer}, {0x0cu, RdnaOpcode::VMulHiU32U24, Vop2SdwaProfile::Integer}, {0x0du, RdnaOpcode::VDot4cI32I8}, - {0x0fu, RdnaOpcode::VMinF32}, - {0x10u, RdnaOpcode::VMaxF32}, + {0x0fu, RdnaOpcode::VMinF32, Vop2SdwaProfile::Float}, + {0x10u, RdnaOpcode::VMaxF32, Vop2SdwaProfile::Float}, {0x11u, RdnaOpcode::VMinI32, Vop2SdwaProfile::Integer}, {0x12u, RdnaOpcode::VMaxI32, Vop2SdwaProfile::Integer}, {0x13u, RdnaOpcode::VMinU32, Vop2SdwaProfile::Integer}, @@ -84,7 +83,7 @@ constexpr Vop2OpcodeInfo vop2Opcodes[] = { {0x2bu, RdnaOpcode::VMacF32}, {0x2cu, RdnaOpcode::VMadmkF32}, {0x2du, RdnaOpcode::VMadakF32}, - {0x2fu, RdnaOpcode::VCvtPkrtzF16F32, Vop2SdwaProfile::PackedFloat16}, + {0x2fu, RdnaOpcode::VCvtPkrtzF16F32, Vop2SdwaProfile::Float}, {0x32u, RdnaOpcode::VAddF16, Vop2SdwaProfile::Float16}, {0x33u, RdnaOpcode::VSubF16, Vop2SdwaProfile::Float16}, {0x34u, RdnaOpcode::VSubrevF16, Vop2SdwaProfile::Float16}, @@ -96,7 +95,7 @@ constexpr Vop2OpcodeInfo vop2Opcodes[] = { {0x3au, RdnaOpcode::VMinF16, Vop2SdwaProfile::Float16}, {0x3cu, RdnaOpcode::VPkFmacF16}, {0x06u, RdnaOpcode::VMacLegacyF32}, - {0x07u, RdnaOpcode::VMulLegacyF32}, + {0x07u, RdnaOpcode::VMulLegacyF32, Vop2SdwaProfile::Float}, {0x3bu, RdnaOpcode::VLdexpF16}, }; @@ -1298,14 +1297,14 @@ struct Vop2SdwaRule { std::uint32_t src1Selectors = sdwaSelFull(); bool partialDst = false; bool sourceModifiers = false; + bool byteSelectorClamp = true; }; constexpr Vop2SdwaRule vop2SdwaRules[] = { {}, - {sdwaSelFull(), sdwaSelFull(), sdwaSelFull(), false, true}, - {sdwaSelWords() | sdwaSelFull(), sdwaSelWords() | sdwaSelFull(), sdwaSelWords() | sdwaSelFull(), true, true}, {sdwaSelAll(), sdwaSelAll(), sdwaSelAll(), true, true}, {sdwaSelAll(), sdwaSelAll(), sdwaSelAll(), true, false}, + {sdwaSelAll(), sdwaSelAll(), sdwaSelAll(), true, true, false}, }; const Vop2SdwaRule* findVop2SdwaRule(std::uint32_t encoding) { @@ -1365,6 +1364,10 @@ void validateVop2Sdwa(const RdnaInstruction& instruction, std::uint32_t opcode, if (!rule->sourceModifiers && hasSourceModifiers && !cndmaskFloatModifiers) { throw std::invalid_argument("VOP2 SDWA source modifiers are not supported"); } + const bool byteSelector = fields.src0Sel < 4u || fields.src1Sel < 4u || fields.dstSel < 4u; + if (!rule->byteSelectorClamp && fields.clamp != 0u && byteSelector) { + throw std::invalid_argument("VOP2 SDWA clamp with byte selectors is not implemented"); + } } void finalizeVop2Instruction(std::span code, std::uint32_t wordIndex, RdnaInstruction& instruction) {