diff --git a/src/graphics/shader/recompiler/decompiler/ShaderDecoder.cpp b/src/graphics/shader/recompiler/decompiler/ShaderDecoder.cpp index d9d23a782..b71b5d568 100644 --- a/src/graphics/shader/recompiler/decompiler/ShaderDecoder.cpp +++ b/src/graphics/shader/recompiler/decompiler/ShaderDecoder.cpp @@ -766,6 +766,7 @@ std::string OpcodeToString(Opcode opcode) { case Opcode::VCmpNeU32: return "v_cmp_ne_u32"; 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::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/decompiler/ShaderDecoder.h b/src/graphics/shader/recompiler/decompiler/ShaderDecoder.h index f46374d74..44df261af 100644 --- a/src/graphics/shader/recompiler/decompiler/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/decompiler/ShaderDecoder.h @@ -374,6 +374,7 @@ enum class Opcode { VCmpNeU32, VCmpGeU32, VCmpTU32, + VCmpEqI64, VCmpNeU64, VCmpxLtU32, VCmpxEqU32, diff --git a/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp b/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp index 870f3d539..664dacad3 100644 --- a/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp +++ b/src/graphics/shader/recompiler/decompiler/VectorAluOps.cpp @@ -157,13 +157,14 @@ constexpr OpcodeMap VOPC_OPS[] = { {0xaeu, Opcode::VCmpGeU16}, {0xc0u, Opcode::VCmpFU32}, {0xc1u, Opcode::VCmpLtU32}, {0xc2u, Opcode::VCmpEqU32}, {0xc3u, Opcode::VCmpLeU32}, {0xc4u, Opcode::VCmpGtU32}, {0xc5u, Opcode::VCmpNeU32}, {0xc6u, Opcode::VCmpGeU32}, {0xc7u, Opcode::VCmpTU32}, - {0xd1u, Opcode::VCmpxLtU32}, {0xd2u, Opcode::VCmpxEqU32}, {0xd3u, Opcode::VCmpxLeU32}, - {0xd4u, Opcode::VCmpxGtU32}, {0xd5u, Opcode::VCmpxNeU32}, {0xd6u, Opcode::VCmpxGeU32}, - {0xe5u, Opcode::VCmpNeU64}, {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}, + {0xa2u, Opcode::VCmpEqI64}, {0xd1u, Opcode::VCmpxLtU32}, {0xd2u, Opcode::VCmpxEqU32}, + {0xd3u, Opcode::VCmpxLeU32}, {0xd4u, Opcode::VCmpxGtU32}, {0xd5u, Opcode::VCmpxNeU32}, + {0xd6u, Opcode::VCmpxGeU32}, {0xe5u, Opcode::VCmpNeU64}, {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}, }; constexpr OpcodeMap VOP3_OPS[] = { diff --git a/src/graphics/shader/recompiler/emitter/spirvEmitterAluOps.cpp b/src/graphics/shader/recompiler/emitter/spirvEmitterAluOps.cpp index 3cc1f5a27..33d7a83d1 100644 --- a/src/graphics/shader/recompiler/emitter/spirvEmitterAluOps.cpp +++ b/src/graphics/shader/recompiler/emitter/spirvEmitterAluOps.cpp @@ -1486,17 +1486,19 @@ void EmitBitCompareB32(EmitterState& state, const IR::Instruction& inst, bool bi EmitStoreU32(state, inst.dst, ret); } -void EmitCompareNeU64(EmitterState& state, const IR::Instruction& inst) { - const auto lhs_low = EmitSequentialValueLoad(state, inst.src[0], 0); - const auto lhs_high = EmitSequentialValueLoad(state, inst.src[0], 1); - const auto rhs_low = EmitSequentialValueLoad(state, inst.src[1], 0); - const auto rhs_high = EmitSequentialValueLoad(state, inst.src[1], 1); - const auto ne_low = state.builder.AllocateId(); - const auto ne_high = state.builder.AllocateId(); - const auto cond = state.builder.AllocateId(); - state.builder.AddFunction({OpINotEqual, state.bool_type, ne_low, lhs_low, rhs_low}); - state.builder.AddFunction({OpINotEqual, state.bool_type, ne_high, lhs_high, rhs_high}); - state.builder.AddFunction({OpLogicalOr, state.bool_type, cond, ne_low, ne_high}); +void EmitCompareU64(EmitterState& state, const IR::Instruction& inst, bool equal) { + const auto lhs_low = EmitSequentialValueLoad(state, inst.src[0], 0); + const auto lhs_high = EmitSequentialValueLoad(state, inst.src[0], 1); + const auto rhs_low = EmitSequentialValueLoad(state, inst.src[1], 0); + const auto rhs_high = EmitSequentialValueLoad(state, inst.src[1], 1); + const auto low = state.builder.AllocateId(); + const auto high = state.builder.AllocateId(); + const auto cond = state.builder.AllocateId(); + const auto compare_op = equal ? OpIEqual : OpINotEqual; + state.builder.AddFunction({compare_op, state.bool_type, low, lhs_low, rhs_low}); + state.builder.AddFunction({compare_op, state.bool_type, high, lhs_high, rhs_high}); + state.builder.AddFunction( + {equal ? OpLogicalAnd : OpLogicalOr, state.bool_type, cond, low, high}); EmitCompareResult(state, inst.dst, cond); } diff --git a/src/graphics/shader/recompiler/emitter/spirvEmitterAnalysis.cpp b/src/graphics/shader/recompiler/emitter/spirvEmitterAnalysis.cpp index 7a57aab26..451524250 100644 --- a/src/graphics/shader/recompiler/emitter/spirvEmitterAnalysis.cpp +++ b/src/graphics/shader/recompiler/emitter/spirvEmitterAnalysis.cpp @@ -189,7 +189,7 @@ void CollectRegisters(const IR::Program& program, std::vector& if (inst.op == IR::Opcode::BitCountU64 || inst.op == IR::Opcode::FindMsbFromHighU64) { CollectSequentialRegisters(registers, inst.src[0], 2); } - if (inst.op == IR::Opcode::CompareNeU64) { + if (inst.op == IR::Opcode::CompareEqU64 || inst.op == IR::Opcode::CompareNeU64) { CollectSequentialRegisters(registers, inst.src[0], 2); CollectSequentialRegisters(registers, inst.src[1], 2); } @@ -394,6 +394,7 @@ bool IsCompareOpcode(IR::Opcode op) { case IR::Opcode::CompareGeU32: case IR::Opcode::CompareLtU32: case IR::Opcode::CompareLeU32: + case IR::Opcode::CompareEqU64: case IR::Opcode::CompareNeU64: case IR::Opcode::CompareMaskEqU32: case IR::Opcode::CompareMaskNeU32: diff --git a/src/graphics/shader/recompiler/emitter/spirvEmitterControlFlow.cpp b/src/graphics/shader/recompiler/emitter/spirvEmitterControlFlow.cpp index 9d3cabdf2..1bb66f012 100644 --- a/src/graphics/shader/recompiler/emitter/spirvEmitterControlFlow.cpp +++ b/src/graphics/shader/recompiler/emitter/spirvEmitterControlFlow.cpp @@ -516,7 +516,8 @@ void EmitInstruction(EmitterState& state, const IR::Instruction& inst) { case IR::Opcode::CompareGeU32: EmitCompareU32(state, inst, OpUGreaterThanEqual); break; case IR::Opcode::CompareLtU32: EmitCompareU32(state, inst, OpULessThan); break; case IR::Opcode::CompareLeU32: EmitCompareU32(state, inst, OpULessThanEqual); break; - case IR::Opcode::CompareNeU64: EmitCompareNeU64(state, inst); break; + case IR::Opcode::CompareEqU64: EmitCompareU64(state, inst, true); break; + case IR::Opcode::CompareNeU64: EmitCompareU64(state, inst, false); break; case IR::Opcode::CompareMaskEqU32: EmitCompareMaskU32(state, inst, OpIEqual); break; case IR::Opcode::CompareMaskNeU32: EmitCompareMaskU32(state, inst, OpINotEqual); break; case IR::Opcode::CompareMaskGtU32: EmitCompareMaskU32(state, inst, OpUGreaterThan); break; diff --git a/src/graphics/shader/recompiler/emitter/spirvEmitterInternal.h b/src/graphics/shader/recompiler/emitter/spirvEmitterInternal.h index 5233ddaa5..702d37dc4 100644 --- a/src/graphics/shader/recompiler/emitter/spirvEmitterInternal.h +++ b/src/graphics/shader/recompiler/emitter/spirvEmitterInternal.h @@ -1345,7 +1345,7 @@ void EmitCompareI16(EmitterState& state, const IR::Instruction& inst, uint32_t o void EmitBitCompareB32(EmitterState& state, const IR::Instruction& inst, bool bit_set); -void EmitCompareNeU64(EmitterState& state, const IR::Instruction& inst); +void EmitCompareU64(EmitterState& state, const IR::Instruction& inst, bool equal); void EmitCompareConstant(EmitterState& state, const IR::Instruction& inst, bool value); diff --git a/src/graphics/shader/recompiler/ir/ShaderIR.h b/src/graphics/shader/recompiler/ir/ShaderIR.h index 9f94601ca..89ed757f2 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIR.h +++ b/src/graphics/shader/recompiler/ir/ShaderIR.h @@ -134,6 +134,7 @@ enum class Opcode { CompareGeU32, CompareLtU32, CompareLeU32, + CompareEqU64, CompareNeU64, CompareMaskEqU32, CompareMaskNeU32, diff --git a/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp b/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp index 22785f5f2..303e7f9e9 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp +++ b/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp @@ -279,6 +279,7 @@ std::string InstructionToString(const Instruction& inst) { case Opcode::CompareGeU32: text += "CompareGeU32"; break; case Opcode::CompareLtU32: text += "CompareLtU32"; break; case Opcode::CompareLeU32: text += "CompareLeU32"; break; + case Opcode::CompareEqU64: text += "CompareEqU64"; break; case Opcode::CompareNeU64: text += "CompareNeU64"; break; case Opcode::CompareMaskEqU32: text += "CompareMaskEqU32"; break; case Opcode::CompareMaskNeU32: text += "CompareMaskNeU32"; break; diff --git a/src/graphics/shader/recompiler/ir/ShaderIROpcodes.cpp b/src/graphics/shader/recompiler/ir/ShaderIROpcodes.cpp index e137f2709..878e44c4d 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIROpcodes.cpp +++ b/src/graphics/shader/recompiler/ir/ShaderIROpcodes.cpp @@ -325,6 +325,7 @@ constexpr LowerMap LOWER_OPS[] = { {Decoder::Opcode::VCmpNeU32, Opcode::CompareNeU32}, {Decoder::Opcode::VCmpGeU32, Opcode::CompareGeU32}, {Decoder::Opcode::VCmpTU32, Opcode::CompareTrue}, + {Decoder::Opcode::VCmpEqI64, Opcode::CompareEqU64}, {Decoder::Opcode::VCmpNeU64, Opcode::CompareNeU64}, {Decoder::Opcode::VCmpxLtU32, Opcode::CompareMaskLtU32}, {Decoder::Opcode::VCmpxEqU32, Opcode::CompareMaskEqU32}, diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 1b5dc6a14..3317ddee5 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -11593,6 +11593,33 @@ TestCase VectorVop3CompareNeU64OnGpu() { O::SEndpgm}}; } +TestCase VectorVop3CompareEqI64OnGpu() { + using O = ShaderOpcode; + + std::vector code; + code.push_back(EncodeVop1(0x01, 1, InlineU32(1))); + code.push_back(EncodeSop1(0x04, 4, 126)); // s_mov_b64 s[4:5], exec + + code.push_back(0xd4a2006au); + code.push_back(0x0000087eu); // v_cmp_eq_i64 vcc, exec, s[4:5] + code.push_back(EncodeVop2(0x01, 2, InlineU32(0), 1)); + AppendStoreVgpr(&code, 2, 0); + + AppendSMovLiteral(&code, 4, 0); + code.push_back(0xd4a2006au); + code.push_back(0x0000087eu); // low dword mismatch + code.push_back(EncodeVop2(0x01, 3, InlineU32(0), 1)); + AppendStoreVgpr(&code, 3, 1); + AppendEnd(&code); + + return {"VectorVop3CompareEqI64OnGpu", + code, + {}, + {1, 0}, + {O::VMovB32, O::SMovB64, O::VCmpEqI64, O::VCndmaskB32, O::SMovB32, + O::BufferStoreDword, O::SEndpgm}}; +} + TestCase VectorCompareClassF32() { using O = ShaderOpcode; @@ -15060,6 +15087,7 @@ std::vector MakeCases() { AddCase(VectorSpecialF32FlushesDenormalInputs); AddCase(VectorSinCosMaxFiniteSpecialCases); AddCase(VectorCompareOps); + AddCase(VectorVop3CompareEqI64OnGpu); AddCase(VectorVop3CompareNeU64OnGpu); AddCase(VectorCompareClassF32); AddCase(VectorCompareF16Ops);