diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h index 8ca2b7f1..a2b346a5 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h @@ -391,6 +391,7 @@ enum class Opcode { V_CMP_GE_U32, V_CMP_T_U32, V_CMP_EQ_I64, + V_CMP_EQ_U64, V_CMP_GT_U64, V_CMP_NE_U64, V_CMPX_NE_I64, diff --git a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp index b324b07e..1e6c8663 100644 --- a/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/VectorAluOps.cpp @@ -234,7 +234,8 @@ constexpr VopcOpcodeInfo VOPC_OPCODE_LIST[] = { {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}, - {0xe4u, Opcode::V_CMP_GT_U64, false}, {0xe5u, Opcode::V_CMP_NE_U64, false}, + {0xe2u, Opcode::V_CMP_EQ_U64, false}, {0xe4u, Opcode::V_CMP_GT_U64, false}, + {0xe5u, Opcode::V_CMP_NE_U64, false}, {0xf5u, Opcode::V_CMPX_NE_U64, false}, {0xc9u, Opcode::V_CMP_LT_F16}, {0xcau, Opcode::V_CMP_EQ_F16}, {0xcbu, Opcode::V_CMP_LE_F16}, {0xccu, Opcode::V_CMP_GT_F16}, diff --git a/src/graphics/shader/recompiler/frontend/translate/Vector.cpp b/src/graphics/shader/recompiler/frontend/translate/Vector.cpp index 6a5bbc0c..a3b8b721 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Vector.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Vector.cpp @@ -96,6 +96,7 @@ bool Translator::EmitVector(const Decoder::Instruction& inst, std::string* error EmitIntegerCompare(inst, IR::ValueOpcode::SLessThanEqual32, IR::Type::U32, false, true); return true; case O::V_CMP_EQ_I64: + case O::V_CMP_EQ_U64: EmitIntegerCompare(inst, IR::ValueOpcode::IEqual64, IR::Type::U64, false, false); return true; case O::V_CMP_GT_U64: diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 4f6ba5bd..a08bf9c2 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -15414,6 +15414,36 @@ TestCase VectorCompareOps() { O::V_CMP_T_U32, O::BUFFER_STORE_DWORD, O::S_ENDPGM}}; } +TestCase VectorVop3CompareEqU64OnGpu() { + using O = ShaderOpcode; + + std::vector code; + code.push_back(EncodeVop1(0x01, 1, InlineU32(1))); + + code.push_back(EncodeSop1(0x04, 106, 126)); // s_mov_b64 vcc, exec + code.push_back(0xd4e2006au); + code.push_back(0x0000d47eu); // v_cmp_eq_u64 vcc, exec, vcc + code.push_back(EncodeVop2(0x01, 2, InlineU32(0), 1)); + AppendStoreVgpr(&code, 2, 0); + + AppendSMovLiteral(&code, 107, 1); // high-dword mismatch + code.push_back(0xd4e2006au); + code.push_back(0x0000d47eu); // v_cmp_eq_u64 vcc, exec, vcc + code.push_back(EncodeVop2(0x01, 3, InlineU32(0), 1)); + AppendStoreVgpr(&code, 3, 1); + AppendEnd(&code); + + TestCase test{"VectorVop3CompareEqU64OnGpu", + code, + {}, + {1, 0}, + {O::V_MOV_B32, O::S_MOV_B64, O::V_CMP_EQ_U64, + O::V_CNDMASK_B32, O::S_MOV_B32, O::BUFFER_STORE_DWORD, + O::S_ENDPGM}}; + test.decoded_counts = {{"V_CMP_EQ_U64 vcc_lo, exec_lo, vcc_lo", 2}}; + return test; +} + TestCase VectorVop3CompareNeU64OnGpu() { using O = ShaderOpcode; @@ -20487,6 +20517,7 @@ std::vector MakeCases() { AddCase(VectorSinCosMaxFiniteSpecialCases); AddCase(VectorCompareOps); AddCase(VectorVop3CompareEqI64OnGpu); + AddCase(VectorVop3CompareEqU64OnGpu); AddCase(VectorVop3CompareGtU64OnGpu); AddCase(VectorVop3CompareNeU64OnGpu); AddCase(VectorVopcCmpxNeU64CapturedExecMask); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index c0968568..9d2f95e6 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -4007,6 +4007,18 @@ void TestNewShaderDecoderArchitecture() { program_direct.word_count, "program decoder diverged from the single-instruction decoder"); + const uint32_t cmp_eq_u64_code[] = {0xd4e2006au, 0x0000d47eu}; + Instruction cmp_eq_u64; + Check(DecodeInstruction(cmp_eq_u64_code, 0u, cmp_eq_u64, &error), + error.c_str()); + Check(cmp_eq_u64.family == Family::VOP3 && + cmp_eq_u64.opcode == Opcode::V_CMP_EQ_U64 && + cmp_eq_u64.dst.kind == OperandKind::VccLo && + cmp_eq_u64.src_count == 2u && + cmp_eq_u64.src0.kind == OperandKind::ExecLo && + cmp_eq_u64.src1.kind == OperandKind::VccLo, + "decoder rejected the captured VOP3 V_CMP_EQ_U64 instruction"); + const uint32_t literal_code[] = {EncodeVop1(0x01, 2, 255u), 0x12345678u}; Instruction literal; Check(DecodeInstruction(literal_code, 0u, literal, &error), error.c_str()); @@ -4126,8 +4138,8 @@ void TestNewShaderDecoderArchitecture() { void TestNewShaderRecompilerRejectsDppOn64BitCompares() { const uint32_t opcodes[] = { - 0xa2u, 0xb5u, 0xe4u, 0xe5u, - 0xf5u}; // eq_i64, cmpx_ne_i64, gt_u64, ne_u64, cmpx_ne_u64 + 0xa2u, 0xb5u, 0xe2u, 0xe4u, 0xe5u, + 0xf5u}; // eq_i64, cmpx_ne_i64, eq_u64, gt_u64, ne_u64, cmpx_ne_u64 for (const auto opcode : opcodes) { const uint32_t shader[] = { EncodeVopc(opcode, 250u, 0u), // DPP escape in SRC0