shader: support high products of 24-bit integers

This commit is contained in:
nmzik committed 2026-10-28 22:49:21 +01:00
1 parent 22610cb93e
commit 54b937c85f
7 files changed
+128 -4

No files matched your search

+109
View File
@@ -26425,6 +26425,102 @@ TestCase Vop2SdwaMinI32CapturedByte0(u32 wave_size) {
return test;
}
TestCase VectorMulHi24(u32 wave_size) {
using O = ShaderOpcode;
namespace D = ShaderRecompiler::Decoder;
constexpr std::array<u32, 8> lhs{0x7f7fffffu, 0xa5800000u, 0x12ffffffu, 0xab000000u,
0x00010000u, 0xffabcdefu, 0x80000001u, 0x7fffffffu};
constexpr std::array<u32, 8> rhs{0x00800000u, 0xcd800000u, 0x55000001u, 0x99ffffffu,
0xab010000u, 0x00ffffffu, 0xfffffffeu, 0xffffffffu};
TestCase test;
test.name = wave_size == 32 ? "VectorMulHi24Wave32" : "VectorMulHi24Wave64";
for (u32 lane = 0; lane < wave_size; ++lane) test.initial.push_back(lhs[lane % lhs.size()]);
for (u32 lane = 0; lane < wave_size; ++lane) test.initial.push_back(rhs[lane % rhs.size()]);
test.expected = test.initial;
auto &code = test.code;
code.push_back(EncodeVop2(0x1a, 30, InlineU32(2), 0));
AppendBufferLoadDword(&code, 2, 30);
AppendVMovU32(&code, 20, wave_size * sizeof(u32));
code.push_back(EncodeVop2(0x25, 30, Vgpr(20), 30));
AppendBufferLoadDword(&code, 3, 30);
for (bool sign : {true, false}) {
const u32 opcode = sign ? 0x0a : 0x0c;
for (u32 modifier = 0; modifier < 13; ++modifier) {
const u32 words[] = {
EncodeVop3Word0(0x100 + opcode, 7, modifier < 3 ? 1u << modifier : 0,
modifier >= 9 ? 1u << (modifier - 9) : 0),
EncodeVop3Word1(Vgpr(5), Vgpr(6), 0,
modifier >= 6 && modifier < 9 ? modifier - 5 : 0,
modifier >= 3 && modifier < 6 ? 1u << (modifier - 3) : 0)};
D::Instruction decoded;
D::DecodeInstruction(words, 0, decoded);
Require(test.name, "integer modifiers", decoded.opcode == O::UNSUPPORTED,
"24-bit high multiply accepted unsupported modifiers");
}
for (u32 variant = 0; variant < 10; ++variant) {
code.push_back(EncodeVop1(0x01, 5, Vgpr(2)));
code.push_back(EncodeVop1(0x01, 6, Vgpr(3)));
AppendVMovLiteral(&code, 7, 0xa5a5beefu);
u32 dst = 7;
switch (variant) {
case 0: dst = 5; code.push_back(EncodeVop2(opcode, dst, Vgpr(5), 6)); break;
case 1: dst = 6; AppendVop3(&code, 0x100 + opcode, dst, Vgpr(5), Vgpr(6)); break;
case 2: AppendVop3(&code, 0x100 + opcode, dst, Vgpr(5), Vgpr(6), 0, 0, 0, true); break;
case 3:
code.push_back(EncodeVop2(opcode, dst, 255, 6));
code.push_back(0x00ffffffu);
break;
case 4:
AppendVop3(&code, 0x100 + opcode, dst, Vgpr(5), 255);
code.push_back(0x00800000u);
break;
case 5:
AppendSMovLiteral(&code, 20, 0xffff0001u);
AppendVop3(&code, 0x100 + opcode, dst, Vgpr(5), 20);
break;
case 6:
case 7:
case 8:
code.push_back(EncodeVop2(opcode, dst, 249, 6));
code.push_back(EncodeVop2Sdwa(5, variant == 7 ? 5 : 6, variant == 7 ? 2 : 0,
variant == 8 ? 4 : 6, 6, variant == 8));
break;
case 9:
code.push_back(EncodeVop2(opcode, dst, 250, 6));
code.push_back(EncodeVop2Dpp(5, 0x01b)); // Reverse each quad's source lanes.
break;
}
AppendStoreVgprAtLaneDwordOffset(&code, dst, 0, static_cast<u32>(test.expected.size()));
for (u32 lane = 0; lane < wave_size; ++lane) {
const u32 source_lane = variant == 9 ? lane ^ 3u : lane;
u32 a = lhs[source_lane % lhs.size()], b = rhs[lane % rhs.size()];
if (variant == 3) a = 0x00ffffffu;
if (variant == 4) b = 0x00800000u;
if (variant == 5) b = 0xffff0001u;
if (variant == 8) a = (a & 0x8000u) ? a | 0xffff0000u : a & 0xffffu;
const auto extend24 = [sign](u32 value) -> int64_t {
const int64_t low = value & 0x00ffffffu;
return sign && (value & 0x00800000u) ? low - 0x01000000 : low;
};
const uint64_t product = static_cast<uint64_t>(extend24(a) * extend24(b));
const u32 high = static_cast<u32>(product >> 32);
test.expected.push_back(variant == 7 ? 0xbeefu | (high << 16) : high);
}
}
}
AppendEnd(&code);
test.opcodes = {O::V_MOV_B32, O::S_MOV_B32, O::V_LSHLREV_B32, O::V_ADD_NC_U32,
O::BUFFER_LOAD_DWORD, O::V_MUL_HI_I32_I24, O::V_MUL_HI_U32_U24,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.compute_info.wave_size = 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.has_compute_info = true;
return test;
}
TestCase Vop2SdwaMulI24Destinations(u32 wave_size) {
using O = ShaderOpcode;
constexpr std::array<u32, 5> sources{
@@ -46282,6 +46378,8 @@ std::vector<TestCase> MakeCases() {
cases.push_back(Vop2SdwaMaxI32CapturedHighWord(64));
cases.push_back(Vop2SdwaMinI32CapturedByte0(32));
cases.push_back(Vop2SdwaMinI32CapturedByte0(64));
cases.push_back(VectorMulHi24(32));
cases.push_back(VectorMulHi24(64));
cases.push_back(Vop2SdwaMulI24Destinations(32));
cases.push_back(Vop2SdwaMulI24Destinations(64));
cases.push_back(Vop2SdwaMulU24Destinations(32));
@@ -52727,6 +52825,17 @@ int main(int argc, char **argv) {
std::setvbuf(stdout, nullptr, _IONBF, 0);
EnsureConfigInitialized();
CheckLeastRecentlyUsedCacheOrdering();
if (argc == 2 && std::strcmp(argv[1], "--mul-hi24-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, VectorMulHi24(32));
RunCase(&vulkan, VectorMulHi24(64));
RunCase(&vulkan, Vop2SdwaMulI24Destinations(32));
RunCase(&vulkan, Vop2SdwaMulI24Destinations(64));
RunCase(&vulkan, Vop2SdwaMulU24Destinations(32));
RunCase(&vulkan, Vop2SdwaMulU24Destinations(64));
RunCase(&vulkan, VectorVop3IntegerOps());
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--mad-u16-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, Vop3MadU16(32));