shader: add scalar zero-bit count and search operations

This commit is contained in:
fxpw
2026-10-10 04:24:33 +02:00
committed by nmzik
parent 3b9e176b70
commit fa56c5eae9
7 changed files with 106 additions and 5 deletions
+67
View File
@@ -20860,6 +20860,66 @@ TestCase ScalarBrevB32PreservesScc() {
O::V_MOV_B32, O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
}
TestCase ScalarZeroBitOps() {
using O = ShaderOpcode;
constexpr uint64_t inputs[] = {0, UINT64_MAX, 0xaaaaaaaa55555555ull,
0xffffffff7fffffffull, 0xfffffffeffffffffull, 0x7fffffffffffffffull,
0x00000000ffffffffull, 0xffffffff00000000ull};
TestCase test;
test.name = "ScalarZeroBitOps";
for (const auto input : inputs)
test.initial.insert(test.initial.end(), {u32(input), u32(input >> 32)});
test.expected = test.initial;
auto &code = test.code;
const auto check = [&](u32 opcode, u32 source, uint64_t input, bool scc) {
const u32 width = opcode == 0x0e || opcode == 0x12 ? 64 : 32;
u32 count = 0, first = UINT32_MAX;
for (u32 bit = 0; bit < width; ++bit) {
if (((input >> bit) & 1u) == 0) {
++count;
if (first == UINT32_MAX) first = bit;
}
}
const bool counting = opcode == 0x0d || opcode == 0x0e;
code.push_back(EncodeSopc(0x06, InlineU32(1), InlineU32(scc)));
code.push_back(EncodeSop1(opcode, 20, source));
if (source == 255) code.push_back(u32(input));
code.push_back(EncodeSMovB32(22, 253)); // Capture SCC before readback.
AppendStoreSgpr(&code, 20, u32(test.expected.size()));
AppendStoreSgpr(&code, 21, u32(test.expected.size() + 1));
AppendStoreSgpr(&code, 22, u32(test.expected.size() + 2));
test.expected.insert(test.expected.end(),
{counting ? count : first, u32(input >> 32), u32(counting ? count != 0 : scc)});
};
for (u32 index = 0; index < std::size(inputs); ++index) {
for (u32 word = 0; word < 2; ++word) {
AppendVMovU32(&code, 30, (index * 2 + word) * sizeof(u32));
AppendBufferLoadDword(&code, 1, 30);
code.push_back(EncodeVop1(0x02, 8 + word, Vgpr(1)));
}
for (const u32 opcode : {0x0du, 0x0eu, 0x11u, 0x12u}) {
for (const bool scc : {false, true}) {
code.push_back(EncodeSop1(0x04, 20, 8)); // Destination aliases the source.
check(opcode, 20, inputs[index], scc);
}
}
}
for (const u32 opcode : {0x0du, 0x0eu, 0x11u, 0x12u}) {
for (const u32 source : {128u, 193u, 255u}) {
const uint64_t input = source == 128 ? 0 : source == 193 ? UINT64_MAX : 0xffffffffull;
AppendSMovLiteral(&code, 21, u32(input >> 32));
check(opcode, source, input, true); // Only inline -1 sign extends to B64.
}
}
AppendEnd(&code);
test.initial.resize(test.expected.size());
test.opcodes = {O::S_BCNT0_I32_B32, O::S_BCNT0_I32_B64,
O::S_FF0_I32_B32, O::S_FF0_I32_B64, O::S_CMP_EQ_U32, O::S_MOV_B32,
O::S_MOV_B64, O::V_MOV_B32, O::V_READFIRSTLANE_B32,
O::BUFFER_LOAD_DWORD, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
return test;
}
TestCase ScalarSextMasks(u32 bits, u32 wave_size) {
using O = ShaderOpcode;
TestCase test;
@@ -37061,6 +37121,7 @@ std::vector<TestCase> MakeCases() {
cases.push_back(ScalarSubvectorLoops(64));
AddCase(ScalarGetpcWritesNextInstructionPc);
AddCase(ScalarBitfieldPack);
AddCase(ScalarZeroBitOps);
AddCase(ScalarBitcmpB64DynamicOperands);
AddCase(ScalarBitcmpB64IntegerConstants);
AddCase(ScalarBrevB32PreservesScc);
@@ -42892,6 +42953,12 @@ int main(int argc, char **argv) {
RunCase(&vulkan, Vop3pInt16Ops());
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--scalar-zero-bit-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, ScalarZeroBitOps());
RunCase(&vulkan, ScalarBitfieldPack());
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--buffer-format-store-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, BufferStoreFormatXyzwPackedUnormSkinningVectors());