From 35c4dca2ce7a90ec1a82f4e3f4d2a6070ac8f2f4 Mon Sep 17 00:00:00 2001 From: nmzik Date: Tue, 29 Sep 2026 18:30:51 +0400 Subject: [PATCH] shader: add V_CMPX_NLE_F16 opcode --- .../frontend/decode/ShaderDecoder.h | 1 + .../frontend/decode/VectorAluOps.cpp | 5 +- .../recompiler/frontend/translate/Vector.cpp | 3 ++ tests/ShaderRecompilerComputeTests.cpp | 47 +++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h index 7b98e469..e23b5204 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h @@ -399,6 +399,7 @@ enum class Opcode { V_CMPX_GT_F16, V_CMPX_GE_F16, V_CMPX_NGT_F16, + V_CMPX_NLE_F16, V_CMPX_NEQ_F16, V_CMPX_NLT_F16, V_CMPX_LT_I32, diff --git a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp index 7881bdcc..176fad74 100644 --- a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp @@ -262,7 +262,8 @@ constexpr VopcOpcodeInfo VOPC_OPCODE_LIST[] = { {0xd9u, Opcode::V_CMPX_LT_F16}, {0xdau, Opcode::V_CMPX_EQ_F16}, {0xdbu, Opcode::V_CMPX_LE_F16}, {0xdcu, Opcode::V_CMPX_GT_F16}, {0xdeu, Opcode::V_CMPX_GE_F16}, {0xfbu, Opcode::V_CMPX_NGT_F16}, - {0xfdu, Opcode::V_CMPX_NEQ_F16}, {0xfeu, Opcode::V_CMPX_NLT_F16}, + {0xfcu, Opcode::V_CMPX_NLE_F16}, {0xfdu, Opcode::V_CMPX_NEQ_F16}, + {0xfeu, Opcode::V_CMPX_NLT_F16}, }; constexpr auto VOPC_OPS = Detail::MakeOpcodeTable<0x100>(VOPC_OPCODE_LIST); @@ -868,6 +869,7 @@ bool IsVopcFloatCompareOpcode(Opcode opcode) { case Opcode::V_CMPX_GT_F16: case Opcode::V_CMPX_GE_F16: case Opcode::V_CMPX_NGT_F16: + case Opcode::V_CMPX_NLE_F16: case Opcode::V_CMPX_NEQ_F16: case Opcode::V_CMPX_NLT_F16: case Opcode::V_CMP_CLASS_F32: @@ -1494,6 +1496,7 @@ bool IsVopcCompareExec(Opcode opcode) { case Opcode::V_CMPX_GT_F16: case Opcode::V_CMPX_GE_F16: case Opcode::V_CMPX_NGT_F16: + case Opcode::V_CMPX_NLE_F16: case Opcode::V_CMPX_NEQ_F16: case Opcode::V_CMPX_NLT_F16: return true; default: return false; diff --git a/src/graphics/shader/recompiler/frontend/translate/Vector.cpp b/src/graphics/shader/recompiler/frontend/translate/Vector.cpp index 68855e5d..5f2e0371 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Vector.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Vector.cpp @@ -273,6 +273,9 @@ void Translator::EmitVector(const Decoder::Instruction& inst) { case O::V_CMPX_NGT_F16: EmitFloatCompare(inst, IR::ValueOpcode::FPUnordLessThanEqual32, true, true); return; + case O::V_CMPX_NLE_F16: + EmitFloatCompare(inst, IR::ValueOpcode::FPUnordGreaterThan32, true, true); + return; case O::V_CMP_NEQ_F16: EmitFloatCompare(inst, IR::ValueOpcode::FPUnordNotEqual32, true, false); return; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 4c0cbbcd..8edeeb01 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -23792,6 +23792,51 @@ TestCase VectorVopcCmpxNgtF16CapturedSdwaExecMask() { return test; } +TestCase VectorVopcCmpxNleF16CapturedSdwaExecMask() { + using O = ShaderOpcode; + struct CompareCase { u32 value, expected, exec = 1; bool vop3 = false; }; + const std::array cases{{ + {0x3c007e00u, 1}, {0xbc003c00u, 0}, // High half +1/-1; opposite low halves. + {0x00003c00u, 0}, {0x80003c00u, 0}, // Signed zeros. + {0x7e003c00u, 1}, {0x7c013c00u, 1}, // Quiet/signaling NaN are unordered. + {0x7c003c00u, 1}, {0xfc003c00u, 0}, // Infinities. + {0x3c000000u, 0, 0}, // Inactive lane cannot enter EXEC. + {0x0000bc00u, 1, 1, true}, // VOP3 negates -1 before comparison. + }}; + constexpr u32 sentinel = 0x89abcdefu; + TestCase test; + test.name = "VectorVopcCmpxNleF16CapturedSdwaExecMask"; + for (const auto &entry : cases) test.initial.push_back(entry.value); + test.expected = test.initial; + auto &code = test.code; + for (u32 i = 0; i < cases.size(); ++i) { + const auto &entry = cases[i]; + AppendVMovU32(&code, 30, i * 4u); + AppendBufferLoadDword(&code, 5, 30); + AppendSMovLiteral(&code, 106, sentinel); + AppendSMovLiteral(&code, 107, sentinel); + code.push_back(EncodeSMovB32(126, InlineU32(entry.exec))); + if (entry.vop3) { + AppendVop3(&code, 0xfc, 106, Vgpr(5), InlineU32(0), 0, 0, 0, false, 0, 1); + } else { + code.insert(code.end(), {0x7df900f9u, 0x86050005u}); + } + code.push_back(EncodeSMovB32(8, 126)); + code.push_back(EncodeSMovB32(126, InlineU32(1))); + const u32 out = test.expected.size(); + code.push_back(EncodeVop1(0x01, 0, 8)); + AppendStoreVgpr(&code, 0, out); + AppendStoreSgprPair(&code, 106, out + 1u); + test.expected.insert(test.expected.end(), {entry.expected, sentinel, sentinel}); + } + AppendEnd(&code); + test.opcodes = {O::V_MOV_B32, O::S_MOV_B32, O::BUFFER_LOAD_DWORD, + O::V_CMPX_NLE_F16, O::BUFFER_STORE_DWORD, O::S_ENDPGM}; + test.decoded_counts = {{"V_CMPX_NLE_F16", cases.size()}}; + test.required_spirv = {"OpFUnordGreaterThan"}; + return test; +} + TestCase VectorCompareInvertedMaskSelect() { using O = ShaderOpcode; @@ -30233,6 +30278,7 @@ std::vector MakeCases() { AddCase(VectorVopcCmpNgtF16CapturedSdwaAndEdges); AddCase(VectorVopcCmpNltF16CapturedSdwaAndEdges); AddCase(VectorVopcCmpxNgtF16CapturedSdwaExecMask); + AddCase(VectorVopcCmpxNleF16CapturedSdwaExecMask); AddCase(VectorCompareInvertedMaskSelect); AddCase(BranchSelect); AddCase(SimpleLoop); @@ -35148,6 +35194,7 @@ int main(int argc, char **argv) { VulkanHarness vulkan; RunCase(&vulkan, VectorVopcCmpNgtF16CapturedSdwaAndEdges()); RunCase(&vulkan, VectorVopcCmpxNgtF16CapturedSdwaExecMask()); + RunCase(&vulkan, VectorVopcCmpxNleF16CapturedSdwaExecMask()); RunCase(&vulkan, VectorCompareF16Ops()); RunCase(&vulkan, Wave32VccMasksPreserveOtherHalf()); RunCase(&vulkan, VectorVop3FloatCompareNegSourceModifier());