mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-27 16:02:37 +00:00
shader: support partial SDWA multiply and byte-source moves
This commit is contained in:
1 parent
7881c69a54
commit
9f25e3c23e
2 files changed
+159
-2
No files matched your search
@@ -36,7 +36,7 @@ constexpr Vop2OpcodeInfo VOP2_OPCODE_LIST[] = {
|
|||||||
{0x05u, Opcode::V_SUBREV_F32},
|
{0x05u, Opcode::V_SUBREV_F32},
|
||||||
{0x08u, Opcode::V_MUL_F32, Vop2SdwaProfile::Float32},
|
{0x08u, Opcode::V_MUL_F32, Vop2SdwaProfile::Float32},
|
||||||
{0x09u, Opcode::V_MUL_I32_I24, Vop2SdwaProfile::IntegerPartialDestination},
|
{0x09u, Opcode::V_MUL_I32_I24, Vop2SdwaProfile::IntegerPartialDestination},
|
||||||
{0x0bu, Opcode::V_MUL_U32_U24, Vop2SdwaProfile::IntegerFullDestination},
|
{0x0bu, Opcode::V_MUL_U32_U24, Vop2SdwaProfile::IntegerPartialDestination},
|
||||||
{0x0fu, Opcode::V_MIN_F32},
|
{0x0fu, Opcode::V_MIN_F32},
|
||||||
{0x10u, Opcode::V_MAX_F32},
|
{0x10u, Opcode::V_MAX_F32},
|
||||||
{0x11u, Opcode::V_MIN_I32},
|
{0x11u, Opcode::V_MIN_I32},
|
||||||
@@ -579,7 +579,7 @@ struct Vop1SdwaRule {
|
|||||||
|
|
||||||
constexpr Vop1SdwaRule VOP1_SDWA_RULES[] = {
|
constexpr Vop1SdwaRule VOP1_SDWA_RULES[] = {
|
||||||
{Opcode::V_MOV_B32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), SdwaSelBytes() | SdwaSelWords(),
|
{Opcode::V_MOV_B32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), SdwaSelBytes() | SdwaSelWords(),
|
||||||
SdwaSelWords() | SdwaSelFull(), false},
|
SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), false},
|
||||||
{Opcode::V_CVT_F32_U32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), 0, 0, false},
|
{Opcode::V_CVT_F32_U32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), 0, 0, false},
|
||||||
{Opcode::V_CVT_F32_I32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), 0, 0, false},
|
{Opcode::V_CVT_F32_I32, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), 0, 0, false},
|
||||||
{Opcode::V_CVT_F32_UBYTE0, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), 0, 0, false},
|
{Opcode::V_CVT_F32_UBYTE0, SdwaSelBytes() | SdwaSelWords() | SdwaSelFull(), 0, 0, false},
|
||||||
|
|||||||
@@ -22094,6 +22094,80 @@ TestCase Vop1SdwaMovByteDestinations() {
|
|||||||
return test;
|
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() {
|
TestCase Vop2SdwaSubNcExactByte2Destination() {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
@@ -22266,6 +22340,74 @@ TestCase Vop2SdwaMulI24Destinations(u32 wave_size) {
|
|||||||
return test;
|
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() {
|
TestCase Vop2SdwaLshrrevCapturedByte1Source() {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
@@ -35937,6 +36079,8 @@ std::vector<TestCase> MakeCases() {
|
|||||||
AddCase(Vop1SdwaNotPreservesHighWordDestination);
|
AddCase(Vop1SdwaNotPreservesHighWordDestination);
|
||||||
AddCase(Vop1SdwaNotPartialSourcesAndDestinations);
|
AddCase(Vop1SdwaNotPartialSourcesAndDestinations);
|
||||||
AddCase(Vop1SdwaMovByteDestinations);
|
AddCase(Vop1SdwaMovByteDestinations);
|
||||||
|
cases.push_back(Vop1SdwaMovByteSources(32));
|
||||||
|
cases.push_back(Vop1SdwaMovByteSources(64));
|
||||||
AddCase(Vop2SdwaSubNcExactByte2Destination);
|
AddCase(Vop2SdwaSubNcExactByte2Destination);
|
||||||
AddCase(Vop2SdwaAddNcCapturedHighWordDestination);
|
AddCase(Vop2SdwaAddNcCapturedHighWordDestination);
|
||||||
AddCase(Vop2SdwaAshrrevCapturedWord0SignExtends);
|
AddCase(Vop2SdwaAshrrevCapturedWord0SignExtends);
|
||||||
@@ -35944,6 +36088,8 @@ std::vector<TestCase> MakeCases() {
|
|||||||
cases.push_back(Vop2SdwaMaxI32CapturedHighWord(64));
|
cases.push_back(Vop2SdwaMaxI32CapturedHighWord(64));
|
||||||
cases.push_back(Vop2SdwaMulI24Destinations(32));
|
cases.push_back(Vop2SdwaMulI24Destinations(32));
|
||||||
cases.push_back(Vop2SdwaMulI24Destinations(64));
|
cases.push_back(Vop2SdwaMulI24Destinations(64));
|
||||||
|
cases.push_back(Vop2SdwaMulU24Destinations(32));
|
||||||
|
cases.push_back(Vop2SdwaMulU24Destinations(64));
|
||||||
AddCase(Vop2SdwaLshrrevCapturedByte1Source);
|
AddCase(Vop2SdwaLshrrevCapturedByte1Source);
|
||||||
AddCase(Vop2SdwaSubNcPreservesByteAndWordDestinations);
|
AddCase(Vop2SdwaSubNcPreservesByteAndWordDestinations);
|
||||||
AddCase(Vop3CvtPkI16I32Captured);
|
AddCase(Vop3CvtPkI16I32Captured);
|
||||||
@@ -41935,6 +42081,8 @@ int main(int argc, char **argv) {
|
|||||||
if (argc == 2 && std::strcmp(argv[1], "--sdwa-mov-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--sdwa-mov-only") == 0) {
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
RunCase(&vulkan, Vop1SdwaMovByteDestinations());
|
RunCase(&vulkan, Vop1SdwaMovByteDestinations());
|
||||||
|
RunCase(&vulkan, Vop1SdwaMovByteSources(32));
|
||||||
|
RunCase(&vulkan, Vop1SdwaMovByteSources(64));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--sdwa-ffbh-only") == 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());
|
RunCase(&vulkan, VectorIntegerOps());
|
||||||
return 0;
|
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) {
|
if (argc == 2 && std::strcmp(argv[1], "--cvt-pk-i16-only") == 0) {
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
RunCase(&vulkan, Vop3CvtPkI16I32Captured());
|
RunCase(&vulkan, Vop3CvtPkI16I32Captured());
|
||||||
|
|||||||
Reference in new issue
Block a user