mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
shader: support partial SDWA multiply and byte-source moves
This commit is contained in:
@@ -22094,6 +22094,80 @@ TestCase Vop1SdwaMovByteDestinations() {
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase Vop1SdwaMovByteSources(u32 wave_size) {
|
||||
using O = ShaderOpcode;
|
||||
// Select 0x80 from each byte position, with nonzero neighboring bytes.
|
||||
constexpr std::array<u32, 4> sources{
|
||||
0x12345680u, 0x12348056u, 0x12803456u, 0x80341256u};
|
||||
// RDNA2 table 88 / PS5 SDWA-related options: PAD, SEXT, PRESERVE.
|
||||
constexpr std::array<u32, 18> partial_expected{
|
||||
0x00000080u, 0xffffff80u, 0xa1b2c380u,
|
||||
0x00008000u, 0xffff8000u, 0xa1b280d4u,
|
||||
0x00800000u, 0xff800000u, 0xa180c3d4u,
|
||||
0x80000000u, 0x80000000u, 0x80b2c3d4u,
|
||||
0x00000080u, 0x00000080u, 0xa1b20080u,
|
||||
0x00800000u, 0x00800000u, 0x0080c3d4u};
|
||||
constexpr std::array<u32, 6> sext_word_expected{
|
||||
0x0000ff80u, 0xffffff80u, 0xa1b2ff80u,
|
||||
0xff800000u, 0xff800000u, 0xff80c3d4u};
|
||||
TestCase test;
|
||||
test.name = wave_size == 64 ? "Vop1SdwaMovByteSourcesWave64"
|
||||
: "Vop1SdwaMovByteSourcesWave32";
|
||||
test.initial.assign(sources.begin(), sources.end());
|
||||
test.expected = test.initial;
|
||||
auto &code = test.code;
|
||||
const auto store = [&](u32 expected) {
|
||||
AppendStoreVgpr(&code, 1, static_cast<u32>(test.expected.size()));
|
||||
test.expected.push_back(expected);
|
||||
};
|
||||
for (u32 src_sel = 0; src_sel < sources.size(); ++src_sel) {
|
||||
AppendVMovU32(&code, 30, src_sel * sizeof(u32));
|
||||
AppendBufferLoadDword(&code, 2, 30);
|
||||
for (u32 sext = 0; sext < 2; ++sext) {
|
||||
for (u32 dst_sel = 0; dst_sel < 6; ++dst_sel) {
|
||||
for (u32 unused = 0; unused < 3; ++unused) {
|
||||
AppendVMovLiteral(&code, 1, 0xa1b2c3d4u);
|
||||
code.push_back(EncodeVop1(0x01, 1, 249));
|
||||
code.push_back(EncodeVop1Sdwa(2, dst_sel, unused, src_sel, sext));
|
||||
store(sext && dst_sel >= 4 ? sext_word_expected[(dst_sel - 4u) * 3u + unused]
|
||||
: partial_expected[dst_sel * 3u + unused]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Aliasing must read the source byte before replacing the destination byte.
|
||||
AppendVMovU32(&code, 30, 0);
|
||||
AppendBufferLoadDword(&code, 1, 30);
|
||||
code.push_back(EncodeVop1(0x01, 1, 249));
|
||||
code.push_back(EncodeVop1Sdwa(1, 3, 2, 1));
|
||||
store(0x56345680u);
|
||||
// Scalar and inline sources use the same independent selectors.
|
||||
AppendSMovLiteral(&code, 18, 0x12348056u);
|
||||
code.push_back(EncodeVop1(0x01, 1, 249));
|
||||
code.push_back(EncodeVop1Sdwa(18, 5, 0, 1, 1, 0, 0, 1));
|
||||
store(0xff800000u);
|
||||
AppendVMovLiteral(&code, 1, 0xa1b2c3d4u);
|
||||
code.push_back(EncodeVop1(0x01, 1, 249));
|
||||
code.push_back(EncodeVop1Sdwa(193, 0, 2, 3, 0, 0, 0, 1)); // Inline -1.
|
||||
store(0xa1b2c3ffu);
|
||||
for (u32 unused = 0; unused < 3; ++unused) {
|
||||
AppendVMovLiteral(&code, 1, 0xa1b2c3d4u);
|
||||
code.push_back(EncodeSMovB32(126, InlineU32(0)));
|
||||
code.push_back(EncodeVop1(0x01, 1, 249));
|
||||
code.push_back(EncodeVop1Sdwa(2, 4, unused, 0));
|
||||
code.push_back(EncodeSMovB32(126, InlineU32(1)));
|
||||
store(0xa1b2c3d4u);
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.initial.resize(test.expected.size());
|
||||
test.opcodes = {O::V_MOV_B32, O::S_MOV_B32, O::BUFFER_LOAD_DWORD,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.required_spirv = {"OpBitFieldUExtract", "OpBitFieldSExtract", "OpBitFieldInsert"};
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.has_compute_info = true;
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase Vop2SdwaSubNcExactByte2Destination() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -22266,6 +22340,74 @@ TestCase Vop2SdwaMulI24Destinations(u32 wave_size) {
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase Vop2SdwaMulU24Destinations(u32 wave_size) {
|
||||
using O = ShaderOpcode;
|
||||
// The high source bytes are discarded: 3 * 0xe080 = 0x2a180.
|
||||
constexpr std::array<u32, 18> partial_expected{
|
||||
0x00000080u, 0xffffff80u, 0xa1b2c380u,
|
||||
0x00008000u, 0xffff8000u, 0xa1b280d4u,
|
||||
0x00800000u, 0xff800000u, 0xa180c3d4u,
|
||||
0x80000000u, 0x80000000u, 0x80b2c3d4u,
|
||||
0x0000a180u, 0xffffa180u, 0xa1b2a180u,
|
||||
0xa1800000u, 0xa1800000u, 0xa180c3d4u};
|
||||
TestCase test;
|
||||
test.name = wave_size == 64 ? "Vop2SdwaMulU24DestinationsWave64"
|
||||
: "Vop2SdwaMulU24DestinationsWave32";
|
||||
test.initial = {0xab000003u, 0xcd00e080u, 0xffffffffu};
|
||||
test.expected = test.initial;
|
||||
auto &code = test.code;
|
||||
const auto store = [&](u32 reg, u32 expected) {
|
||||
AppendStoreVgpr(&code, reg, static_cast<u32>(test.expected.size()));
|
||||
test.expected.push_back(expected);
|
||||
};
|
||||
for (u32 i = 0; i < test.initial.size(); ++i) {
|
||||
AppendVMovU32(&code, 30, i * sizeof(u32));
|
||||
AppendBufferLoadDword(&code, 12u + i, 30);
|
||||
}
|
||||
for (u32 selector = 0; selector < 6; ++selector) {
|
||||
for (u32 unused = 0; unused < 3; ++unused) {
|
||||
AppendVMovLiteral(&code, 26, 0xa1b2c3d4u);
|
||||
code.push_back(EncodeVop2(0x0b, 26, 249, 13));
|
||||
code.push_back(EncodeVop2Sdwa(12, selector, unused));
|
||||
store(26, partial_expected[selector * 3u + unused]);
|
||||
}
|
||||
}
|
||||
// Full result still truncates the 48-bit unsigned product to 32 bits.
|
||||
code.push_back(EncodeVop2(0x0b, 26, 249, 14));
|
||||
code.push_back(EncodeVop2Sdwa(14));
|
||||
store(26, 0xfe000001u);
|
||||
// Either multiplicand may alias the partial destination.
|
||||
code.push_back(EncodeVop2(0x0b, 12, 249, 13));
|
||||
code.push_back(EncodeVop2Sdwa(12, 5, 2));
|
||||
store(12, 0xa1800003u);
|
||||
code.push_back(EncodeVop2(0x0b, 13, 249, 13));
|
||||
code.push_back(EncodeVop2Sdwa(InlineU32(3), 2, 2, 6, 4,
|
||||
0, 0, 0, 0, 0, 0, 1));
|
||||
store(13, 0xcd80e080u);
|
||||
// Source-byte sign extension happens before the unsigned 24-bit multiply.
|
||||
AppendSMovLiteral(&code, 18, 0x12348056u);
|
||||
code.push_back(EncodeVop2(0x0b, 26, 249, InlineU32(3)));
|
||||
code.push_back(EncodeVop2Sdwa(18, 5, 0, 1, 6, 1, 0, 0, 0, 0, 0, 1, 1));
|
||||
store(26, 0xfe800000u);
|
||||
for (u32 unused = 0; unused < 3; ++unused) {
|
||||
AppendVMovLiteral(&code, 26, 0xa1b2c3d4u);
|
||||
code.push_back(EncodeSMovB32(126, InlineU32(0)));
|
||||
code.push_back(EncodeVop2(0x0b, 26, 249, 13));
|
||||
code.push_back(EncodeVop2Sdwa(12, 4, unused));
|
||||
code.push_back(EncodeSMovB32(126, InlineU32(1)));
|
||||
store(26, 0xa1b2c3d4u);
|
||||
}
|
||||
AppendEnd(&code);
|
||||
test.initial.resize(test.expected.size());
|
||||
test.opcodes = {O::V_MOV_B32, O::S_MOV_B32, O::BUFFER_LOAD_DWORD,
|
||||
O::V_MUL_U32_U24, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.decoded_counts = {{"V_MUL_U32_U24", 25u}};
|
||||
test.required_spirv = {"OpIMul", "OpBitFieldUExtract", "OpBitFieldSExtract"};
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.has_compute_info = true;
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase Vop2SdwaLshrrevCapturedByte1Source() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -35937,6 +36079,8 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(Vop1SdwaNotPreservesHighWordDestination);
|
||||
AddCase(Vop1SdwaNotPartialSourcesAndDestinations);
|
||||
AddCase(Vop1SdwaMovByteDestinations);
|
||||
cases.push_back(Vop1SdwaMovByteSources(32));
|
||||
cases.push_back(Vop1SdwaMovByteSources(64));
|
||||
AddCase(Vop2SdwaSubNcExactByte2Destination);
|
||||
AddCase(Vop2SdwaAddNcCapturedHighWordDestination);
|
||||
AddCase(Vop2SdwaAshrrevCapturedWord0SignExtends);
|
||||
@@ -35944,6 +36088,8 @@ std::vector<TestCase> MakeCases() {
|
||||
cases.push_back(Vop2SdwaMaxI32CapturedHighWord(64));
|
||||
cases.push_back(Vop2SdwaMulI24Destinations(32));
|
||||
cases.push_back(Vop2SdwaMulI24Destinations(64));
|
||||
cases.push_back(Vop2SdwaMulU24Destinations(32));
|
||||
cases.push_back(Vop2SdwaMulU24Destinations(64));
|
||||
AddCase(Vop2SdwaLshrrevCapturedByte1Source);
|
||||
AddCase(Vop2SdwaSubNcPreservesByteAndWordDestinations);
|
||||
AddCase(Vop3CvtPkI16I32Captured);
|
||||
@@ -41935,6 +42081,8 @@ int main(int argc, char **argv) {
|
||||
if (argc == 2 && std::strcmp(argv[1], "--sdwa-mov-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, Vop1SdwaMovByteDestinations());
|
||||
RunCase(&vulkan, Vop1SdwaMovByteSources(32));
|
||||
RunCase(&vulkan, Vop1SdwaMovByteSources(64));
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--sdwa-ffbh-only") == 0) {
|
||||
@@ -41984,6 +42132,15 @@ int main(int argc, char **argv) {
|
||||
RunCase(&vulkan, VectorIntegerOps());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--sdwa-mul-u24-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, Vop2SdwaMulU24Destinations(32));
|
||||
RunCase(&vulkan, Vop2SdwaMulU24Destinations(64));
|
||||
RunCase(&vulkan, Vop2SdwaMulI24Destinations(32));
|
||||
RunCase(&vulkan, Vop2SdwaMulI24Destinations(64));
|
||||
RunCase(&vulkan, VectorIntegerOps());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--cvt-pk-i16-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, Vop3CvtPkI16I32Captured());
|
||||
|
||||
Reference in New Issue
Block a user