shader: support V_CMPX_NE_U16

This commit is contained in:
fxpw
2026-10-05 09:22:31 +04:00
committed by nmzik
parent 2b1b7ed0e4
commit 1d55272467
4 changed files with 56 additions and 17 deletions
@@ -441,6 +441,7 @@ enum class Opcode {
V_CMPX_LT_U16,
V_CMPX_EQ_U16,
V_CMPX_GT_U16,
V_CMPX_NE_U16,
V_CMP_NE_U16,
V_CMP_GE_U16,
V_CMP_F_U32,
@@ -256,7 +256,8 @@ constexpr VopcOpcodeInfo VOPC_OPCODE_LIST[] = {
{0xabu, Opcode::V_CMP_LE_U16}, {0xacu, Opcode::V_CMP_GT_U16},
{0xadu, Opcode::V_CMP_NE_U16}, {0xaeu, Opcode::V_CMP_GE_U16},
{0xb9u, Opcode::V_CMPX_LT_U16, false}, {0xbau, Opcode::V_CMPX_EQ_U16, false},
{0xbcu, Opcode::V_CMPX_GT_U16}, {0xc0u, Opcode::V_CMP_F_U32},
{0xbcu, Opcode::V_CMPX_GT_U16}, {0xbdu, Opcode::V_CMPX_NE_U16, false},
{0xc0u, Opcode::V_CMP_F_U32},
{0xc1u, Opcode::V_CMP_LT_U32}, {0xc2u, Opcode::V_CMP_EQ_U32},
{0xc3u, Opcode::V_CMP_LE_U32}, {0xc4u, Opcode::V_CMP_GT_U32},
{0xc5u, Opcode::V_CMP_NE_U32}, {0xc6u, Opcode::V_CMP_GE_U32},
@@ -1557,6 +1558,7 @@ bool IsVopcCompareExec(Opcode opcode) {
case Opcode::V_CMPX_LT_U16:
case Opcode::V_CMPX_EQ_U16:
case Opcode::V_CMPX_GT_U16:
case Opcode::V_CMPX_NE_U16:
case Opcode::V_CMPX_LT_F16:
case Opcode::V_CMPX_EQ_F16:
case Opcode::V_CMPX_LE_F16:
@@ -143,6 +143,9 @@ void Translator::EmitVector(const Decoder::Instruction& inst) {
case O::V_CMP_NE_U16:
EmitInteger16Compare(inst, IR::ValueOpcode::INotEqual32, false, false);
return;
case O::V_CMPX_NE_U16:
EmitInteger16Compare(inst, IR::ValueOpcode::INotEqual32, false, true);
return;
case O::V_CMP_NE_I16:
EmitInteger16Compare(inst, IR::ValueOpcode::INotEqual32, true, false);
return;
+49 -16
View File
@@ -26247,16 +26247,16 @@ TestCase VectorVopcCmpxLtI16WaveMasks(u32 wave_size) {
return test;
}
TestCase VectorVopcCmpxEqU16SdwaCompactVop3ExecMask() {
TestCase VectorVopcCmpxU16SdwaCompactVop3ExecMask(bool not_equal) {
using O = ShaderOpcode;
struct CompareCase {
u32 lhs;
u32 rhs;
u32 incoming_exec;
u32 expected_exec;
u32 encoding = 0; // SDWA, compact, VOP3, sign-extended words/bytes.
u32 encoding = 0; // SDWA, compact, VOP3, sign-extended words/bytes, literal.
};
const std::array<CompareCase, 16> cases{{
const std::array<CompareCase, 21> cases{{
{0x12340000u, 0x56780000u, 1, 1}, // Equal low half; ignore high half.
{0xffff0001u, 0xabcd0001u, 1, 1},
{0x00000000u, 0x12340000u, 1, 1},
@@ -26273,10 +26273,17 @@ TestCase VectorVopcCmpxEqU16SdwaCompactVop3ExecMask() {
{0x123456ffu, 0x0000ffffu, 1, 1, 4},
{0x0000ff80u, 0x12348000u, 1, 1, 5}, // SEXT BYTE_1 on src1.
{0x1234ffffu, 0x5678ffffu, 1, 1, 6}, // SEXT WORD_0 versus DWORD low half.
{0xabcd0001u, 1u, 1, 1, 7}, // Literal source, equal low halves.
{0xabcd0000u, 1u, 1, 0, 7},
{0x00000000u, 1u, 0, 0}, // Neither EQ nor NE may reactivate an inactive lane.
{0x00010000u, 0xffff0001u, 1, 1, 8}, // Select the high word of src0.
{0xabcd0002u, 0x0002ffffu, 1, 1, 9}, // Select the high word of src1.
}};
const u32 opcode = not_equal ? 0xbdu : 0xbau;
constexpr u32 vcc_hi = 0x89abcdefu;
TestCase test;
test.name = "VectorVopcCmpxEqU16SdwaCompactVop3ExecMask";
test.name = not_equal ? "VectorVopcCmpxNeU16SdwaCompactVop3ExecMask"
: "VectorVopcCmpxEqU16SdwaCompactVop3ExecMask";
for (const auto &entry : cases) {
test.initial.push_back(entry.lhs);
}
@@ -26291,26 +26298,36 @@ TestCase VectorVopcCmpxEqU16SdwaCompactVop3ExecMask() {
AppendSMovLiteral(&code, 107, vcc_hi);
code.push_back(EncodeSMovB32(126, InlineU32(entry.incoming_exec)));
switch (entry.encoding) {
case 1: code.push_back(0x7d740300u); break; // compact v0, v1
case 2: code.insert(code.end(), {0xd4ba007eu, 0x00020300u}); break;
case 1: code.push_back(EncodeVopc(opcode, Vgpr(0), 1u)); break;
case 2: AppendVop3(&code, opcode, 126u, Vgpr(0), Vgpr(1)); break;
case 3:
code.push_back(EncodeVopc(0xba, 249u, 1u));
code.push_back(EncodeVopc(opcode, 249u, 1u));
code.push_back(EncodeVopcSdwa(0u, 0u, 0u, 6u, 6u, 1u, 1u));
break;
case 4:
code.push_back(EncodeVopc(0xba, 249u, 1u));
code.push_back(EncodeVopc(opcode, 249u, 1u));
code.push_back(EncodeVopcSdwa(0u, 0u, 0u, 0u, 6u, 1u, 0u));
break;
case 5:
code.push_back(EncodeVopc(0xba, 249u, 1u));
code.push_back(EncodeVopc(opcode, 249u, 1u));
code.push_back(EncodeVopcSdwa(0u, 0u, 0u, 6u, 1u, 0u, 1u));
break;
case 6:
code.push_back(EncodeVopc(0xba, 249u, 1u));
code.push_back(EncodeVopc(opcode, 249u, 1u));
code.push_back(EncodeVopcSdwa(0u, 0u, 0u, 4u, 6u, 1u, 0u));
break;
case 7:
code.push_back(EncodeVopc(opcode, 255u, 0u));
code.push_back(entry.rhs);
break;
case 8:
case 9:
code.push_back(EncodeVopc(opcode, 249u, 1u));
code.push_back(EncodeVopcSdwa(0u, 0u, 0u, entry.encoding == 8u ? 5u : 6u,
entry.encoding == 9u ? 5u : 6u));
break;
default:
code.push_back(EncodeVopc(0xba, 249u, 1u));
code.push_back(EncodeVopc(opcode, 249u, 1u));
code.push_back(EncodeVopcSdwa(0u));
break;
}
@@ -26320,17 +26337,27 @@ TestCase VectorVopcCmpxEqU16SdwaCompactVop3ExecMask() {
const u32 out = static_cast<u32>(cases.size()) + i * 4u;
AppendStoreSgprPair(&code, 20, out);
AppendStoreSgprPair(&code, 106, out + 2u); // CMPX must not overwrite either VCC half.
test.expected.insert(test.expected.end(),
{entry.expected_exec, 0u, entry.rhs, vcc_hi});
const u32 expected_exec = not_equal ? entry.incoming_exec & (entry.expected_exec ^ 1u)
: entry.expected_exec;
test.expected.insert(test.expected.end(), {expected_exec, 0u, entry.rhs, vcc_hi});
}
AppendEnd(&code);
test.opcodes = {O::V_MOV_B32, O::S_MOV_B32, O::BUFFER_LOAD_DWORD,
O::V_CMPX_EQ_U16, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.decoded_counts = {{"V_CMPX_EQ_U16", cases.size()}};
test.required_spirv = {"OpIEqual"};
not_equal ? O::V_CMPX_NE_U16 : O::V_CMPX_EQ_U16,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.decoded_counts = {{not_equal ? "V_CMPX_NE_U16" : "V_CMPX_EQ_U16", cases.size()}};
test.required_spirv = {not_equal ? "OpINotEqual" : "OpIEqual"};
return test;
}
TestCase VectorVopcCmpxEqU16SdwaCompactVop3ExecMask() {
return VectorVopcCmpxU16SdwaCompactVop3ExecMask(false);
}
TestCase VectorVopcCmpxNeU16SdwaCompactVop3ExecMask() {
return VectorVopcCmpxU16SdwaCompactVop3ExecMask(true);
}
TestCase VectorVopcCmpNgtF16CapturedSdwaAndEdges() {
using O = ShaderOpcode;
enum Encoding { Captured, Compact, Vop3NegAbs, HighWord, ScalarDst, SdwaNegAbs };
@@ -34693,6 +34720,7 @@ std::vector<TestCase> MakeCases() {
cases.push_back(VectorVopcCmpxLtI16WaveMasks(wave_size));
}
AddCase(VectorVopcCmpxEqU16SdwaCompactVop3ExecMask);
AddCase(VectorVopcCmpxNeU16SdwaCompactVop3ExecMask);
AddCase(VectorVopcCmpNgtF16CapturedSdwaAndEdges);
AddCase(VectorVopcCmpNltF16CapturedSdwaAndEdges);
AddCase(VectorVopcCmpxNgtF16CapturedSdwaExecMask);
@@ -39995,6 +40023,11 @@ int main(int argc, char **argv) {
RunCase(&vulkan, VectorVopcCmpxEqU16SdwaCompactVop3ExecMask());
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--cmpx-ne-u16-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, VectorVopcCmpxNeU16SdwaCompactVop3ExecMask());
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--cmpx-lt-i16-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, VectorVopcCmpxLtI16CapturedSdwaExecMask());