From a61052807525918672ee098e4e4f100cff46ee6c Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 23 Aug 2026 00:59:44 +0200 Subject: [PATCH] shader: V_CMPX_NE_I64 --- .../frontend/decode/ShaderDecoder.h | 1 + .../frontend/decode/VectorAluOps.cpp | 2 + .../recompiler/ir/opcodes/ShaderIROpcodes.cpp | 1 + tests/ShaderRecompilerComputeTests.cpp | 31 +++++++++++++++ tests/shaderCfgTests.cpp | 39 ++++++++++++++++++- 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h index 1cc10b892..89011f4df 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h @@ -389,6 +389,7 @@ enum class Opcode { V_CMP_EQ_I64, V_CMP_GT_U64, V_CMP_NE_U64, + V_CMPX_NE_I64, V_CMPX_NE_U64, V_CMPX_LT_U32, V_CMPX_EQ_U32, diff --git a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp index b3638420e..21d0f2c78 100644 --- a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp @@ -229,6 +229,7 @@ constexpr VopcOpcodeInfo VOPC_OPCODE_LIST[] = { {0xc3u, Opcode::V_CMP_LE_U32}, {0xc4u, Opcode::V_CMP_GT_U32}, {0xc5u, Opcode::V_CMP_NE_U32}, {0xc6u, Opcode::V_CMP_GE_U32}, {0xc7u, Opcode::V_CMP_T_U32}, {0xa2u, Opcode::V_CMP_EQ_I64, false}, + {0xb5u, Opcode::V_CMPX_NE_I64, false}, {0xd1u, Opcode::V_CMPX_LT_U32}, {0xd2u, Opcode::V_CMPX_EQ_U32}, {0xd3u, Opcode::V_CMPX_LE_U32}, {0xd4u, Opcode::V_CMPX_GT_U32}, {0xd5u, Opcode::V_CMPX_NE_U32}, {0xd6u, Opcode::V_CMPX_GE_U32}, @@ -1499,6 +1500,7 @@ bool IsVopcCompareExec(Opcode opcode) { case Opcode::V_CMPX_GT_U32: case Opcode::V_CMPX_NE_U32: case Opcode::V_CMPX_GE_U32: + case Opcode::V_CMPX_NE_I64: case Opcode::V_CMPX_NE_U64: case Opcode::V_CMPX_LT_F16: case Opcode::V_CMPX_EQ_F16: diff --git a/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.cpp b/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.cpp index 7d68b81ce..5b8b4aff8 100644 --- a/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.cpp +++ b/src/graphics/shader/recompiler/ir/opcodes/ShaderIROpcodes.cpp @@ -338,6 +338,7 @@ constexpr LowerMap LOWER_OPS[] = { {Decoder::Opcode::V_CMP_EQ_I64, Opcode::CompareEqU64}, {Decoder::Opcode::V_CMP_GT_U64, Opcode::CompareGtU64}, {Decoder::Opcode::V_CMP_NE_U64, Opcode::CompareNeU64}, + {Decoder::Opcode::V_CMPX_NE_I64, Opcode::CompareNeU64}, {Decoder::Opcode::V_CMPX_NE_U64, Opcode::CompareNeU64}, {Decoder::Opcode::V_CMPX_LT_U32, Opcode::CompareMaskLtU32}, {Decoder::Opcode::V_CMPX_EQ_U32, Opcode::CompareMaskEqU32}, diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 32ef09114..61f2e6b0b 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -14748,6 +14748,36 @@ TestCase VectorVopcCmpxNeU64CapturedExecMask() { return test; } +TestCase VectorVop3CmpxNeI64CapturedExecMask() { + using O = ShaderOpcode; + + std::vector code; + AppendVMovU32(&code, 7, 0); + AppendVMovU32(&code, 8, 0); + AppendVMovU32(&code, 31, 0); + code.push_back(0xd4b5007eu); + code.push_back(0x00020e80u); // v_cmpx_ne_i64 exec, 0, v[7:8] + AppendBufferStoreDword(&code, 8, 31); + + code.push_back(EncodeSMovB32(126, InlineU32(1))); + AppendVMovU32(&code, 8, 1); + AppendVMovU32(&code, 31, 4); + code.push_back(0xd4b5007eu); + code.push_back(0x00020e80u); // v_cmpx_ne_i64 exec, 0, v[7:8] + AppendBufferStoreDword(&code, 8, 31); + AppendEnd(&code); + + TestCase test{"VectorVop3CmpxNeI64CapturedExecMask", + code, + {0x11223344u, 0x55667788u}, + {0x11223344u, 1u}, + {O::V_MOV_B32, O::V_CMPX_NE_I64, O::BUFFER_STORE_DWORD, + O::S_MOV_B32, O::S_ENDPGM}}; + test.decoded_counts = {{"V_CMPX_NE_I64 exec_lo, 0, v7", 2}}; + test.native_ir_counts = {{"CompareNeU64 exec_lo, 0x00000000, v7", 2}}; + return test; +} + TestCase VectorVop3CompareGtU64OnGpu() { using O = ShaderOpcode; @@ -19593,6 +19623,7 @@ std::vector MakeCases() { AddCase(VectorVop3CompareGtU64OnGpu); AddCase(VectorVop3CompareNeU64OnGpu); AddCase(VectorVopcCmpxNeU64CapturedExecMask); + AddCase(VectorVop3CmpxNeI64CapturedExecMask); AddCase(VectorCompareClassF32); AddCase(VectorCompareF16Ops); AddCase(Vop2SdwaCndmaskSourceModifier); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index c31c36c13..46e6902fc 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -4044,8 +4044,9 @@ void TestNewShaderDecoderArchitecture() { } void TestNewShaderRecompilerRejectsDppOn64BitCompares() { - const uint32_t opcodes[] = {0xa2u, 0xe4u, 0xe5u, - 0xf5u}; // eq_i64, gt_u64, ne_u64, cmpx_ne_u64 + const uint32_t opcodes[] = { + 0xa2u, 0xb5u, 0xe4u, 0xe5u, + 0xf5u}; // eq_i64, cmpx_ne_i64, gt_u64, ne_u64, cmpx_ne_u64 for (const auto opcode : opcodes) { const uint32_t shader[] = { EncodeVopc(opcode, 250u, 0u), // DPP escape in SRC0 @@ -8367,6 +8368,40 @@ void TestNewShaderRecompilerU64PairLowering() { CompileResult result; std::string error; + const uint32_t cmpx_i64_shader[] = { + 0xd4b5007eu, 0x00020e80u, // v_cmpx_ne_i64 exec, 0, v[7:8] + EncodeSopp(0x01), + }; + Decoder::Instruction decoded_cmpx_i64; + Check(Decoder::DecodeInstruction(cmpx_i64_shader, 0u, decoded_cmpx_i64, + &error), + error.c_str()); + Check(decoded_cmpx_i64.opcode == Decoder::Opcode::V_CMPX_NE_I64 && + decoded_cmpx_i64.dst.kind == Decoder::OperandKind::ExecLo && + decoded_cmpx_i64.src0.value == 0u && + decoded_cmpx_i64.src1.kind == Decoder::OperandKind::Vgpr && + decoded_cmpx_i64.src1.reg == 7u, + "decoder rejected captured VOP3 V_CMPX_NE_I64 fields"); + Check(TryRecompile(cmpx_i64_shader, options, result, &error), error.c_str()); + Check(Common::ContainsStr(result.decoded_dump, + "V_CMPX_NE_I64 exec_lo, 0, v7"), + "captured VOP3 V_CMPX_NE_I64 was not present in the decoded dump"); + Decoder::Program decoded_i64_program; + CFG::Graph graph_i64; + IR::Program native_i64; + Check(Decoder::DecodeProgram(cmpx_i64_shader, decoded_i64_program, &error), + error.c_str()); + Check(CFG::BuildGraph(decoded_i64_program, graph_i64, &error) && + CFG::Structurize(graph_i64, &error), + error.c_str()); + Check(IR::LowerProgram(decoded_i64_program, graph_i64, ShaderType::Compute, + 64u, native_i64, &error), + error.c_str()); + Check(Common::ContainsStr(IR::ProgramToString(native_i64), + "CompareNeU64 exec_lo, 0x00000000, v7"), + "V_CMPX_NE_I64 did not lower to masked 64-bit inequality"); + CheckSpirvBinaryValidates(result.spirv); + const uint32_t cmpx_shader[] = { 0x7dea0e80u, // v_cmpx_ne_u64 exec, 0, v[7:8] EncodeSopp(0x01),