Merge pull request #507 from adriadam10/feat/vop3-integer-clamp
fix(shader): saturate VOP3 integer mad/sad results on clamp
This commit is contained in:
commit
fdd6519eac
|
|
@ -0,0 +1,188 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Inputs = 4;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Inputs> Input{};
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 48> Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0xd543800a, 0x041a0b04, 0xd542800b,
|
||||
0x041a0b04, 0xd740800c, 0x041a0b04, 0xd75e800d, 0x041a0b04, 0xd773800e, 0x041a0b04, 0xd775800f,
|
||||
0x041a0b04, 0xd55a8010, 0x041a0b04, 0xd55b8011, 0x041a0b04, 0xd55c8012, 0x041a0b04, 0xd55d8013,
|
||||
0x041a0b04, 0xd5718014, 0x041a0b04, 0x7e2a0307, 0xd740d815, 0x041a0b04, 0xd75eb016, 0x041a0b04,
|
||||
0xd7758817, 0x041a0b04, 0xd7739018, 0x041a0b04, 0x7e320307, 0xd75ef819, 0x041a0b04, 0xe0781000,
|
||||
0x80010a03, 0xe0781010, 0x80010e03, 0xe0781020, 0x80011203, 0xe0781030, 0x80011603, 0xbf810000,
|
||||
};
|
||||
|
||||
constexpr std::uint32_t Rows[32][4] = {
|
||||
{0x00000000u, 0x00000000u, 0x00000001u, 0x0000ffffu},
|
||||
{0x00000000u, 0x00007fffu, 0xffffffffu, 0x0000fff0u},
|
||||
{0x01010101u, 0x01010101u, 0xffffffffu, 0xff00ff00u},
|
||||
{0x00000001u, 0xff00ff00u, 0x80000000u, 0x7fffffffu},
|
||||
{0x00000000u, 0x00000000u, 0x506377feu, 0x09418c53u},
|
||||
{0x00000000u, 0x00000000u, 0xad078efau, 0x00000002u},
|
||||
{0x00000000u, 0x00000001u, 0x00000002u, 0x293b6032u},
|
||||
{0x00000000u, 0x00000001u, 0x0000fff0u, 0x00ff00ffu},
|
||||
{0x00000000u, 0x00000001u, 0x00ff00ffu, 0xdbd16e44u},
|
||||
{0x00000000u, 0x00000001u, 0x671b91d7u, 0xb1836b5au},
|
||||
{0x00000000u, 0x00000001u, 0xb51b0523u, 0x54b074b8u},
|
||||
{0x00000000u, 0x00000001u, 0xff0ec345u, 0x00007fffu},
|
||||
{0x00000000u, 0x00000002u, 0x00000000u, 0xfefefefeu},
|
||||
{0x00000000u, 0x0000007fu, 0x00000002u, 0xcee69ed0u},
|
||||
{0x00000000u, 0x0000007fu, 0x12345678u, 0x40778188u},
|
||||
{0x00000000u, 0x0000007fu, 0x1bf35776u, 0x12345678u},
|
||||
{0x00000000u, 0x0000007fu, 0x29c0ba3bu, 0x48e98a0au},
|
||||
{0x00000000u, 0x0000007fu, 0x9d299c7bu, 0x39cdd549u},
|
||||
{0x00000000u, 0x0000007fu, 0x9ff9949eu, 0x00ffffffu},
|
||||
{0x00000000u, 0x00000080u, 0x000000ffu, 0x12345678u},
|
||||
{0x00000000u, 0x00000080u, 0x00008000u, 0x80000001u},
|
||||
{0x00000000u, 0x00000080u, 0x0000fff0u, 0xae15989du},
|
||||
{0x00000000u, 0x00000080u, 0x0000ffffu, 0x00000080u},
|
||||
{0x00000000u, 0x00000080u, 0x80000001u, 0x0000007fu},
|
||||
{0x00000000u, 0x00000080u, 0xaf4a9e38u, 0xd42344f4u},
|
||||
{0x00000000u, 0x00000080u, 0xea4d8c45u, 0x00625618u},
|
||||
{0x00000000u, 0x00000080u, 0xfd4fb563u, 0xff00ff00u},
|
||||
{0x00000000u, 0x000000ffu, 0x00000001u, 0x310733d9u},
|
||||
{0x00000000u, 0x000000ffu, 0x2f3bacc0u, 0xffff0000u},
|
||||
{0x00000000u, 0x000000ffu, 0x85f55b11u, 0xffff0000u},
|
||||
{0x00000000u, 0x000000ffu, 0xff00ff00u, 0x9fc408e0u},
|
||||
{0x00000000u, 0x000000ffu, 0xffff0000u, 0xffff0000u}
|
||||
};
|
||||
constexpr std::uint32_t Expected[32][16] = {
|
||||
{0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x0001ffffu, 0x00000000u, 0x00000001u, 0x00000001u, 0x0000ffffu},
|
||||
{0xffffffffu, 0xffffffffu, 0x0000ffffu, 0x0000ffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xfffffff0u, 0x0000ffffu, 0xffffffffu, 0xffffffffu, 0xfffffff0u},
|
||||
{0xffffffffu, 0x7fffffffu, 0x0000ffffu, 0x00007fffu, 0xffffffffu, 0x00010200u, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffff00u, 0x00007fffu, 0x00010200u, 0xffffffffu, 0x7fffff00u},
|
||||
{0x8000ff00u, 0x8000ff00u, 0x0000ff00u, 0x0000ff00u, 0x8000ff00u, 0x80000000u, 0x800001ffu, 0x81ff0000u, 0x8001fdffu, 0xffffffffu, 0x800001feu, 0x0000ffffu, 0x00008000u, 0x80000000u, 0x8000ff00u, 0x8000ffffu},
|
||||
{0x506377feu, 0x506377feu, 0x000077feu, 0x000077feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x77fe8c53u, 0x00005063u, 0x506377feu, 0x506377feu, 0x50638c53u},
|
||||
{0xad078efau, 0xad078efau, 0x00008efau, 0x00008efau, 0xad078efau, 0xad078efau, 0xad078efau, 0xad078efau, 0xad078efau, 0xad078efau, 0xad078efau, 0x8efa0002u, 0x0000ad07u, 0xad078efau, 0xad078efau, 0xad070002u},
|
||||
{0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000003u, 0x00010002u, 0x00000003u, 0x00000003u, 0x00000003u, 0x00026032u, 0x00000000u, 0x00000002u, 0x00000002u, 0x00006032u},
|
||||
{0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff1u, 0x0001fff0u, 0x0000fff1u, 0x0000fff1u, 0x0000fff1u, 0xfff000ffu, 0x00000000u, 0x0000fff0u, 0x0000fff0u, 0x000000ffu},
|
||||
{0x00ff00ffu, 0x00ff00ffu, 0x000000ffu, 0x000000ffu, 0x00ff00ffu, 0x00ff00ffu, 0x00ff0100u, 0x010000ffu, 0x00ff0100u, 0x00ff0100u, 0x00ff0100u, 0x00ff6e44u, 0x000000ffu, 0x00ff00ffu, 0x00ff00ffu, 0x00ff6e44u},
|
||||
{0x671b91d7u, 0x671b91d7u, 0x000091d7u, 0x000091d7u, 0x671b91d7u, 0x671b91d7u, 0x671b91d8u, 0x671c91d7u, 0x671b91d8u, 0x671b91d8u, 0x671b91d8u, 0x91d76b5au, 0x0000671bu, 0x671b91d7u, 0x671b91d7u, 0x671b6b5au},
|
||||
{0xb51b0523u, 0xb51b0523u, 0x00000523u, 0x00000523u, 0xb51b0523u, 0xb51b0523u, 0xb51b0524u, 0xb51c0523u, 0xb51b0524u, 0xb51b0524u, 0xb51b0524u, 0x052374b8u, 0x0000b51bu, 0xb51b0523u, 0xb51b0523u, 0xb51b74b8u},
|
||||
{0xff0ec345u, 0xff0ec345u, 0x0000c345u, 0x0000c345u, 0xff0ec345u, 0xff0ec345u, 0xff0ec346u, 0xff0fc345u, 0xff0ec346u, 0xff0ec346u, 0xff0ec346u, 0xc3457fffu, 0x0000ff0eu, 0xff0ec345u, 0xff0ec345u, 0xff0e7fffu},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000002u, 0x00020000u, 0x00000002u, 0x00000002u, 0x00000002u, 0x0000fefeu, 0x00000000u, 0x00000000u, 0x00000000u, 0x0000fefeu},
|
||||
{0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000081u, 0x007f0002u, 0x00000081u, 0x00000081u, 0x00000081u, 0x00029ed0u, 0x00000000u, 0x00000002u, 0x00000002u, 0x00009ed0u},
|
||||
{0x12345678u, 0x12345678u, 0x00005678u, 0x00005678u, 0x12345678u, 0x12345678u, 0x123456f7u, 0x12b35678u, 0x123456f7u, 0x123456f7u, 0x123456f7u, 0x56788188u, 0x00001234u, 0x12345678u, 0x12345678u, 0x12348188u},
|
||||
{0x1bf35776u, 0x1bf35776u, 0x00005776u, 0x00005776u, 0x1bf35776u, 0x1bf35776u, 0x1bf357f5u, 0x1c725776u, 0x1bf357f5u, 0x1bf357f5u, 0x1bf357f5u, 0x57765678u, 0x00001bf3u, 0x1bf35776u, 0x1bf35776u, 0x1bf35678u},
|
||||
{0x29c0ba3bu, 0x29c0ba3bu, 0x0000ba3bu, 0x0000ba3bu, 0x29c0ba3bu, 0x29c0ba3bu, 0x29c0babau, 0x2a3fba3bu, 0x29c0babau, 0x29c0babau, 0x29c0babau, 0xba3b8a0au, 0x000029c0u, 0x29c0ba3bu, 0x29c0ba3bu, 0x29c08a0au},
|
||||
{0x9d299c7bu, 0x9d299c7bu, 0x00009c7bu, 0x00009c7bu, 0x9d299c7bu, 0x9d299c7bu, 0x9d299cfau, 0x9da89c7bu, 0x9d299cfau, 0x9d299cfau, 0x9d299cfau, 0x9c7bd549u, 0x00009d29u, 0x9d299c7bu, 0x9d299c7bu, 0x9d29d549u},
|
||||
{0x9ff9949eu, 0x9ff9949eu, 0x0000949eu, 0x0000949eu, 0x9ff9949eu, 0x9ff9949eu, 0x9ff9951du, 0xa078949eu, 0x9ff9951du, 0x9ff9951du, 0x9ff9951du, 0x949effffu, 0x00009ff9u, 0x9ff9949eu, 0x9ff9949eu, 0x9ff9ffffu},
|
||||
{0x000000ffu, 0x000000ffu, 0x000000ffu, 0x000000ffu, 0x000000ffu, 0x000000ffu, 0x0000017fu, 0x008000ffu, 0x0000017fu, 0x0000017fu, 0x0000017fu, 0x00ff5678u, 0x00000000u, 0x000000ffu, 0x000000ffu, 0x00005678u},
|
||||
{0x00008000u, 0x00008000u, 0x00008000u, 0x00008000u, 0x00008000u, 0x00008000u, 0x00008080u, 0x00808000u, 0x00008080u, 0x00008080u, 0x00008080u, 0x80000001u, 0x00000000u, 0x00008000u, 0x00008000u, 0x00000001u},
|
||||
{0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x00010070u, 0x0080fff0u, 0x00010070u, 0x00010070u, 0x00010070u, 0xfff0989du, 0x00000000u, 0x0000fff0u, 0x0000fff0u, 0x0000989du},
|
||||
{0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0001007fu, 0x0080ffffu, 0x0001007fu, 0x0001007fu, 0x0001007fu, 0xffff0080u, 0x00000000u, 0x0000ffffu, 0x0000ffffu, 0x00000080u},
|
||||
{0x80000001u, 0x80000001u, 0x00000001u, 0x00000001u, 0x80000001u, 0x80000001u, 0x80000081u, 0x80800001u, 0x80000081u, 0x80000081u, 0x80000081u, 0x0001007fu, 0x00008000u, 0x80000001u, 0x80000001u, 0x8000007fu},
|
||||
{0xaf4a9e38u, 0xaf4a9e38u, 0x00009e38u, 0x00009e38u, 0xaf4a9e38u, 0xaf4a9e38u, 0xaf4a9eb8u, 0xafca9e38u, 0xaf4a9eb8u, 0xaf4a9eb8u, 0xaf4a9eb8u, 0x9e3844f4u, 0x0000af4au, 0xaf4a9e38u, 0xaf4a9e38u, 0xaf4a44f4u},
|
||||
{0xea4d8c45u, 0xea4d8c45u, 0x00008c45u, 0x00008c45u, 0xea4d8c45u, 0xea4d8c45u, 0xea4d8cc5u, 0xeacd8c45u, 0xea4d8cc5u, 0xea4d8cc5u, 0xea4d8cc5u, 0x8c455618u, 0x0000ea4du, 0xea4d8c45u, 0xea4d8c45u, 0xea4d5618u},
|
||||
{0xfd4fb563u, 0xfd4fb563u, 0x0000b563u, 0x0000b563u, 0xfd4fb563u, 0xfd4fb563u, 0xfd4fb5e3u, 0xfdcfb563u, 0xfd4fb5e3u, 0xfd4fb5e3u, 0xfd4fb5e3u, 0xb563ff00u, 0x0000fd4fu, 0xfd4fb563u, 0xfd4fb563u, 0xfd4fff00u},
|
||||
{0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000100u, 0x00ff0001u, 0x00000100u, 0x00000100u, 0x00000100u, 0x000133d9u, 0x00000000u, 0x00000001u, 0x00000001u, 0x000033d9u},
|
||||
{0x2f3bacc0u, 0x2f3bacc0u, 0x0000acc0u, 0x0000acc0u, 0x2f3bacc0u, 0x2f3bacc0u, 0x2f3badbfu, 0x303aacc0u, 0x2f3badbfu, 0x2f3badbfu, 0x2f3badbfu, 0xacc00000u, 0x00002f3bu, 0x2f3bacc0u, 0x2f3bacc0u, 0x2f3b0000u},
|
||||
{0x85f55b11u, 0x85f55b11u, 0x00005b11u, 0x00005b11u, 0x85f55b11u, 0x85f55b11u, 0x85f55c10u, 0x86f45b11u, 0x85f55c10u, 0x85f55c10u, 0x85f55c10u, 0x5b110000u, 0x000085f5u, 0x85f55b11u, 0x85f55b11u, 0x85f50000u},
|
||||
{0xff00ff00u, 0xff00ff00u, 0x0000ff00u, 0x0000ff00u, 0xff00ff00u, 0xff00ff00u, 0xff00ffffu, 0xffffff00u, 0xff00ffffu, 0xff00ffffu, 0xff00ffffu, 0xff0008e0u, 0x0000ff00u, 0xff00ff00u, 0xff00ff00u, 0xff0008e0u},
|
||||
{0xffff0000u, 0xffff0000u, 0x00000000u, 0x00000000u, 0xffff0000u, 0xffff0000u, 0xffff00ffu, 0xffffffffu, 0xffff00ffu, 0xffff00ffu, 0xffff00ffu, 0x00000000u, 0x0000ffffu, 0xffff0000u, 0xffff0000u, 0xffff0000u}
|
||||
};
|
||||
constexpr const char* Names[16] = {
|
||||
"mad_u32_u24",
|
||||
"mad_i32_i24",
|
||||
"mad_u16",
|
||||
"mad_i16",
|
||||
"mad_u32_u16",
|
||||
"mad_i32_i16",
|
||||
"sad_u8",
|
||||
"sad_hi_u8",
|
||||
"sad_u16",
|
||||
"sad_u32",
|
||||
"msad_u8",
|
||||
"mad_u16 op_sel",
|
||||
"mad_i16 op_sel",
|
||||
"mad_i32_i16 op_sel",
|
||||
"mad_u32_u16 op_sel",
|
||||
"mad_i16 op_sel",
|
||||
};
|
||||
|
||||
void Fill(std::uint32_t tid, std::uint32_t* words) {
|
||||
std::copy(std::begin(Rows[tid]), std::end(Rows[tid]), words);
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t bytes) {
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(data);
|
||||
return {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>((address >> 32u) & 0xffffu), bytes, 0x01016facu};
|
||||
}
|
||||
|
||||
std::string Hex(std::uint32_t value) {
|
||||
char text[16];
|
||||
std::snprintf(text, sizeof(text), "0x%08x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Expect(std::uint32_t tid, std::uint32_t actual, std::uint32_t expected, const char* name) {
|
||||
Require(actual == expected, std::string("vop3 integer clamp: lane ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected));
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) Fill(tid, &Input[tid * Inputs]);
|
||||
Output.fill(0xdeadbeefu);
|
||||
std::vector<std::uint32_t> userData(8, 0u);
|
||||
const auto input = BufferDescriptor(Input.data(), static_cast<std::uint32_t>(Input.size() * 4u));
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(input.begin(), input.end(), userData.begin());
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
const std::span<const std::uint32_t> code(Code);
|
||||
const std::array<ShaderRecompiler::MemoryRegion, 1> memory{{{reinterpret_cast<std::uintptr_t>(code.data()), std::as_bytes(code)}}};
|
||||
const ShaderRecompiler::ShaderComputeStageInfo compute{{Threads, 1, 1}, 0u, {false, false, false}, false, 1};
|
||||
ShaderRecompiler::RecompileRequest request{
|
||||
{ShaderStage::Compute, reinterpret_cast<std::uintptr_t>(code.data()), code, 0, {}},
|
||||
{32, 0, userData, compute, std::nullopt, std::nullopt, memory},
|
||||
device.Target(),
|
||||
{0, 0, 0, 128}
|
||||
};
|
||||
request.useCache = false;
|
||||
const auto result = ShaderRecompiler::Recompile(request);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void Check() {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const std::uint32_t* in = &Input[tid * Inputs];
|
||||
const std::uint32_t* out = &Output[tid * Results];
|
||||
for (std::uint32_t i = 0; i < 16; ++i) {
|
||||
Expect(tid, out[i], Expected[tid][i], Names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
Run(*device);
|
||||
Check();
|
||||
std::puts("vop3 integer clamp tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Inputs = 4;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Inputs> Input{};
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 36> Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0xd572800a, 0x041a0d04, 0xd573800c,
|
||||
0x041a0d04, 0xd575800e, 0x04120d04, 0xd7558012, 0x041a0b04, 0xd7568013, 0x041a0b04, 0xd7528014,
|
||||
0x041a0b04, 0xd7538015, 0x041a0b04, 0xd7588016, 0x041a0b04, 0xd7598017, 0x041a0b04, 0xd54e8018,
|
||||
0x041a0b04, 0xd54f8019, 0x041a0b04, 0xe0781000, 0x80010a03, 0xe0781010, 0x80010e03, 0xe0781020,
|
||||
0x80011203, 0xe0781030, 0x80011603, 0xbf810000,
|
||||
};
|
||||
|
||||
constexpr std::uint32_t Rows[32][4] = {
|
||||
{0x00000000u, 0x00000000u, 0x00800000u, 0x0000ffffu},
|
||||
{0x0000007fu, 0xe3718038u, 0xfffffffeu, 0xfd7c84feu},
|
||||
{0x0000007fu, 0xfffffffeu, 0x0000007fu, 0xfffffffeu},
|
||||
{0xfffffffeu, 0x00000002u, 0xb93201bfu, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x3ff51543u, 0x8ca197b1u},
|
||||
{0x00000000u, 0x00000001u, 0x007fffffu, 0x29813b74u},
|
||||
{0x00000000u, 0x00000001u, 0x00ff00ffu, 0x00007fffu},
|
||||
{0x00000000u, 0x00000001u, 0x01010101u, 0xa48d7f36u},
|
||||
{0x00000000u, 0x00000001u, 0x1ef5acc3u, 0x5d780492u},
|
||||
{0x00000000u, 0x00000001u, 0x41f8bfb7u, 0x3f57a9d3u},
|
||||
{0x00000000u, 0x00000001u, 0xfefefefeu, 0x0000007fu},
|
||||
{0x00000000u, 0x00000002u, 0x00ffffffu, 0x80000000u},
|
||||
{0x00000000u, 0x00000002u, 0x7351a059u, 0x00007fffu},
|
||||
{0x00000000u, 0x00000002u, 0xcb50b50fu, 0x7fffffffu},
|
||||
{0x00000000u, 0x0000007fu, 0x0000ffffu, 0x01010101u},
|
||||
{0x00000000u, 0x0000007fu, 0x0ac13011u, 0xffff0000u},
|
||||
{0x00000000u, 0x0000007fu, 0x4b88f735u, 0x000000ffu},
|
||||
{0x00000000u, 0x0000007fu, 0xffffffffu, 0x0000fff0u},
|
||||
{0x00000000u, 0x00000080u, 0x00000000u, 0x00ffffffu},
|
||||
{0x00000000u, 0x00000080u, 0xffffffffu, 0xde945808u},
|
||||
{0x00000000u, 0x000000ffu, 0x000000ffu, 0x00000080u},
|
||||
{0x00000000u, 0x000000ffu, 0x7fffffffu, 0xca9c52c9u},
|
||||
{0x00000000u, 0x000000ffu, 0x80000001u, 0x0000007fu},
|
||||
{0x00000000u, 0x000000ffu, 0xffff0000u, 0x00007fffu},
|
||||
{0x00000000u, 0x000000ffu, 0xffffffffu, 0xffffffffu},
|
||||
{0x00000000u, 0x00007fffu, 0x01010101u, 0xcff6ab04u},
|
||||
{0x00000000u, 0x00007fffu, 0x44e9da39u, 0x63548e6fu},
|
||||
{0x00000000u, 0x00007fffu, 0x4944fa2au, 0xf5524d50u},
|
||||
{0x00000000u, 0x00007fffu, 0xa1dfdb1eu, 0xa9e05a10u},
|
||||
{0x00000000u, 0x00007fffu, 0xffff0000u, 0x01010101u},
|
||||
{0x00000000u, 0x00007fffu, 0xffffffffu, 0x0000007fu},
|
||||
{0x00000000u, 0x0000fff0u, 0x00000080u, 0x01010101u}
|
||||
};
|
||||
constexpr std::uint32_t Expected[32][16] = {
|
||||
{0x01000080u, 0x0080ffffu, 0x01000080u, 0x0080ffffu, 0x00000080u, 0x00000080u, 0x00800080u, 0x0001007fu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0xffffffffu, 0xffff8841u, 0xffffffffu, 0xffff8841u, 0x000003fbu, 0xe37183fbu, 0xffffffffu, 0xfd7c87d0u, 0x0000007fu, 0x0000fffeu, 0x00008038u, 0x0000007fu, 0x0000fffeu, 0x00008038u, 0x000001ffu, 0x007fe371u},
|
||||
{0x017d007fu, 0xffffffffu, 0x007f007fu, 0xffffffffu, 0x0000007fu, 0xffffffffu, 0x000000feu, 0xffffffffu, 0x0000007fu, 0x0000fffeu, 0x0000fffeu, 0x0000007fu, 0x0000007fu, 0x0000007fu, 0x000000ffu, 0x00007fffu},
|
||||
{0xbbf4040fu, 0x012c0227u, 0xbbf4040fu, 0x012c0227u, 0xffffffffu, 0x000002c4u, 0xb93203e6u, 0x0000012cu, 0x000001bfu, 0x0000fffeu, 0x0000fffeu, 0x00000002u, 0x00000002u, 0x000001bfu, 0xfffffffcu, 0xfffffe00u},
|
||||
{0x418116cfu, 0x8e2d993du, 0x418116cfu, 0x8e2d993du, 0x0000018cu, 0x0000018cu, 0x3ff516cfu, 0x8ca1993du, 0x00001543u, 0x00001543u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x02fdffffu, 0x2bfd3df0u, 0x02fcffffu, 0x2bfd3df0u, 0x0000027du, 0x0000027eu, 0x0080027bu, 0x29813df0u, 0x00000001u, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x02fe02fdu, 0x01ff81fcu, 0x02fd02fdu, 0x01fe81fcu, 0x000001feu, 0x000001ffu, 0x00ff02fcu, 0x000081fdu, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x01040105u, 0xa4907f39u, 0x01040105u, 0xa4907f39u, 0x00000004u, 0x00000004u, 0x01010104u, 0xa48d7f39u, 0x00000101u, 0x00000101u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x2176af45u, 0x5ff90713u, 0x2176af45u, 0x5ff90713u, 0x00000282u, 0x00000282u, 0x1ef5af44u, 0x5d780713u, 0x00000001u, 0x0000acc3u, 0x0000acc3u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x44a6c266u, 0x4205ac81u, 0x44a6c266u, 0x4205ac81u, 0x000002afu, 0x000002afu, 0x41f8c265u, 0x3f57ac81u, 0x00000001u, 0x0000bfb7u, 0x0000bfb7u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0xffffffffu, 0x03f70476u, 0xffffffffu, 0x03f70476u, 0x000003f8u, 0x000003f8u, 0xfeff02f5u, 0x00000476u, 0x00000001u, 0x0000fefeu, 0x0000fefeu, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x03feffffu, 0x82fb02fbu, 0x03fcffffu, 0x82fb02fbu, 0x000002fdu, 0x000002ffu, 0x010002fau, 0x800002fbu, 0x00000002u, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x00000002u, 0x00000000u, 0x00000000u},
|
||||
{0x750ca216u, 0x01bb81bau, 0x750ca216u, 0x01bb81bau, 0x000001bdu, 0x000001bdu, 0x7351a214u, 0x000081bau, 0x00000002u, 0x0000a059u, 0x0000a059u, 0x00000000u, 0x00000000u, 0x00000002u, 0x00000000u, 0x00000000u},
|
||||
{0xcd2db6eeu, 0x81dcffffu, 0xcd2db6eeu, 0x81dcffffu, 0x000001dfu, 0x000001dfu, 0xcb50b6ecu, 0x800001dcu, 0x00000002u, 0x0000b50fu, 0x0000b50fu, 0x00000000u, 0x00000000u, 0x00000002u, 0x00000000u, 0x00000000u},
|
||||
{0x027dffffu, 0x0280037eu, 0x01feffffu, 0x028002ffu, 0x000001feu, 0x0000027du, 0x000101fdu, 0x01010280u, 0x0000007fu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x0000007fu, 0x00000000u, 0x00000000u},
|
||||
{0x0c38311du, 0xffff008du, 0x0c38311du, 0xffff008du, 0x0000010cu, 0x000001f6u, 0x0ac1309eu, 0xffff012bu, 0x00003011u, 0x00003011u, 0x00000000u, 0x00000000u, 0x0000007fu, 0x0000007fu, 0x00000000u, 0x00000000u},
|
||||
{0x4d70f934u, 0x0180027fu, 0x4d70f934u, 0x0180027fu, 0x000001ffu, 0x00000267u, 0x4b88f8b5u, 0x0000027fu, 0x0000007fu, 0x0000f735u, 0x0000f735u, 0x00000000u, 0x00000000u, 0x0000007fu, 0x00000000u, 0x00000000u},
|
||||
{0xffffffffu, 0x037dffffu, 0xffffffffu, 0x037dffffu, 0x000003fcu, 0x000003fcu, 0xffffffffu, 0x0001036du, 0x0000007fu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x0000007fu, 0x00000000u, 0x00000000u},
|
||||
{0x00800000u, 0x017fffffu, 0x00000000u, 0x00ffffffu, 0x00000000u, 0x00000080u, 0x00000000u, 0x00ffffffu, 0x00000080u, 0x00000080u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000080u, 0x00000080u},
|
||||
{0xffffffffu, 0xe2105b84u, 0xffffffffu, 0xe2105b84u, 0x000003fcu, 0x000003fcu, 0xffffffffu, 0xde945b84u, 0x00000080u, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x00000080u, 0x00000000u, 0x00000000u},
|
||||
{0x01fe01feu, 0x01fe027eu, 0x00ff01feu, 0x00ff017fu, 0x000000ffu, 0x000001feu, 0x000001feu, 0x0000017fu, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u},
|
||||
{0x837cffffu, 0xcd195546u, 0x837cffffu, 0xcd195546u, 0x0000037cu, 0x0000047cu, 0x8000027cu, 0xca9c5546u, 0x000000ffu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x000000ffu, 0x00000000u, 0x00000000u},
|
||||
{0x80800082u, 0x018001ffu, 0x80800082u, 0x00810100u, 0x00000081u, 0x0000017fu, 0x80000082u, 0x00000100u, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000001u, 0x0000007fu, 0x00000000u},
|
||||
{0xffff01feu, 0x02fd80feu, 0xffff01feu, 0x01fe80feu, 0x000001feu, 0x000001feu, 0xffff00ffu, 0x000081fdu, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x000000ffu, 0x000000ffu},
|
||||
{0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0x000003fcu, 0x000003fcu, 0xffffffffu, 0xffffffffu, 0x000000ffu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x000000ffu, 0x00000000u, 0x00000000u},
|
||||
{0x02020105u, 0xd174ac82u, 0x02020105u, 0xd174ac82u, 0x00000004u, 0x00008100u, 0x0101027fu, 0xcff6ac82u, 0x00007fffu, 0x00007fffu, 0x00000000u, 0x00000000u, 0x00000101u, 0x00000101u, 0x00003fffu, 0x0000007fu},
|
||||
{0x47a0dc79u, 0x64608fd3u, 0x47a0dc79u, 0x64608fd3u, 0x00000240u, 0x000082b6u, 0x44e9db9du, 0x63548f7bu, 0x00007fffu, 0x0000da39u, 0x0000da39u, 0x00000000u, 0x00000000u, 0x00007fffu, 0x00000000u, 0x0000007fu},
|
||||
{0x4b62fbdbu, 0xf6054f65u, 0x4b62fbdbu, 0xf6054f65u, 0x000001b1u, 0x0000821du, 0x4944fc3fu, 0xf5524e03u, 0x00007fffu, 0x0000fa2au, 0x0000fa2au, 0x00000000u, 0x00000000u, 0x00007fffu, 0x0000001fu, 0x00000000u},
|
||||
{0xa415dd97u, 0xab235b4bu, 0xa415dd97u, 0xab235b4bu, 0x00000279u, 0x00008235u, 0xa1dfdc59u, 0xa9e05b53u, 0x00007fffu, 0x0000db1eu, 0x0000db1eu, 0x00000000u, 0x00000000u, 0x00007fffu, 0x00000000u, 0x00000000u},
|
||||
{0xffff01feu, 0x037f0181u, 0xffff01feu, 0x02800181u, 0x000001feu, 0x000080feu, 0xffff0080u, 0x01010280u, 0x00007fffu, 0x00007fffu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00007fffu, 0x00007fffu},
|
||||
{0xffffffffu, 0x027e02fdu, 0xffffffffu, 0x027e02fdu, 0x000003fcu, 0x000082fcu, 0xffffffffu, 0x000002fdu, 0x00007fffu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x00007fffu, 0x00000000u, 0x00000000u},
|
||||
{0x01700100u, 0x03700370u, 0x00800100u, 0x01810181u, 0x00000080u, 0x00010070u, 0x00000100u, 0x01010181u, 0x00000080u, 0x0000fff0u, 0x0000fff0u, 0x00000000u, 0x00000000u, 0x00000080u, 0x0000fff0u, 0x0000fff0u}
|
||||
};
|
||||
constexpr const char* Names[16] = {
|
||||
"qsad_pk_u16_u8 0",
|
||||
"qsad_pk_u16_u8 1",
|
||||
"mqsad_pk_u16_u8 0",
|
||||
"mqsad_pk_u16_u8 1",
|
||||
"mqsad_u32_u8 0",
|
||||
"mqsad_u32_u8 1",
|
||||
"mqsad_u32_u8 2",
|
||||
"mqsad_u32_u8 3",
|
||||
"max3_i16",
|
||||
"max3_u16",
|
||||
"min3_i16",
|
||||
"min3_u16",
|
||||
"med3_i16",
|
||||
"med3_u16",
|
||||
"alignbit_b32",
|
||||
"alignbyte_b32",
|
||||
};
|
||||
|
||||
void Fill(std::uint32_t tid, std::uint32_t* words) {
|
||||
std::copy(std::begin(Rows[tid]), std::end(Rows[tid]), words);
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t bytes) {
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(data);
|
||||
return {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>((address >> 32u) & 0xffffu), bytes, 0x01016facu};
|
||||
}
|
||||
|
||||
std::string Hex(std::uint32_t value) {
|
||||
char text[16];
|
||||
std::snprintf(text, sizeof(text), "0x%08x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Expect(std::uint32_t tid, std::uint32_t actual, std::uint32_t expected, const char* name) {
|
||||
Require(actual == expected, std::string("vop3 integer clamp wide: lane ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected));
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) Fill(tid, &Input[tid * Inputs]);
|
||||
Output.fill(0xdeadbeefu);
|
||||
std::vector<std::uint32_t> userData(8, 0u);
|
||||
const auto input = BufferDescriptor(Input.data(), static_cast<std::uint32_t>(Input.size() * 4u));
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(input.begin(), input.end(), userData.begin());
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
const std::span<const std::uint32_t> code(Code);
|
||||
const std::array<ShaderRecompiler::MemoryRegion, 1> memory{{{reinterpret_cast<std::uintptr_t>(code.data()), std::as_bytes(code)}}};
|
||||
const ShaderRecompiler::ShaderComputeStageInfo compute{{Threads, 1, 1}, 0u, {false, false, false}, false, 1};
|
||||
ShaderRecompiler::RecompileRequest request{
|
||||
{ShaderStage::Compute, reinterpret_cast<std::uintptr_t>(code.data()), code, 0, {}},
|
||||
{32, 0, userData, compute, std::nullopt, std::nullopt, memory},
|
||||
device.Target(),
|
||||
{0, 0, 0, 128}
|
||||
};
|
||||
request.useCache = false;
|
||||
const auto result = ShaderRecompiler::Recompile(request);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void Check() {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const std::uint32_t* in = &Input[tid * Inputs];
|
||||
const std::uint32_t* out = &Output[tid * Results];
|
||||
for (std::uint32_t i = 0; i < 16; ++i) {
|
||||
Expect(tid, out[i], Expected[tid][i], Names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
Run(*device);
|
||||
Check();
|
||||
std::puts("vop3 integer clamp wide tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -90,19 +90,6 @@ void Run(AgcDriver::VulkanDevice& device) {
|
|||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void CheckClampRefused(AgcDriver::VulkanDevice& device) {
|
||||
for (const std::uint32_t opcode : {0x15au, 0x15bu, 0x15cu, 0x171u}) {
|
||||
alignas(256) const std::array<std::uint32_t, 3> code{0xd400800au | (opcode << 16u), 0x041a0b04u, 0xbf810000u};
|
||||
std::string refusal;
|
||||
try {
|
||||
static_cast<void>(Compile(device, code));
|
||||
} catch (const std::exception& error) {
|
||||
refusal = error.what();
|
||||
}
|
||||
Require(refusal.find("VOP3 source modifiers are not implemented") != std::string::npos, "VOP3 opcode " + Hex(opcode) + " with clamp was not refused");
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t Sad(std::uint32_t lhs, std::uint32_t rhs, std::uint32_t fieldBits, bool masked) {
|
||||
const std::uint32_t fieldMask = (1u << fieldBits) - 1u;
|
||||
std::uint32_t sum = 0u;
|
||||
|
|
@ -154,7 +141,6 @@ int main() {
|
|||
FillInput();
|
||||
Run(*device);
|
||||
Check();
|
||||
CheckClampRefused(*device);
|
||||
std::puts("vop3 sad tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
|
|
|||
|
|
@ -752,8 +752,26 @@ bool isNativeVop3AlignOpcode(RdnaOpcode opcode) {
|
|||
return opcode == RdnaOpcode::VAlignbitB32 || opcode == RdnaOpcode::VAlignbyteB32;
|
||||
}
|
||||
|
||||
bool usesSignedSaturateClamp(RdnaOpcode opcode) {
|
||||
return opcode == RdnaOpcode::VAddNcI32 || opcode == RdnaOpcode::VSubNcI32;
|
||||
bool usesIntegerSaturateClamp(RdnaOpcode opcode) {
|
||||
switch (opcode) {
|
||||
case RdnaOpcode::VAddNcI32:
|
||||
case RdnaOpcode::VSubNcI32:
|
||||
case RdnaOpcode::VMadU32U24:
|
||||
case RdnaOpcode::VMadI32I24:
|
||||
case RdnaOpcode::VMadU16:
|
||||
case RdnaOpcode::VMadI16:
|
||||
case RdnaOpcode::VMadU32U16:
|
||||
case RdnaOpcode::VMadI32I16:
|
||||
case RdnaOpcode::VSadU8:
|
||||
case RdnaOpcode::VSadHiU8:
|
||||
case RdnaOpcode::VSadU16:
|
||||
case RdnaOpcode::VSadU32:
|
||||
case RdnaOpcode::VMsadU8:
|
||||
case RdnaOpcode::VQsadPkU16U8:
|
||||
case RdnaOpcode::VMqsadPkU16U8:
|
||||
case RdnaOpcode::VMqsadU32U8: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isCubeOpcode(RdnaOpcode opcode) {
|
||||
|
|
@ -1941,7 +1959,7 @@ bool isF32DivisionStepOpcode(RdnaOpcode opcode) {
|
|||
}
|
||||
|
||||
bool supportsNativeVop3Clamp(RdnaOpcode opcode) {
|
||||
return supportsNativeVop3ResultModifiers(opcode) || usesInexactClampControl(opcode) || usesSignedSaturateClamp(opcode) ||
|
||||
return supportsNativeVop3ResultModifiers(opcode) || usesInexactClampControl(opcode) || usesIntegerSaturateClamp(opcode) ||
|
||||
isF32DivisionStepOpcode(opcode) || isCubeOpcode(opcode);
|
||||
}
|
||||
|
||||
|
|
@ -1959,13 +1977,13 @@ void checkNativeVop3Modifiers(RdnaOpcode opcode, bool permlane, bool carryInOut,
|
|||
return;
|
||||
}
|
||||
if (isNativeVop3I16TernaryOpcode(opcode)) {
|
||||
if (abs != 0u || clamp != 0u || omod != 0u || neg != 0u) {
|
||||
if (abs != 0u || omod != 0u || neg != 0u) {
|
||||
throw std::invalid_argument("VOP3 source modifiers are not implemented");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isNativeVop3AlignOpcode(opcode)) {
|
||||
if (abs != 0u || clamp != 0u || omod != 0u || neg != 0u) {
|
||||
if (abs != 0u || omod != 0u || neg != 0u) {
|
||||
throw std::invalid_argument("VOP3 source modifiers are not implemented");
|
||||
}
|
||||
return;
|
||||
|
|
@ -1983,7 +2001,7 @@ void checkNativeVop3Modifiers(RdnaOpcode opcode, bool permlane, bool carryInOut,
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (usesSignedSaturateClamp(opcode)) {
|
||||
if (usesIntegerSaturateClamp(opcode)) {
|
||||
if (abs != 0u || opSel != 0u || omod != 0u || neg != 0u) {
|
||||
throw std::invalid_argument("VOP3 source modifiers are not implemented");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,6 +193,8 @@ private:
|
|||
bool integer16Shift(const RdnaInstruction& inst, IrOpcode opcode, bool arithmetic);
|
||||
bool integer16Binary(const RdnaInstruction& inst, IrOpcode opcode, bool sign);
|
||||
bool integer16Mad(const RdnaInstruction& inst, bool sign, bool wide);
|
||||
IrU32 saturateU16Result(const RdnaInstruction& inst, const IrU32& value, bool sign);
|
||||
IrU32 wideAdd(const RdnaInstruction& inst, const IrU32& low, const IrU32& high, const IrU32& addend, bool sign);
|
||||
bool vAddSubNcI32(const RdnaInstruction& inst, bool subtract);
|
||||
bool integer16Ternary(const RdnaInstruction& inst, IrOpcode opcode, bool sign);
|
||||
bool vMed3I16(const RdnaInstruction& inst);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,33 @@ bool TranslationContext::integer16Binary(const RdnaInstruction& inst, IrOpcode o
|
|||
return true;
|
||||
}
|
||||
|
||||
IrU32 TranslationContext::saturateU16Result(const RdnaInstruction& inst, const IrU32& value, bool sign) {
|
||||
if (!inst.destination.clamp) {
|
||||
return value;
|
||||
}
|
||||
if (!sign) {
|
||||
return IrU32(ir.Emit(IrOpcode::UMin32, IrType::U32, {&value.Value(), &ir.Constant(0xffffu)}));
|
||||
}
|
||||
const IrU32 upper(ir.Emit(IrOpcode::SMin32, IrType::U32, {&value.Value(), &ir.Constant(0x7fffu)}));
|
||||
return IrU32(ir.Emit(IrOpcode::SMax32, IrType::U32, {&upper.Value(), &ir.Constant(0xffff8000u)}));
|
||||
}
|
||||
|
||||
IrU32 TranslationContext::wideAdd(const RdnaInstruction& inst, const IrU32& low, const IrU32& high, const IrU32& addend, bool sign) {
|
||||
const IrU32 sum(ir.IAdd(low.Value(), addend.Value()));
|
||||
if (!inst.destination.clamp) {
|
||||
return sum;
|
||||
}
|
||||
const IrU32 carry(ir.Select(ir.ULessThan(sum.Value(), low.Value()), ir.Constant(1u), ir.Constant(0u)));
|
||||
IrU32 top(ir.IAdd(high.Value(), carry.Value()));
|
||||
if (!sign) {
|
||||
return IrU32(ir.Select(ir.INotEqual(top.Value(), ir.Constant(0u)), ir.Constant(0xffffffffu), sum.Value()));
|
||||
}
|
||||
top = IrU32(ir.IAdd(top.Value(), ir.ShiftRightArithmetic(addend.Value(), ir.Constant(31u))));
|
||||
const IrU1 overflow(ir.INotEqual(top.Value(), ir.ShiftRightArithmetic(sum.Value(), ir.Constant(31u))));
|
||||
IrValue& saturated = ir.BitwiseXor(ir.ShiftRightArithmetic(top.Value(), ir.Constant(31u)), ir.Constant(0x7fffffffu));
|
||||
return IrU32(ir.Select(overflow.Value(), saturated, sum.Value()));
|
||||
}
|
||||
|
||||
bool TranslationContext::vMed3I16(const RdnaInstruction& inst) {
|
||||
const IrU32 first = readU16AsU32(sourceAt(inst, 0u), true);
|
||||
const IrU32 second = readU16AsU32(sourceAt(inst, 1u), true);
|
||||
|
|
@ -46,11 +73,14 @@ bool TranslationContext::integer16Ternary(const RdnaInstruction& inst, IrOpcode
|
|||
bool TranslationContext::integer16Mad(const RdnaInstruction& inst, bool sign, bool wide) {
|
||||
const IrU32 lhs = readU16AsU32(sourceAt(inst, 0u), sign);
|
||||
const IrU32 rhs = readU16AsU32(sourceAt(inst, 1u), sign);
|
||||
const IrU32 addend = wide ? readU32(sourceAt(inst, 2u)) : readU16AsU32(sourceAt(inst, 2u), sign);
|
||||
const IrU32 result(ir.IAdd(ir.IMul(lhs.Value(), rhs.Value()), addend.Value()));
|
||||
const IrU32 product(ir.IMul(lhs.Value(), rhs.Value()));
|
||||
if (wide) {
|
||||
const IrU32 high(sign ? ir.ShiftRightArithmetic(product.Value(), ir.Constant(31u)) : ir.Constant(0u));
|
||||
const IrU32 result = wideAdd(inst, product, high, readU32(sourceAt(inst, 2u)), sign);
|
||||
writeOperand(inst.destination, &result.Value());
|
||||
} else {
|
||||
const IrU32 addend = readU16AsU32(sourceAt(inst, 2u), sign);
|
||||
const IrU32 result = saturateU16Result(inst, IrU32(ir.IAdd(product.Value(), addend.Value())), sign);
|
||||
write16Bits(inst.destination, IrU32(ir.BitwiseAnd(result.Value(), ir.Constant(0xffffu))));
|
||||
}
|
||||
return true;
|
||||
|
|
@ -323,7 +353,8 @@ bool TranslationContext::integer24(const RdnaInstruction& inst, bool sign, bool
|
|||
result = IrU32(ir.Select(ir.INotEqual(top.Value(), expected), saturated, result.Value()));
|
||||
}
|
||||
if (addend) {
|
||||
result = IrU32(ir.IAdd(result.Value(), readU32(sourceAt(inst, 2u)).Value()));
|
||||
const IrU32 productHigh(inst.destination.clamp ? ir.Emit(sign ? IrOpcode::SMulHi : IrOpcode::UMulHi, IrType::U32, {&lhs.Value(), &rhs.Value()}) : ir.Constant(0u));
|
||||
result = wideAdd(inst, result, productHigh, readU32(sourceAt(inst, 2u)), sign);
|
||||
}
|
||||
writeOperand(inst.destination, &result.Value());
|
||||
return true;
|
||||
|
|
@ -377,7 +408,7 @@ bool TranslationContext::vSadU32(const RdnaInstruction& inst) {
|
|||
const IrU32 lo(ir.Emit(IrOpcode::UMin32, IrType::U32, {&lhs.Value(), &rhs.Value()}));
|
||||
const IrU32 hi(ir.Emit(IrOpcode::UMax32, IrType::U32, {&lhs.Value(), &rhs.Value()}));
|
||||
const IrU32 addend = readU32(sourceAt(inst, 2u));
|
||||
const IrU32 result(ir.IAdd(ir.ISub(hi.Value(), lo.Value()), addend.Value()));
|
||||
const IrU32 result = wideAdd(inst, IrU32(ir.ISub(hi.Value(), lo.Value())), IrU32(ir.Constant(0u)), addend, false);
|
||||
writeOperand(inst.destination, &result.Value());
|
||||
return true;
|
||||
}
|
||||
|
|
@ -405,7 +436,7 @@ bool TranslationContext::subwordSad(const RdnaInstruction& inst, std::uint32_t f
|
|||
sum = IrU32(ir.ShiftLeftLogical(sum.Value(), ir.Constant(sumShift)));
|
||||
}
|
||||
const IrU32 addend = readU32(sourceAt(inst, 2u));
|
||||
const IrU32 result(ir.IAdd(sum.Value(), addend.Value()));
|
||||
const IrU32 result = wideAdd(inst, sum, IrU32(ir.Constant(0u)), addend, false);
|
||||
writeOperand(inst.destination, &result.Value());
|
||||
return true;
|
||||
}
|
||||
|
|
@ -423,14 +454,15 @@ bool TranslationContext::vQsadU8(const RdnaInstruction& inst, bool masked, bool
|
|||
const std::array<IrU32, 2> accumulator = readU32Pair(sourceAt(inst, 2u));
|
||||
if (wide) {
|
||||
const std::array<IrU32, 2> accumulatorHigh = readU32Pair(offsetOperand(sourceAt(inst, 2u), 2u));
|
||||
writeU32Pair(inst.destination, {IrU32(ir.IAdd(accumulator[0].Value(), sad(0u).Value())), IrU32(ir.IAdd(accumulator[1].Value(), sad(8u).Value()))});
|
||||
const IrU32 zero(ir.Constant(0u));
|
||||
writeU32Pair(inst.destination, {wideAdd(inst, sad(0u), zero, accumulator[0], false), wideAdd(inst, sad(8u), zero, accumulator[1], false)});
|
||||
writeU32Pair(offsetOperand(inst.destination, 2u),
|
||||
{IrU32(ir.IAdd(accumulatorHigh[0].Value(), sad(16u).Value())), IrU32(ir.IAdd(accumulatorHigh[1].Value(), sad(24u).Value()))});
|
||||
{wideAdd(inst, sad(16u), zero, accumulatorHigh[0], false), wideAdd(inst, sad(24u), zero, accumulatorHigh[1], false)});
|
||||
return true;
|
||||
}
|
||||
const auto packed = [&](const IrU32& addend, std::uint32_t shift) {
|
||||
const IrU32 low(ir.IAdd(addend.Value(), sad(shift).Value()));
|
||||
const IrU32 high(ir.IAdd(ir.ShiftRightLogical(addend.Value(), ir.Constant(16u)), sad(shift + 8u).Value()));
|
||||
const IrU32 low = saturateU16Result(inst, IrU32(ir.IAdd(ir.BitwiseAnd(addend.Value(), ir.Constant(0xffffu)), sad(shift).Value())), false);
|
||||
const IrU32 high = saturateU16Result(inst, IrU32(ir.IAdd(ir.ShiftRightLogical(addend.Value(), ir.Constant(16u)), sad(shift + 8u).Value())), false);
|
||||
return IrU32(ir.BitwiseOr(ir.BitwiseAnd(low.Value(), ir.Constant(0xffffu)), ir.ShiftLeftLogical(high.Value(), ir.Constant(16u))));
|
||||
};
|
||||
writeU32Pair(inst.destination, {packed(accumulator[0], 0u), packed(accumulator[1], 16u)});
|
||||
|
|
|
|||
Loading…
Reference in New Issue