shader: implement V_CMP_EQ_I64

This commit is contained in:
nmzik
2026-08-04 21:51:17 +02:00
parent b9aa0dc3b3
commit 2b6fd699e7
11 changed files with 59 additions and 21 deletions
@@ -766,6 +766,7 @@ std::string OpcodeToString(Opcode opcode) {
case Opcode::VCmpNeU32: return "v_cmp_ne_u32"; case Opcode::VCmpNeU32: return "v_cmp_ne_u32";
case Opcode::VCmpGeU32: return "v_cmp_ge_u32"; case Opcode::VCmpGeU32: return "v_cmp_ge_u32";
case Opcode::VCmpTU32: return "v_cmp_t_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::VCmpNeU64: return "v_cmp_ne_u64";
case Opcode::VCmpxLtU32: return "v_cmpx_lt_u32"; case Opcode::VCmpxLtU32: return "v_cmpx_lt_u32";
case Opcode::VCmpxEqU32: return "v_cmpx_eq_u32"; case Opcode::VCmpxEqU32: return "v_cmpx_eq_u32";
@@ -374,6 +374,7 @@ enum class Opcode {
VCmpNeU32, VCmpNeU32,
VCmpGeU32, VCmpGeU32,
VCmpTU32, VCmpTU32,
VCmpEqI64,
VCmpNeU64, VCmpNeU64,
VCmpxLtU32, VCmpxLtU32,
VCmpxEqU32, VCmpxEqU32,
@@ -157,13 +157,14 @@ constexpr OpcodeMap VOPC_OPS[] = {
{0xaeu, Opcode::VCmpGeU16}, {0xc0u, Opcode::VCmpFU32}, {0xc1u, Opcode::VCmpLtU32}, {0xaeu, Opcode::VCmpGeU16}, {0xc0u, Opcode::VCmpFU32}, {0xc1u, Opcode::VCmpLtU32},
{0xc2u, Opcode::VCmpEqU32}, {0xc3u, Opcode::VCmpLeU32}, {0xc4u, Opcode::VCmpGtU32}, {0xc2u, Opcode::VCmpEqU32}, {0xc3u, Opcode::VCmpLeU32}, {0xc4u, Opcode::VCmpGtU32},
{0xc5u, Opcode::VCmpNeU32}, {0xc6u, Opcode::VCmpGeU32}, {0xc7u, Opcode::VCmpTU32}, {0xc5u, Opcode::VCmpNeU32}, {0xc6u, Opcode::VCmpGeU32}, {0xc7u, Opcode::VCmpTU32},
{0xd1u, Opcode::VCmpxLtU32}, {0xd2u, Opcode::VCmpxEqU32}, {0xd3u, Opcode::VCmpxLeU32}, {0xa2u, Opcode::VCmpEqI64}, {0xd1u, Opcode::VCmpxLtU32}, {0xd2u, Opcode::VCmpxEqU32},
{0xd4u, Opcode::VCmpxGtU32}, {0xd5u, Opcode::VCmpxNeU32}, {0xd6u, Opcode::VCmpxGeU32}, {0xd3u, Opcode::VCmpxLeU32}, {0xd4u, Opcode::VCmpxGtU32}, {0xd5u, Opcode::VCmpxNeU32},
{0xe5u, Opcode::VCmpNeU64}, {0xc9u, Opcode::VCmpLtF16}, {0xcau, Opcode::VCmpEqF16}, {0xd6u, Opcode::VCmpxGeU32}, {0xe5u, Opcode::VCmpNeU64}, {0xc9u, Opcode::VCmpLtF16},
{0xcbu, Opcode::VCmpLeF16}, {0xccu, Opcode::VCmpGtF16}, {0xcdu, Opcode::VCmpLgF16}, {0xcau, Opcode::VCmpEqF16}, {0xcbu, Opcode::VCmpLeF16}, {0xccu, Opcode::VCmpGtF16},
{0xceu, Opcode::VCmpGeF16}, {0xedu, Opcode::VCmpNeqF16}, {0xd9u, Opcode::VCmpxLtF16}, {0xcdu, Opcode::VCmpLgF16}, {0xceu, Opcode::VCmpGeF16}, {0xedu, Opcode::VCmpNeqF16},
{0xdau, Opcode::VCmpxEqF16}, {0xdbu, Opcode::VCmpxLeF16}, {0xdcu, Opcode::VCmpxGtF16}, {0xd9u, Opcode::VCmpxLtF16}, {0xdau, Opcode::VCmpxEqF16}, {0xdbu, Opcode::VCmpxLeF16},
{0xdeu, Opcode::VCmpxGeF16}, {0xfdu, Opcode::VCmpxNeqF16}, {0xfeu, Opcode::VCmpxNltF16}, {0xdcu, Opcode::VCmpxGtF16}, {0xdeu, Opcode::VCmpxGeF16}, {0xfdu, Opcode::VCmpxNeqF16},
{0xfeu, Opcode::VCmpxNltF16},
}; };
constexpr OpcodeMap VOP3_OPS[] = { constexpr OpcodeMap VOP3_OPS[] = {
@@ -1486,17 +1486,19 @@ void EmitBitCompareB32(EmitterState& state, const IR::Instruction& inst, bool bi
EmitStoreU32(state, inst.dst, ret); EmitStoreU32(state, inst.dst, ret);
} }
void EmitCompareNeU64(EmitterState& state, const IR::Instruction& inst) { void EmitCompareU64(EmitterState& state, const IR::Instruction& inst, bool equal) {
const auto lhs_low = EmitSequentialValueLoad(state, inst.src[0], 0); const auto lhs_low = EmitSequentialValueLoad(state, inst.src[0], 0);
const auto lhs_high = EmitSequentialValueLoad(state, inst.src[0], 1); const auto lhs_high = EmitSequentialValueLoad(state, inst.src[0], 1);
const auto rhs_low = EmitSequentialValueLoad(state, inst.src[1], 0); const auto rhs_low = EmitSequentialValueLoad(state, inst.src[1], 0);
const auto rhs_high = EmitSequentialValueLoad(state, inst.src[1], 1); const auto rhs_high = EmitSequentialValueLoad(state, inst.src[1], 1);
const auto ne_low = state.builder.AllocateId(); const auto low = state.builder.AllocateId();
const auto ne_high = state.builder.AllocateId(); const auto high = state.builder.AllocateId();
const auto cond = state.builder.AllocateId(); const auto cond = state.builder.AllocateId();
state.builder.AddFunction({OpINotEqual, state.bool_type, ne_low, lhs_low, rhs_low}); const auto compare_op = equal ? OpIEqual : OpINotEqual;
state.builder.AddFunction({OpINotEqual, state.bool_type, ne_high, lhs_high, rhs_high}); state.builder.AddFunction({compare_op, state.bool_type, low, lhs_low, rhs_low});
state.builder.AddFunction({OpLogicalOr, state.bool_type, cond, ne_low, ne_high}); 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); EmitCompareResult(state, inst.dst, cond);
} }
@@ -189,7 +189,7 @@ void CollectRegisters(const IR::Program& program, std::vector<RegisterBinding>&
if (inst.op == IR::Opcode::BitCountU64 || inst.op == IR::Opcode::FindMsbFromHighU64) { if (inst.op == IR::Opcode::BitCountU64 || inst.op == IR::Opcode::FindMsbFromHighU64) {
CollectSequentialRegisters(registers, inst.src[0], 2); 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[0], 2);
CollectSequentialRegisters(registers, inst.src[1], 2); CollectSequentialRegisters(registers, inst.src[1], 2);
} }
@@ -394,6 +394,7 @@ bool IsCompareOpcode(IR::Opcode op) {
case IR::Opcode::CompareGeU32: case IR::Opcode::CompareGeU32:
case IR::Opcode::CompareLtU32: case IR::Opcode::CompareLtU32:
case IR::Opcode::CompareLeU32: case IR::Opcode::CompareLeU32:
case IR::Opcode::CompareEqU64:
case IR::Opcode::CompareNeU64: case IR::Opcode::CompareNeU64:
case IR::Opcode::CompareMaskEqU32: case IR::Opcode::CompareMaskEqU32:
case IR::Opcode::CompareMaskNeU32: case IR::Opcode::CompareMaskNeU32:
@@ -516,7 +516,8 @@ void EmitInstruction(EmitterState& state, const IR::Instruction& inst) {
case IR::Opcode::CompareGeU32: EmitCompareU32(state, inst, OpUGreaterThanEqual); break; case IR::Opcode::CompareGeU32: EmitCompareU32(state, inst, OpUGreaterThanEqual); break;
case IR::Opcode::CompareLtU32: EmitCompareU32(state, inst, OpULessThan); break; case IR::Opcode::CompareLtU32: EmitCompareU32(state, inst, OpULessThan); break;
case IR::Opcode::CompareLeU32: EmitCompareU32(state, inst, OpULessThanEqual); 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::CompareMaskEqU32: EmitCompareMaskU32(state, inst, OpIEqual); break;
case IR::Opcode::CompareMaskNeU32: EmitCompareMaskU32(state, inst, OpINotEqual); break; case IR::Opcode::CompareMaskNeU32: EmitCompareMaskU32(state, inst, OpINotEqual); break;
case IR::Opcode::CompareMaskGtU32: EmitCompareMaskU32(state, inst, OpUGreaterThan); break; case IR::Opcode::CompareMaskGtU32: EmitCompareMaskU32(state, inst, OpUGreaterThan); break;
@@ -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 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); void EmitCompareConstant(EmitterState& state, const IR::Instruction& inst, bool value);
@@ -134,6 +134,7 @@ enum class Opcode {
CompareGeU32, CompareGeU32,
CompareLtU32, CompareLtU32,
CompareLeU32, CompareLeU32,
CompareEqU64,
CompareNeU64, CompareNeU64,
CompareMaskEqU32, CompareMaskEqU32,
CompareMaskNeU32, CompareMaskNeU32,
@@ -279,6 +279,7 @@ std::string InstructionToString(const Instruction& inst) {
case Opcode::CompareGeU32: text += "CompareGeU32"; break; case Opcode::CompareGeU32: text += "CompareGeU32"; break;
case Opcode::CompareLtU32: text += "CompareLtU32"; break; case Opcode::CompareLtU32: text += "CompareLtU32"; break;
case Opcode::CompareLeU32: text += "CompareLeU32"; break; case Opcode::CompareLeU32: text += "CompareLeU32"; break;
case Opcode::CompareEqU64: text += "CompareEqU64"; break;
case Opcode::CompareNeU64: text += "CompareNeU64"; break; case Opcode::CompareNeU64: text += "CompareNeU64"; break;
case Opcode::CompareMaskEqU32: text += "CompareMaskEqU32"; break; case Opcode::CompareMaskEqU32: text += "CompareMaskEqU32"; break;
case Opcode::CompareMaskNeU32: text += "CompareMaskNeU32"; break; case Opcode::CompareMaskNeU32: text += "CompareMaskNeU32"; break;
@@ -325,6 +325,7 @@ constexpr LowerMap LOWER_OPS[] = {
{Decoder::Opcode::VCmpNeU32, Opcode::CompareNeU32}, {Decoder::Opcode::VCmpNeU32, Opcode::CompareNeU32},
{Decoder::Opcode::VCmpGeU32, Opcode::CompareGeU32}, {Decoder::Opcode::VCmpGeU32, Opcode::CompareGeU32},
{Decoder::Opcode::VCmpTU32, Opcode::CompareTrue}, {Decoder::Opcode::VCmpTU32, Opcode::CompareTrue},
{Decoder::Opcode::VCmpEqI64, Opcode::CompareEqU64},
{Decoder::Opcode::VCmpNeU64, Opcode::CompareNeU64}, {Decoder::Opcode::VCmpNeU64, Opcode::CompareNeU64},
{Decoder::Opcode::VCmpxLtU32, Opcode::CompareMaskLtU32}, {Decoder::Opcode::VCmpxLtU32, Opcode::CompareMaskLtU32},
{Decoder::Opcode::VCmpxEqU32, Opcode::CompareMaskEqU32}, {Decoder::Opcode::VCmpxEqU32, Opcode::CompareMaskEqU32},
+28
View File
@@ -11593,6 +11593,33 @@ TestCase VectorVop3CompareNeU64OnGpu() {
O::SEndpgm}}; O::SEndpgm}};
} }
TestCase VectorVop3CompareEqI64OnGpu() {
using O = ShaderOpcode;
std::vector<u32> 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() { TestCase VectorCompareClassF32() {
using O = ShaderOpcode; using O = ShaderOpcode;
@@ -15060,6 +15087,7 @@ std::vector<TestCase> MakeCases() {
AddCase(VectorSpecialF32FlushesDenormalInputs); AddCase(VectorSpecialF32FlushesDenormalInputs);
AddCase(VectorSinCosMaxFiniteSpecialCases); AddCase(VectorSinCosMaxFiniteSpecialCases);
AddCase(VectorCompareOps); AddCase(VectorCompareOps);
AddCase(VectorVop3CompareEqI64OnGpu);
AddCase(VectorVop3CompareNeU64OnGpu); AddCase(VectorVop3CompareNeU64OnGpu);
AddCase(VectorCompareClassF32); AddCase(VectorCompareClassF32);
AddCase(VectorCompareF16Ops); AddCase(VectorCompareF16Ops);