|
|
|
@@ -18672,6 +18672,7 @@ CoverageClass ClassifyOpcode(ShaderOpcode opcode,
|
|
|
|
|
case Opcode::FLAT_LOAD_SBYTE:
|
|
|
|
|
case Opcode::FLAT_LOAD_USHORT:
|
|
|
|
|
case Opcode::FLAT_LOAD_SSHORT:
|
|
|
|
|
case Opcode::FLAT_LOAD_SHORT_D16:
|
|
|
|
|
case Opcode::FLAT_LOAD_DWORD:
|
|
|
|
|
case Opcode::FLAT_LOAD_DWORDX2:
|
|
|
|
|
case Opcode::FLAT_LOAD_DWORDX3:
|
|
|
|
@@ -26246,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},
|
|
|
|
@@ -26272,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);
|
|
|
|
|
}
|
|
|
|
@@ -26290,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;
|
|
|
|
|
}
|
|
|
|
@@ -26319,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 };
|
|
|
|
@@ -29171,6 +29199,89 @@ TestCase FlatSubdwordLoadsApplyByteOffset() {
|
|
|
|
|
return test;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestCase GlobalLoadShortD16Captured(u32 wave_size) {
|
|
|
|
|
using O = ShaderOpcode;
|
|
|
|
|
constexpr uint64_t GuestBase = 0x0000000110000000ull;
|
|
|
|
|
constexpr u32 Marker = 0xa5a50000u;
|
|
|
|
|
constexpr uint64_t ScalarBase = GuestBase - Marker - 0x70u;
|
|
|
|
|
constexpr uint64_t ExecMask = 0xaaaaaaaa55555555ull;
|
|
|
|
|
constexpr u32 Values[] = {0u, 0x7fffu, 0x8000u, 0xffffu};
|
|
|
|
|
TestCase test;
|
|
|
|
|
test.name = wave_size == 32u ? "GlobalLoadShortD16CapturedWave32"
|
|
|
|
|
: "GlobalLoadShortD16CapturedWave64";
|
|
|
|
|
test.initial.resize(2u * wave_size + wave_size / 2u);
|
|
|
|
|
test.expected.resize(2u * wave_size);
|
|
|
|
|
for (u32 lane = 0; lane < wave_size; ++lane) {
|
|
|
|
|
const u32 value = Values[lane % std::size(Values)];
|
|
|
|
|
test.initial[2u * wave_size + lane / 2u] |= value << (16u * (lane % 2u));
|
|
|
|
|
test.expected[lane] = Marker | value;
|
|
|
|
|
test.expected[wave_size + lane] = Marker |
|
|
|
|
|
((ExecMask & (uint64_t{1} << lane)) != 0u ? value : lane * 2u);
|
|
|
|
|
}
|
|
|
|
|
auto &code = test.code;
|
|
|
|
|
AppendSMovLiteral(&code, 2, static_cast<u32>(ScalarBase));
|
|
|
|
|
AppendSMovLiteral(&code, 3, static_cast<u32>(ScalarBase >> 32u));
|
|
|
|
|
code.push_back(EncodeVop2(0x1a, 6, InlineU32(1), 0));
|
|
|
|
|
AppendVMovLiteral(&code, 5, Marker);
|
|
|
|
|
code.push_back(EncodeVop2(0x25, 6, Vgpr(5), 6));
|
|
|
|
|
for (bool masked : {false, true}) {
|
|
|
|
|
code.push_back(EncodeVop1(0x01, 5, Vgpr(6)));
|
|
|
|
|
if (masked) {
|
|
|
|
|
code.push_back(EncodeSop1(0x04, 8, 126));
|
|
|
|
|
AppendSMovLiteral(&code, 126, static_cast<u32>(ExecMask));
|
|
|
|
|
AppendSMovLiteral(&code, 127, static_cast<u32>(ExecMask >> 32u));
|
|
|
|
|
}
|
|
|
|
|
// Captured GLOBAL_LOAD_SHORT_D16: v5 supplies the byte offset and destination.
|
|
|
|
|
code.insert(code.end(), {0xdc908070u, 0x05020005u});
|
|
|
|
|
if (masked) code.push_back(EncodeSop1(0x04, 126, 8));
|
|
|
|
|
AppendStoreVgprAtLaneDwordOffset(&code, 5, 0, masked ? wave_size : 0u);
|
|
|
|
|
}
|
|
|
|
|
AppendEnd(&code);
|
|
|
|
|
test.bda_mappings = {{GuestBase, 8u * wave_size}};
|
|
|
|
|
test.compute_info.threads_num[0] = wave_size;
|
|
|
|
|
test.compute_info.threads_num[1] = 1;
|
|
|
|
|
test.compute_info.threads_num[2] = 1;
|
|
|
|
|
test.compute_info.thread_ids_num = 1;
|
|
|
|
|
test.compute_info.wave_size = wave_size;
|
|
|
|
|
test.has_compute_info = true;
|
|
|
|
|
test.opcodes = {O::S_MOV_B32, O::S_MOV_B64, O::V_MOV_B32, O::V_LSHLREV_B32,
|
|
|
|
|
O::V_ADD_NC_U32, O::FLAT_LOAD_SHORT_D16,
|
|
|
|
|
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
|
|
|
|
test.decoded_counts = {{"FLAT_LOAD_SHORT_D16", 2}};
|
|
|
|
|
return test;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestCase FlatLoadShortD16AddressSegments() {
|
|
|
|
|
using O = ShaderOpcode;
|
|
|
|
|
constexpr uint64_t GuestBase = 0x0000000110000000ull;
|
|
|
|
|
std::vector<u32> code;
|
|
|
|
|
AppendVMovLiteral(&code, 20, static_cast<u32>(GuestBase) + 2u);
|
|
|
|
|
AppendVMovLiteral(&code, 21, static_cast<u32>(GuestBase >> 32u));
|
|
|
|
|
for (u32 segment : {0u, 2u}) {
|
|
|
|
|
AppendVMovLiteral(&code, 3, 0x12345678u);
|
|
|
|
|
code.push_back(EncodeFlat0(0x24, segment, segment == 0u ? 0u : 0xffeu));
|
|
|
|
|
code.push_back(EncodeFlat1(3, 0x7d, 0, 20));
|
|
|
|
|
AppendStoreVgpr(&code, 3, segment == 0u ? 0u : 1u);
|
|
|
|
|
}
|
|
|
|
|
AppendVMovU32(&code, 20, 0u);
|
|
|
|
|
AppendVMovLiteral(&code, 3, 0xbeef5678u);
|
|
|
|
|
code.push_back(EncodeFlat0(0x1c, 1, 0));
|
|
|
|
|
code.push_back(EncodeFlat1(0, 0x7d, 3, 20));
|
|
|
|
|
AppendVMovLiteral(&code, 3, 0x98761234u);
|
|
|
|
|
code.push_back(EncodeFlat0(0x24, 1, 2));
|
|
|
|
|
code.push_back(EncodeFlat1(3, 0x7d, 0, 20));
|
|
|
|
|
AppendStoreVgpr(&code, 3, 2);
|
|
|
|
|
AppendEnd(&code);
|
|
|
|
|
TestCase test{"FlatLoadShortD16AddressSegments", code,
|
|
|
|
|
{0, 0, 0, 0, 0x80017fffu},
|
|
|
|
|
{0x12348001u, 0x12347fffu, 0x9876beefu},
|
|
|
|
|
{O::V_MOV_B32, O::FLAT_LOAD_SHORT_D16, O::FLAT_STORE_DWORD,
|
|
|
|
|
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
|
|
|
|
test.bda_mappings = {{GuestBase, 16}};
|
|
|
|
|
test.compute_info.scratch_size_dwords = 1;
|
|
|
|
|
return test;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestCase BranchVccnzUsesCarryProducedWaveMask() {
|
|
|
|
|
using O = ShaderOpcode;
|
|
|
|
|
|
|
|
|
@@ -34609,6 +34720,7 @@ std::vector<TestCase> MakeCases() {
|
|
|
|
|
cases.push_back(VectorVopcCmpxLtI16WaveMasks(wave_size));
|
|
|
|
|
}
|
|
|
|
|
AddCase(VectorVopcCmpxEqU16SdwaCompactVop3ExecMask);
|
|
|
|
|
AddCase(VectorVopcCmpxNeU16SdwaCompactVop3ExecMask);
|
|
|
|
|
AddCase(VectorVopcCmpNgtF16CapturedSdwaAndEdges);
|
|
|
|
|
AddCase(VectorVopcCmpNltF16CapturedSdwaAndEdges);
|
|
|
|
|
AddCase(VectorVopcCmpxNgtF16CapturedSdwaExecMask);
|
|
|
|
@@ -34720,6 +34832,9 @@ std::vector<TestCase> MakeCases() {
|
|
|
|
|
AddCase(TBufferStoreVariants);
|
|
|
|
|
AddCase(FlatLoadVariants);
|
|
|
|
|
AddCase(FlatSubdwordLoadsApplyByteOffset);
|
|
|
|
|
cases.push_back(GlobalLoadShortD16Captured(32));
|
|
|
|
|
cases.push_back(GlobalLoadShortD16Captured(64));
|
|
|
|
|
AddCase(FlatLoadShortD16AddressSegments);
|
|
|
|
|
AddCase(FlatVirtualAddressRebasesGuestAllocation);
|
|
|
|
|
AddCase(GlobalSignedImmediateRebasesBeforeSaddr);
|
|
|
|
|
AddCase(FlatSegmentIgnoresSaddrAndMasksOffsetMsb);
|
|
|
|
@@ -39908,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());
|
|
|
|
@@ -40007,6 +40127,18 @@ int main(int argc, char **argv) {
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (argc == 2 && std::strcmp(argv[1], "--flat-d16-only") == 0) {
|
|
|
|
|
VulkanHarness vulkan;
|
|
|
|
|
RunCase(&vulkan, GlobalLoadShortD16Captured(32));
|
|
|
|
|
RunCase(&vulkan, GlobalLoadShortD16Captured(64));
|
|
|
|
|
RunCase(&vulkan, FlatLoadShortD16AddressSegments());
|
|
|
|
|
RunCase(&vulkan, FlatSubdwordLoadsApplyByteOffset());
|
|
|
|
|
RunCase(&vulkan, FlatVirtualAddressRebasesGuestAllocation());
|
|
|
|
|
RunCase(&vulkan, GlobalSignedImmediateRebasesBeforeSaddr());
|
|
|
|
|
RunCase(&vulkan, FlatSegmentIgnoresSaddrAndMasksOffsetMsb());
|
|
|
|
|
RunCase(&vulkan, ScratchIsPrivatePerInvocation());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (argc == 2 && std::strcmp(argv[1], "--indirect-buffer-only") == 0) {
|
|
|
|
|
VulkanHarness vulkan;
|
|
|
|
|
RunCase(&vulkan, ScalarBufferFromLoopReadlane(32));
|
|
|
|
|