From 9c316e6988560983b95e1ac8b51006f938bfbb4a Mon Sep 17 00:00:00 2001 From: nmzik Date: Sat, 15 Aug 2026 04:33:30 +0200 Subject: [PATCH] shader: implement RDNA2 v_cmp_gt_u64 --- .../frontend/decode/ShaderDecoder.cpp | 1 + .../frontend/decode/ShaderDecoder.h | 1 + .../frontend/decode/VectorAluOps.cpp | 16 +++---- .../recompiler/frontend/translate/Compare.cpp | 4 ++ .../recompiler/ir/opcodes/ShaderIROpcodes.cpp | 1 + .../recompiler/ir/opcodes/ShaderIROpcodes.inc | 1 + tests/ShaderRecompilerComputeTests.cpp | 43 +++++++++++++++++++ tests/shaderCfgTests.cpp | 2 +- 8 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp index b192346c5..dd961f693 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp @@ -779,6 +779,7 @@ std::string OpcodeToString(Opcode opcode) { case Opcode::VCmpGeU32: return "v_cmp_ge_u32"; case Opcode::VCmpTU32: return "v_cmp_t_u32"; case Opcode::VCmpEqI64: return "v_cmp_eq_i64"; + case Opcode::VCmpGtU64: return "v_cmp_gt_u64"; case Opcode::VCmpNeU64: return "v_cmp_ne_u64"; case Opcode::VCmpxLtU32: return "v_cmpx_lt_u32"; case Opcode::VCmpxEqU32: return "v_cmpx_eq_u32"; diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h index 9cca50dde..c12a10602 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h @@ -377,6 +377,7 @@ enum class Opcode { VCmpGeU32, VCmpTU32, VCmpEqI64, + VCmpGtU64, VCmpNeU64, VCmpxLtU32, VCmpxEqU32, diff --git a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp index d84b948a4..63625f14f 100644 --- a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp @@ -225,14 +225,14 @@ constexpr VopcOpcodeInfo VOPC_OPS[] = { {0xd1u, Opcode::VCmpxLtU32}, {0xd2u, Opcode::VCmpxEqU32}, {0xd3u, Opcode::VCmpxLeU32}, {0xd4u, Opcode::VCmpxGtU32}, {0xd5u, Opcode::VCmpxNeU32}, {0xd6u, Opcode::VCmpxGeU32}, - {0xe5u, Opcode::VCmpNeU64, false}, {0xc9u, Opcode::VCmpLtF16}, - {0xcau, Opcode::VCmpEqF16}, {0xcbu, Opcode::VCmpLeF16}, - {0xccu, Opcode::VCmpGtF16}, {0xcdu, Opcode::VCmpLgF16}, - {0xceu, Opcode::VCmpGeF16}, {0xedu, Opcode::VCmpNeqF16}, - {0xd9u, Opcode::VCmpxLtF16}, {0xdau, Opcode::VCmpxEqF16}, - {0xdbu, Opcode::VCmpxLeF16}, {0xdcu, Opcode::VCmpxGtF16}, - {0xdeu, Opcode::VCmpxGeF16}, {0xfdu, Opcode::VCmpxNeqF16}, - {0xfeu, Opcode::VCmpxNltF16}, + {0xe4u, Opcode::VCmpGtU64, false}, {0xe5u, Opcode::VCmpNeU64, false}, + {0xc9u, Opcode::VCmpLtF16}, {0xcau, Opcode::VCmpEqF16}, + {0xcbu, Opcode::VCmpLeF16}, {0xccu, Opcode::VCmpGtF16}, + {0xcdu, Opcode::VCmpLgF16}, {0xceu, Opcode::VCmpGeF16}, + {0xedu, Opcode::VCmpNeqF16}, {0xd9u, Opcode::VCmpxLtF16}, + {0xdau, Opcode::VCmpxEqF16}, {0xdbu, Opcode::VCmpxLeF16}, + {0xdcu, Opcode::VCmpxGtF16}, {0xdeu, Opcode::VCmpxGeF16}, + {0xfdu, Opcode::VCmpxNeqF16}, {0xfeu, Opcode::VCmpxNltF16}, }; static_assert(Detail::HasUniqueEncodings(VOPC_OPS)); diff --git a/src/graphics/shader/recompiler/frontend/translate/Compare.cpp b/src/graphics/shader/recompiler/frontend/translate/Compare.cpp index 0a3d0d964..8cd406ba4 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Compare.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Compare.cpp @@ -40,6 +40,10 @@ bool Translator::TranslateIntegerCompare(const IR::Instruction& inst) { opcode = IR::ValueOpcode::IEqual64; type = IR::Type::U64; break; + case IR::Opcode::CompareGtU64: + opcode = IR::ValueOpcode::UGreaterThan64; + type = IR::Type::U64; + break; case IR::Opcode::CompareNeU64: opcode = IR::ValueOpcode::INotEqual64; type = IR::Type::U64; diff --git a/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.cpp b/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.cpp index 1da0bf344..ff1328bf0 100644 --- a/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.cpp +++ b/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.cpp @@ -328,6 +328,7 @@ constexpr LowerMap LOWER_OPS[] = { {Decoder::Opcode::VCmpGeU32, Opcode::CompareGeU32}, {Decoder::Opcode::VCmpTU32, Opcode::CompareTrue}, {Decoder::Opcode::VCmpEqI64, Opcode::CompareEqU64}, + {Decoder::Opcode::VCmpGtU64, Opcode::CompareGtU64}, {Decoder::Opcode::VCmpNeU64, Opcode::CompareNeU64}, {Decoder::Opcode::VCmpxLtU32, Opcode::CompareMaskLtU32}, {Decoder::Opcode::VCmpxEqU32, Opcode::CompareMaskEqU32}, diff --git a/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.inc b/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.inc index e7f9dac73..dce998b8f 100644 --- a/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.inc +++ b/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.inc @@ -122,6 +122,7 @@ IR_OPCODE(CompareGeU32, Compare, IntegerCompare) IR_OPCODE(CompareLtU32, Compare, IntegerCompare) IR_OPCODE(CompareLeU32, Compare, IntegerCompare) IR_OPCODE(CompareEqU64, Compare64, IntegerCompare) +IR_OPCODE(CompareGtU64, Compare64, IntegerCompare) IR_OPCODE(CompareNeU64, Compare64, IntegerCompare) IR_OPCODE(CompareMaskEqU32, Compare, IntegerCompare) IR_OPCODE(CompareMaskNeU32, Compare, IntegerCompare) diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 00b55a02a..bae823460 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -12959,6 +12959,48 @@ TestCase VectorVop3CompareNeU64OnGpu() { O::BufferStoreDword, O::SEndpgm}}; } +TestCase VectorVop3CompareGtU64OnGpu() { + using O = ShaderOpcode; + + std::vector code; + code.push_back(EncodeVop1(0x01, 1, InlineU32(1))); + + AppendSMovLiteral(&code, 4, 0); + AppendSMovLiteral(&code, 5, 0x80000000u); + code.push_back(0xd4e4006au); + code.push_back(0x00010004u); // v_cmp_gt_u64 vcc, s[4:5], 0 + code.push_back(EncodeVop2(0x01, 2, InlineU32(0), 1)); + AppendStoreVgpr(&code, 2, 0); + + code.push_back(0xd4e4006au); + code.push_back(0x0001006au); // v_cmp_gt_u64 vcc, vcc, 0 + code.push_back(EncodeVop2(0x01, 3, InlineU32(0), 1)); + AppendStoreVgpr(&code, 3, 1); + + AppendSMovLiteral(&code, 106, 0); + AppendSMovLiteral(&code, 107, 0); + code.push_back(0xd4e4006au); + code.push_back(0x0001006au); // v_cmp_gt_u64 vcc, vcc, 0 + code.push_back(EncodeVop2(0x01, 4, InlineU32(0), 1)); + AppendStoreVgpr(&code, 4, 2); + AppendEnd(&code); + + TestCase test{"VectorVop3CompareGtU64OnGpu", + code, + {}, + {1, 1, 0}, + {O::VMovB32, O::SMovB32, O::VCmpGtU64, O::VCndmaskB32, + O::BufferStoreDword, O::SEndpgm}}; + test.required_spirv = {"OpUGreaterThan"}; + test.compute_info.threads_num[0] = 64; + test.compute_info.threads_num[1] = 1; + test.compute_info.threads_num[2] = 1; + test.compute_info.wave_size = 32; + test.compute_info.thread_ids_num = 1; + test.has_compute_info = true; + return test; +} + TestCase VectorVop3CompareEqI64OnGpu() { using O = ShaderOpcode; @@ -16796,6 +16838,7 @@ std::vector MakeCases() { AddCase(VectorSinCosMaxFiniteSpecialCases); AddCase(VectorCompareOps); AddCase(VectorVop3CompareEqI64OnGpu); + AddCase(VectorVop3CompareGtU64OnGpu); AddCase(VectorVop3CompareNeU64OnGpu); AddCase(VectorCompareClassF32); AddCase(VectorCompareF16Ops); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index bd00fa899..bd8acfceb 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -3305,7 +3305,7 @@ void CheckNewDecoderUnsupported(const uint32_t *shader, uint32_t words, } void TestNewShaderRecompilerRejectsDppOn64BitCompares() { - const uint32_t opcodes[] = {0xa2u, 0xe5u}; // v_cmp_eq_i64, v_cmp_ne_u64 + const uint32_t opcodes[] = {0xa2u, 0xe4u, 0xe5u}; // eq_i64, gt_u64, ne_u64 for (const auto opcode : opcodes) { const uint32_t shader[] = { EncodeVopc(opcode, 250u, 0u), // DPP escape in SRC0