diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/LdsAtomics64.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/LdsAtomics64.cpp index 3ca9e67f2c71..e6bf5cd895fb 100644 --- a/core/libs/prx/libSceAgcDriver/tests/execution/LdsAtomics64.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/execution/LdsAtomics64.cpp @@ -90,7 +90,12 @@ constexpr std::uint64_t Sign = 0x8000000000000000ull; bool Nan(std::uint64_t bits) { return (bits & ~Sign) > 0x7ff0000000000000ull; } std::uint64_t OrderKey(std::uint64_t bits) { return (bits & Sign) != 0u ? ~bits : bits | Sign; } +constexpr std::uint64_t Quiet = 0x0008000000000000ull; + +bool Signaling(std::uint64_t bits) { return Nan(bits) && (bits & Quiet) == 0u; } std::uint64_t MinMax(std::uint64_t old, std::uint64_t data, bool max) { + if (Signaling(data)) return data | Quiet; + if (Signaling(old)) return old | Quiet; if (Nan(old)) return data; if (Nan(data)) return old; return (max ? OrderKey(data) > OrderKey(old) : OrderKey(data) < OrderKey(old)) ? data : old; @@ -114,7 +119,7 @@ void Fill(std::uint32_t tid, std::uint32_t* words) { std::array values{}; if (kind == 0u) values = {seed, seed * 0xbf58476d1ce4e5b9ull, seed ^ 0x94d049bb133111ebull}; if (kind == 1u) values = {tid % 7u, (tid * 3u) % 7u, tid % 5u}; - if (kind == 2u) values = {floats[tid % 12u], floats[(tid / 2u + 3u) % 12u], floats[(tid + 5u) % 12u]}; + if (kind == 2u) values = {floats[tid % 12u], floats[(tid / 4u + 9u) % 12u], floats[(tid + 5u) % 12u]}; if (kind == 3u) values = {seed, (tid & 4u) != 0u ? seed : seed + 0x100000000ull, seed * 3u}; for (std::uint32_t i = 0; i < values.size(); ++i) { words[i * 2u] = static_cast(values[i]); diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/LdsFloatAtomicModes.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/LdsFloatAtomicModes.cpp new file mode 100644 index 000000000000..0233d2c12af7 --- /dev/null +++ b/core/libs/prx/libSceAgcDriver/tests/execution/LdsFloatAtomicModes.cpp @@ -0,0 +1,480 @@ +#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp" +#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp" +#include "Recompiler.hpp" +#include "VulkanTestDevice.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using AgcDriver::Graphics::Require; +using ShaderRecompiler::ShaderStage; + +constexpr std::uint32_t Threads = 32; +constexpr std::uint32_t Inputs = 8; +constexpr std::uint32_t Results = 32; +constexpr std::uint32_t Columns = 27; +alignas(256) std::array Input{}; +alignas(256) std::array Output{}; + +alignas(256) constexpr std::array Code{ + 0x34020085u, 0x34040087u, 0xe0381000u, 0x80000401u, 0xe0381010u, 0x80000801u, 0xbf8c3f70u, 0x7e180280u, + 0x7e1a0280u, 0x7e1c0280u, 0x7e1e0280u, 0x7e200280u, 0x7e220280u, 0x7e240280u, 0x7e260280u, 0x7e280280u, + 0x7e2a0280u, 0x7e2c0280u, 0x7e2e0280u, 0x7e300280u, 0x7e320280u, 0x7e340280u, 0x7e360280u, 0x7e380280u, + 0x7e3a0280u, 0x7e3c0280u, 0x7e3e0280u, 0x7e400280u, 0x7e420280u, 0x7e440280u, 0x7e460280u, 0x7e480280u, + 0x7e4a0280u, 0x7e4c0280u, 0x7e4e0280u, 0x7e5002ffu, 0x45464748u, 0x7e5202ffu, 0x41424344u, 0x34060083u, + 0xd8340000u, 0x00000403u, 0xbf8cc07fu, 0xd8c80000u, 0x0d000503u, 0xbf8cc07fu, 0xd8d80000u, 0x0c000003u, + 0xbf8cc07fu, 0xd8340000u, 0x00000403u, 0xbf8cc07fu, 0xd8cc0000u, 0x0f000503u, 0xbf8cc07fu, 0xd8d80000u, + 0x0e000003u, 0xbf8cc07fu, 0xd8340000u, 0x00000403u, 0xbf8cc07fu, 0xd8c40000u, 0x110a0503u, 0xbf8cc07fu, + 0xd8d80000u, 0x10000003u, 0xbf8cc07fu, 0xd8340000u, 0x00000403u, 0xbf8cc07fu, 0xd8480000u, 0x00000503u, + 0xbf8cc07fu, 0xd8d80000u, 0x12000003u, 0xbf8cc07fu, 0xd8340000u, 0x00000403u, 0xbf8cc07fu, 0xd84c0000u, + 0x00000503u, 0xbf8cc07fu, 0xd8d80000u, 0x13000003u, 0xbf8cc07fu, 0xd8340000u, 0x00000403u, 0xbf8cc07fu, + 0xd8440000u, 0x000a0503u, 0xbf8cc07fu, 0xd8d80000u, 0x14000003u, 0xbf8cc07fu, 0xd9340000u, 0x00000603u, + 0xbf8cc07fu, 0xd9c80000u, 0x18000803u, 0xbf8cc07fu, 0xd9d80000u, 0x16000003u, 0xbf8cc07fu, 0xd9340000u, + 0x00000603u, 0xbf8cc07fu, 0xd9cc0000u, 0x1c000803u, 0xbf8cc07fu, 0xd9d80000u, 0x1a000003u, 0xbf8cc07fu, + 0xd9340000u, 0x00000603u, 0xbf8cc07fu, 0xd9480000u, 0x00000803u, 0xbf8cc07fu, 0xd9d80000u, 0x1e000003u, + 0xbf8cc07fu, 0xd9340000u, 0x00000603u, 0xbf8cc07fu, 0xd94c0000u, 0x00000803u, 0xbf8cc07fu, 0xd9d80000u, + 0x20000003u, 0xbf8cc07fu, 0xd9340000u, 0x00000603u, 0xbf8cc07fu, 0xd9c40000u, 0x24280803u, 0xbf8cc07fu, + 0xd9d80000u, 0x22000003u, 0xbf8cc07fu, 0xd9340000u, 0x00000603u, 0xbf8cc07fu, 0xd9440000u, 0x00280803u, + 0xbf8cc07fu, 0xd9d80000u, 0x26000003u, 0xbf8cc07fu, 0xe0781000u, 0x80010c02u, 0xe0781010u, 0x80011002u, + 0xe0781020u, 0x80011402u, 0xe0781030u, 0x80011802u, 0xe0781040u, 0x80011c02u, 0xe0781050u, 0x80012002u, + 0xe0781060u, 0x80012402u, 0xbf810000u, +}; + +constexpr std::uint32_t Rows[32][8] = { + {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u}, + {0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x45464748u, 0x00000000u}, + {0x80000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u}, + {0x3f800000u, 0xbf800000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0xbff00000u, 0x45464748u, 0x00000000u}, + {0xbf800000u, 0x3f800000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x45464748u, 0x00000000u}, + {0x7f800000u, 0xff800000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0xfff00000u, 0x45464748u, 0x00000000u}, + {0xff800000u, 0x7f800000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u}, + {0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x45464748u, 0x00000000u}, + {0x80000001u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000000u, 0x80000000u, 0x45464748u, 0x00000000u}, + {0x00000001u, 0x80000001u, 0x00000001u, 0x00000000u, 0x00000001u, 0x80000000u, 0x45464748u, 0x00000000u}, + {0x3f800000u, 0x00000001u, 0x00000000u, 0x3ff00000u, 0x00000001u, 0x00000000u, 0x45464748u, 0x00000000u}, + {0x7fc00000u, 0x3f800000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x45464748u, 0x00000000u}, + {0x3f800000u, 0x7fc00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x45464748u, 0x00000000u}, + {0x7fc00000u, 0x7fc00123u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x45464748u, 0x00000000u}, + {0x7fc00123u, 0x7fc00000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x45464748u, 0x00000000u}, + {0xffc00000u, 0x7fc00000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0x7ff80000u, 0x45464748u, 0x00000000u}, + {0x7fc00000u, 0x7fc00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x45464748u, 0x00000000u}, + {0x7f800001u, 0x3f800000u, 0x00000001u, 0x7ff00000u, 0x00000000u, 0x3ff00000u, 0x45464748u, 0x00000000u}, + {0x3f800000u, 0x7f800001u, 0x00000000u, 0x3ff00000u, 0x00000001u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0x7f800001u, 0x7fc00000u, 0x00000001u, 0x7ff00000u, 0x00000000u, 0x7ff80000u, 0x45464748u, 0x00000000u}, + {0x7fc00000u, 0x7f800001u, 0x00000000u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0x7f800001u, 0x7f800123u, 0x00000001u, 0x7ff00000u, 0x00000123u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0x7f800123u, 0x7f800001u, 0x00000123u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0xff800001u, 0x7f800001u, 0x00000001u, 0xfff00000u, 0x00000001u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0x7f800001u, 0xff800001u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0xfff00000u, 0x45464748u, 0x00000000u}, + {0x00000001u, 0x7f800001u, 0x00000001u, 0x00000000u, 0x00000001u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0x7f800001u, 0x00000001u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x00000000u, 0x45464748u, 0x00000000u}, + {0x7f800000u, 0x7f800001u, 0x00000000u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0x7f800001u, 0x7f800000u, 0x00000001u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0x00000000u, 0x7f800001u, 0x00000000u, 0x00000000u, 0x00000001u, 0x7ff00000u, 0x45464748u, 0x00000000u}, + {0x7f800001u, 0x00000000u, 0x00000001u, 0x7ff00000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u} +}; + +constexpr std::uint32_t ExpectedTitles[32][Columns] = { + {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u}, + {0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u, 0x80000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, + 0x80000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u}, + {0x80000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x45464748u, 0x80000000u, 0x80000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, + 0x80000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x80000000u, 0x45464748u, 0x41424344u}, + {0xbf800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0xbf800000u, 0x3f800000u, 0x3f800000u, + 0x00000000u, 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, + 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0xbf800000u, 0xbf800000u, 0x3f800000u, 0xbf800000u, 0xbf800000u, 0xbf800000u, 0xbf800000u, 0x3f800000u, 0xbf800000u, + 0x00000000u, 0xbff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, + 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0xbff00000u}, + {0xff800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0xff800000u, 0x7f800000u, 0x7f800000u, + 0x00000000u, 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, + 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u}, + {0xff800000u, 0xff800000u, 0x7f800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0x7f800000u, 0xff800000u, + 0x00000000u, 0xfff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, + 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0xfff00000u}, + {0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x45464748u, 0x00000001u, 0x00000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, + 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u}, + {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, + 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x80000000u, 0x80000001u, 0x80000000u, 0x80000001u, 0x45464748u, 0x80000001u, 0x80000000u, 0x80000000u, 0x45464748u, + 0x00000001u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000000u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000001u, + 0x80000000u, 0x00000000u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000001u, 0x80000000u}, + {0x80000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x45464748u, 0x00000001u, 0x80000000u, 0x00000000u, 0x45464748u, + 0x00000001u, 0x80000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, + 0x80000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u}, + {0x00000000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, + 0x00000001u, 0x00000000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000001u, + 0x00000000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0x3f800000u, 0x7fc00000u, 0x3f800000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x3f800000u, 0x3f800000u, 0x7fc00000u, + 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, + 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, + 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, + 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0x7fc00123u, 0x7fc00000u, 0x7fc00123u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00123u, 0x7fc00123u, 0x7fc00000u, + 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, + 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x7fc00000u, 0x7fc00123u, 0x7fc00000u, 0x7fc00123u, 0x7fc00123u, 0x7fc00123u, 0x7fc00000u, 0x7fc00000u, 0x7fc00123u, + 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, + 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000123u, 0x7ff80000u}, + {0x7fc00000u, 0xffc00000u, 0x7fc00000u, 0xffc00000u, 0xffc00000u, 0xffc00000u, 0x7fc00000u, 0x7fc00000u, 0xffc00000u, + 0x00000000u, 0x7ff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, + 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0xfff80000u}, + {0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, + 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, + 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x3f800000u, 0x7fc00001u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x7fc00001u, 0x7fc00001u, 0x3f800000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x7fc00000u, 0x7fc00001u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x7fc00123u, 0x7f800001u, 0x7fc00123u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00123u, 0x7fc00123u, 0x7f800001u, + 0x00000123u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000123u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000123u, + 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x7f800123u, 0x7fc00001u, 0x7f800123u, 0x7f800123u, 0x7f800123u, 0x7fc00001u, 0x7fc00001u, 0x7f800123u, + 0x00000001u, 0x7ff80000u, 0x00000123u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000123u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000123u, 0x7ff00000u, 0x00000123u, 0x7ff00000u, 0x00000123u, 0x7ff00000u}, + {0x7fc00001u, 0xff800001u, 0x7fc00001u, 0xff800001u, 0xff800001u, 0xff800001u, 0x7fc00001u, 0x7fc00001u, 0xff800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0xfff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0xfff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0xfff00000u, 0x00000001u, 0xfff00000u, 0x00000001u, 0xfff00000u}, + {0xffc00001u, 0x7f800001u, 0xffc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0xffc00001u, 0xffc00001u, 0x7f800001u, + 0x00000001u, 0xfff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0xfff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0xfff80000u, 0x00000001u, 0xfff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x00000001u, 0x7fc00001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x7fc00001u, 0x7fc00001u, 0x00000001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x00000000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x7f800000u, 0x7fc00001u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7fc00001u, 0x7fc00001u, 0x7f800000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x00000000u, 0x7fc00001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x7fc00001u, 0x7fc00001u, 0x00000000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x00000000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u} +}; + +constexpr std::uint32_t ExpectedKept[32][Columns] = { + {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u}, + {0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u, 0x80000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, + 0x80000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u}, + {0x80000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x45464748u, 0x80000000u, 0x80000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, + 0x80000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x80000000u, 0x45464748u, 0x41424344u}, + {0xbf800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0xbf800000u, 0x3f800000u, 0x3f800000u, + 0x00000000u, 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, + 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0xbf800000u, 0xbf800000u, 0x3f800000u, 0xbf800000u, 0xbf800000u, 0xbf800000u, 0xbf800000u, 0x3f800000u, 0xbf800000u, + 0x00000000u, 0xbff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, + 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0xbff00000u}, + {0xff800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0xff800000u, 0x7f800000u, 0x7f800000u, + 0x00000000u, 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, + 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u}, + {0xff800000u, 0xff800000u, 0x7f800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0x7f800000u, 0xff800000u, + 0x00000000u, 0xfff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, + 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0xfff00000u}, + {0x00000000u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000001u, + 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, + 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u}, + {0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, + 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x80000001u, 0x80000001u, 0x80000000u, 0x80000001u, 0x80000001u, 0x80000001u, 0x80000001u, 0x80000000u, 0x80000001u, + 0x00000001u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000000u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000001u, + 0x80000000u, 0x00000000u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000001u, 0x80000000u}, + {0x80000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x80000001u, 0x00000001u, 0x00000001u, + 0x00000001u, 0x80000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, + 0x80000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u}, + {0x00000001u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x00000001u, 0x3f800000u, 0x3f800000u, + 0x00000001u, 0x00000000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000001u, + 0x00000000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0x3f800000u, 0x7fc00000u, 0x3f800000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x3f800000u, 0x3f800000u, 0x7fc00000u, + 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, + 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, + 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, + 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0x7fc00123u, 0x7fc00000u, 0x7fc00123u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00123u, 0x7fc00123u, 0x7fc00000u, + 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, + 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x7fc00000u, 0x7fc00123u, 0x7fc00000u, 0x7fc00123u, 0x7fc00123u, 0x7fc00123u, 0x7fc00000u, 0x7fc00000u, 0x7fc00123u, + 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, + 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000123u, 0x7ff80000u}, + {0x7fc00000u, 0xffc00000u, 0x7fc00000u, 0xffc00000u, 0xffc00000u, 0xffc00000u, 0x7fc00000u, 0x7fc00000u, 0xffc00000u, + 0x00000000u, 0x7ff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, + 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0xfff80000u}, + {0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, + 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, + 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x3f800000u, 0x7fc00001u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x7fc00001u, 0x7fc00001u, 0x3f800000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x7fc00000u, 0x7fc00001u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x7fc00123u, 0x7f800001u, 0x7fc00123u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00123u, 0x7fc00123u, 0x7f800001u, + 0x00000123u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000123u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000123u, + 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x7f800123u, 0x7fc00001u, 0x7f800123u, 0x7f800123u, 0x7f800123u, 0x7fc00001u, 0x7fc00001u, 0x7f800123u, + 0x00000001u, 0x7ff80000u, 0x00000123u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000123u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000123u, 0x7ff00000u, 0x00000123u, 0x7ff00000u, 0x00000123u, 0x7ff00000u}, + {0x7fc00001u, 0xff800001u, 0x7fc00001u, 0xff800001u, 0xff800001u, 0xff800001u, 0x7fc00001u, 0x7fc00001u, 0xff800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0xfff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0xfff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0xfff00000u, 0x00000001u, 0xfff00000u, 0x00000001u, 0xfff00000u}, + {0xffc00001u, 0x7f800001u, 0xffc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0xffc00001u, 0xffc00001u, 0x7f800001u, + 0x00000001u, 0xfff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0xfff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0xfff80000u, 0x00000001u, 0xfff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x00000001u, 0x7fc00001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x7fc00001u, 0x7fc00001u, 0x00000001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x00000000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x7f800000u, 0x7fc00001u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7fc00001u, 0x7fc00001u, 0x7f800000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x00000000u, 0x7fc00001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x7fc00001u, 0x7fc00001u, 0x00000000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x00000000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u} +}; + +constexpr std::uint32_t ExpectedFlushed[32][Columns] = { + {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u}, + {0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u, 0x80000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, + 0x80000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u}, + {0x80000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x45464748u, 0x80000000u, 0x80000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, + 0x80000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x80000000u, 0x45464748u, 0x41424344u}, + {0xbf800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0xbf800000u, 0x3f800000u, 0x3f800000u, + 0x00000000u, 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, + 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0xbf800000u, 0xbf800000u, 0x3f800000u, 0xbf800000u, 0xbf800000u, 0xbf800000u, 0xbf800000u, 0x3f800000u, 0xbf800000u, + 0x00000000u, 0xbff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, + 0xbff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0xbff00000u, 0x00000000u, 0xbff00000u}, + {0xff800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0xff800000u, 0x7f800000u, 0x7f800000u, + 0x00000000u, 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, + 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u}, + {0xff800000u, 0xff800000u, 0x7f800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u, 0x7f800000u, 0xff800000u, + 0x00000000u, 0xfff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, + 0xfff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0xfff00000u, 0x00000000u, 0xfff00000u}, + {0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x45464748u, 0x00000001u, 0x00000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000001u, 0x00000000u, 0x45464748u, 0x41424344u}, + {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u}, + {0x80000000u, 0x80000001u, 0x80000000u, 0x80000001u, 0x45464748u, 0x80000001u, 0x80000000u, 0x80000000u, 0x45464748u, + 0x00000000u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000000u, 0x80000000u, 0x00000001u, 0x80000000u, 0x00000000u, + 0x80000000u, 0x00000000u, 0x80000000u, 0x45464748u, 0x41424344u, 0x00000001u, 0x80000000u, 0x45464748u, 0x41424344u}, + {0x80000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x45464748u, 0x00000001u, 0x80000000u, 0x00000000u, 0x45464748u, + 0x00000000u, 0x80000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, + 0x80000000u, 0x00000000u, 0x00000000u, 0x45464748u, 0x41424344u, 0x00000001u, 0x00000000u, 0x45464748u, 0x41424344u}, + {0x00000000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, + 0x00000000u, 0x00000000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, + 0x00000000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0x3f800000u, 0x7fc00000u, 0x3f800000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x3f800000u, 0x3f800000u, 0x7fc00000u, + 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, + 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, + 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, + 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0x7fc00123u, 0x7fc00000u, 0x7fc00123u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00123u, 0x7fc00123u, 0x7fc00000u, + 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, + 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x7fc00000u, 0x7fc00123u, 0x7fc00000u, 0x7fc00123u, 0x7fc00123u, 0x7fc00123u, 0x7fc00000u, 0x7fc00000u, 0x7fc00123u, + 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000000u, + 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000123u, 0x7ff80000u}, + {0x7fc00000u, 0xffc00000u, 0x7fc00000u, 0xffc00000u, 0xffc00000u, 0xffc00000u, 0x7fc00000u, 0x7fc00000u, 0xffc00000u, + 0x00000000u, 0x7ff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, + 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0xfff80000u, 0x00000000u, 0xfff80000u}, + {0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, + 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, + 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x3f800000u, 0x7fc00001u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x7fc00001u, 0x7fc00001u, 0x3f800000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u, 0x00000000u, 0x3ff00000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x7fc00000u, 0x7fc00001u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00001u, 0x7fc00001u, 0x7fc00000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u, 0x00000000u, 0x7ff80000u}, + {0x7fc00123u, 0x7f800001u, 0x7fc00123u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00123u, 0x7fc00123u, 0x7f800001u, + 0x00000123u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000123u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000123u, + 0x7ff80000u, 0x00000123u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x7f800123u, 0x7fc00001u, 0x7f800123u, 0x7f800123u, 0x7f800123u, 0x7fc00001u, 0x7fc00001u, 0x7f800123u, + 0x00000001u, 0x7ff80000u, 0x00000123u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000123u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000123u, 0x7ff00000u, 0x00000123u, 0x7ff00000u, 0x00000123u, 0x7ff00000u}, + {0x7fc00001u, 0xff800001u, 0x7fc00001u, 0xff800001u, 0xff800001u, 0xff800001u, 0x7fc00001u, 0x7fc00001u, 0xff800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0xfff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0xfff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0xfff00000u, 0x00000001u, 0xfff00000u, 0x00000001u, 0xfff00000u}, + {0xffc00001u, 0x7f800001u, 0xffc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0xffc00001u, 0xffc00001u, 0x7f800001u, + 0x00000001u, 0xfff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0xfff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0xfff80000u, 0x00000001u, 0xfff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x00000001u, 0x7fc00001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x7fc00001u, 0x7fc00001u, 0x00000001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x00000000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000001u, 0x00000000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x7f800000u, 0x7fc00001u, 0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7fc00001u, 0x7fc00001u, 0x7f800000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u, 0x00000000u, 0x7ff00000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u}, + {0x7fc00001u, 0x00000000u, 0x7fc00001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x7fc00001u, 0x7fc00001u, 0x00000000u, + 0x00000001u, 0x7ff80000u, 0x00000000u, 0x00000000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x00000000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x7fc00001u, 0x7f800001u, 0x7fc00001u, 0x7f800001u, 0x7f800001u, 0x7f800001u, 0x7fc00001u, 0x7fc00001u, 0x7f800001u, + 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, + 0x7ff80000u, 0x00000001u, 0x7ff80000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u, 0x00000001u, 0x7ff00000u} +}; + +constexpr const char* Names[18] = { + "ds_min_rtn_f32 memory", + "ds_min_rtn_f32 returned", + "ds_max_rtn_f32 memory", + "ds_max_rtn_f32 returned", + "ds_cmpst_rtn_f32 memory", + "ds_cmpst_rtn_f32 returned", + "ds_min_f32 memory", + "ds_max_f32 memory", + "ds_cmpst_f32 memory", + "ds_min_rtn_f64 memory", + "ds_min_rtn_f64 returned", + "ds_max_rtn_f64 memory", + "ds_max_rtn_f64 returned", + "ds_min_f64 memory", + "ds_max_f64 memory", + "ds_cmpst_rtn_f64 memory", + "ds_cmpst_rtn_f64 returned", + "ds_cmpst_f64 memory" +}; + +constexpr std::uint32_t Columns64 = 9; + +std::array BufferDescriptor(const void* data, std::uint32_t bytes) { + const auto address = reinterpret_cast(data); + return {static_cast(address), static_cast((address >> 32u) & 0xffffu), bytes, 0x31016facu}; +} + +std::string Hex(std::uint32_t value) { + char text[16]; + std::snprintf(text, sizeof(text), "0x%08x", value); + return text; +} + +const char* ColumnName(std::uint32_t column) { + return column < Columns64 ? Names[column] : Names[Columns64 + (column - Columns64) / 2u]; +} + +void Run(AgcDriver::VulkanDevice& device, const std::optional& floatMode) { + for (std::uint32_t tid = 0; tid < Threads; ++tid) std::copy(std::begin(Rows[tid]), std::end(Rows[tid]), &Input[tid * Inputs]); + Output.fill(0xdeadbeefu); + std::vector userData(8, 0u); + const auto input = BufferDescriptor(Input.data(), static_cast(Input.size() * 4u)); + const auto output = BufferDescriptor(Output.data(), static_cast(Output.size() * 4u)); + std::copy(input.begin(), input.end(), userData.begin()); + std::copy(output.begin(), output.end(), userData.begin() + 4); + const std::span code(Code); + const std::array memory{{reinterpret_cast(code.data()), std::as_bytes(code)}}; + const ShaderRecompiler::ShaderComputeStageInfo compute{{Threads, 1, 1}, 64u, {false, false, false}, false, 1}; + ShaderRecompiler::RecompileRequest request{ + {ShaderStage::Compute, reinterpret_cast(code.data()), code, 0, {}}, + {32, 0, userData, compute, std::nullopt, std::nullopt, memory}, + device.Target(), + {0, 0, 0, 128} + }; + request.useCache = false; + request.context.floatMode = floatMode; + const auto result = ShaderRecompiler::Recompile(request); + device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast(code.data())); + device.WaitIdle(); +} + +void Check(const std::uint32_t (&expected)[32][Columns], const char* mode) { + for (std::uint32_t tid = 0; tid < Threads; ++tid) { + const std::uint32_t* out = &Output[tid * Results]; + for (std::uint32_t column = 0; column < Columns; ++column) { + const std::uint32_t actual = out[column < Columns64 ? column : column + 1u]; + Require(actual == expected[tid][column], std::string("lds float atomic modes: ") + mode + " lane " + std::to_string(tid) + " " + ColumnName(column) + + (column >= Columns64 && (column - Columns64) % 2u ? " high" : column >= Columns64 ? " low" : "") + " is " + Hex(actual) + ", expected " + Hex(expected[tid][column])); + } + } +} + +} + +int main() { + try { + const auto device = OpenVulkanTestDevice(); + if (!device) return VulkanTestSkipped; + Run(*device, std::nullopt); + Check(ExpectedTitles, "no float mode"); + Run(*device, ShaderRecompiler::ShaderFloatMode{0xc0u, true, false, false}); + Check(ExpectedTitles, "FLOAT_MODE 0xc0"); + Run(*device, ShaderRecompiler::ShaderFloatMode{0xf0u, true, false, false}); + Check(ExpectedKept, "FLOAT_MODE 0xf0"); + Run(*device, ShaderRecompiler::ShaderFloatMode{0x00u, true, false, false}); + Check(ExpectedFlushed, "FLOAT_MODE 0x00"); + Run(*device, ShaderRecompiler::ShaderFloatMode{0x50u, true, false, false}); + Check(ExpectedKept, "FLOAT_MODE 0x50"); + Run(*device, ShaderRecompiler::ShaderFloatMode{0xa0u, true, false, false}); + Check(ExpectedFlushed, "FLOAT_MODE 0xa0"); + std::puts("lds float atomic modes tests passed"); + return 0; + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourceInfo.hpp b/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourceInfo.hpp index a8216cc16319..7c8d5d26d1ac 100644 --- a/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourceInfo.hpp +++ b/core/shader/recompiler/IntermediateRepresentation/include/IntermediateRepresentation/IrMetadata/ResourceInfo.hpp @@ -50,6 +50,7 @@ struct MemoryInfo { bool planningOnly = false; bool coherent = false; bool gpuDescriptor = false; + bool flushDenormals = false; bool operator==(const MemoryInfo& other) const = default; }; diff --git a/core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp b/core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp index a0ab538176cb..884d341baa93 100644 --- a/core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp +++ b/core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp @@ -611,11 +611,15 @@ struct AtomicFloatBits { std::uint64_t sign() const { return wide ? 0x8000000000000000ull : 0x80000000ull; } std::uint64_t quiet() const { return wide ? 0x0008000000000000ull : 0x00400000ull; } std::uint64_t infinity() const { return wide ? 0x7ff0000000000000ull : 0x7f800000ull; } + std::uint64_t minNormal() const { return wide ? 0x0010000000000000ull : 0x00800000ull; } std::uint32_t op(spv::Op opcode, std::uint32_t lhs, std::uint32_t rhs) const { return Binary(state, opcode, type(), lhs, rhs); } std::uint32_t test(spv::Op opcode, std::uint32_t lhs, std::uint32_t rhs) const { return Binary(state, opcode, TypeBool(state), lhs, rhs); } std::uint32_t select(std::uint32_t condition, std::uint32_t lhs, std::uint32_t rhs) const { return Select(state, type(), condition, lhs, rhs); } std::uint32_t magnitude(std::uint32_t value) const { return op(spv::OpBitwiseAnd, value, constant(sign() - 1u)); } std::uint32_t nan(std::uint32_t value) const { return test(spv::OpUGreaterThan, magnitude(value), constant(infinity())); } + std::uint32_t flush(std::uint32_t value, bool enabled) const { + return enabled ? select(test(spv::OpULessThan, magnitude(value), constant(minNormal())), op(spv::OpBitwiseAnd, value, constant(sign())), value) : value; + } std::uint32_t signalingNan(std::uint32_t value) const { return Binary(state, spv::OpLogicalAnd, TypeBool(state), nan(value), test(spv::OpIEqual, op(spv::OpBitwiseAnd, value, constant(quiet())), constant(0u))); } @@ -683,19 +687,10 @@ std::uint32_t SharedAtomicUpdate(SpirvValueEmitContext& ctx, const IrValue& inst std::uint32_t SharedFloatMinMax(SpirvValueEmitContext& ctx, const IrValue& inst, bool maxValue) { const auto data = ctx.Arg(inst, 1); + const bool flush = SharedMemory(ctx, inst).flushDenormals; return SharedAtomicUpdate(ctx, inst, [&](SpirvEmitterState& state, std::uint32_t old) { - const auto oldFloat = Unary(state, spv::OpBitcast, TypeF32(state), old); - const auto dataFloat = Unary(state, spv::OpBitcast, TypeF32(state), data); - const auto oldNan = Unary(state, spv::OpIsNan, TypeBool(state), oldFloat); - const auto dataNan = Unary(state, spv::OpIsNan, TypeBool(state), dataFloat); - const auto better = Binary(state, maxValue ? spv::OpFOrdGreaterThan : spv::OpFOrdLessThan, TypeBool(state), dataFloat, oldFloat); - const auto magnitudes = Binary(state, spv::OpBitwiseAnd, TypeU32(state), Binary(state, spv::OpBitwiseOr, TypeU32(state), old, data), ConstantU32(state, 0x7fffffffu)); - const auto zeros = Binary(state, spv::OpIEqual, TypeBool(state), magnitudes, ConstantU32(state, 0u)); - const auto zero = Binary(state, maxValue ? spv::OpBitwiseAnd : spv::OpBitwiseOr, TypeU32(state), old, data); - auto result = Select(state, TypeU32(state), better, data, old); - result = Select(state, TypeU32(state), zeros, zero, result); - result = Select(state, TypeU32(state), dataNan, old, result); - return Select(state, TypeU32(state), oldNan, data, result); + const AtomicFloatBits bits{state, false}; + return bits.minMax(bits.flush(old, flush), bits.flush(data, flush), maxValue); }); } @@ -972,11 +967,10 @@ std::uint32_t SharedAtomic64Select(SpirvValueEmitContext& ctx, const IrValue& in } std::uint32_t SharedFloatMinMax64(SpirvValueEmitContext& ctx, const IrValue& inst, bool maxValue) { + const bool flush = SharedMemory(ctx, inst).flushDenormals; return SharedAtomic64Binary(ctx, inst, [&](SpirvEmitterState& state, std::uint32_t old, std::uint32_t data) { const AtomicFloatBits bits{state, true}; - auto result = bits.select(bits.test(maxValue ? spv::OpUGreaterThan : spv::OpULessThan, bits.orderKey(data), bits.orderKey(old)), data, old); - result = bits.select(bits.nan(data), old, result); - return bits.select(bits.nan(old), data, result); + return bits.minMax(bits.flush(old, flush), bits.flush(data, flush), maxValue); }); } @@ -1373,9 +1367,10 @@ std::uint32_t EmitSharedAtomicCmpst32(SpirvValueEmitContext& ctx, const IrValue& std::uint32_t EmitSharedAtomicCmpstF32(SpirvValueEmitContext& ctx, const IrValue& inst) { const auto compare = ctx.Arg(inst, 1); const auto source = ctx.Arg(inst, 2); + const bool flush = SharedMemory(ctx, inst).flushDenormals; return SharedAtomicUpdate(ctx, inst, [&](SpirvEmitterState& state, std::uint32_t old) { - const auto equal = Binary(state, spv::OpFOrdEqual, TypeBool(state), Unary(state, spv::OpBitcast, TypeF32(state), old), Unary(state, spv::OpBitcast, TypeF32(state), compare)); - return Select(state, TypeU32(state), equal, source, old); + const AtomicFloatBits bits{state, false}; + return bits.select(bits.equal(bits.flush(old, flush), bits.flush(compare, flush)), source, old); }); } @@ -1475,9 +1470,10 @@ std::uint32_t EmitSharedAtomicCmpst64(SpirvValueEmitContext& ctx, const IrValue& std::uint32_t EmitSharedAtomicCmpstF64(SpirvValueEmitContext& ctx, const IrValue& inst) { const auto compare = ScalarU64Argument(ctx, inst, 3u); const auto source = ScalarU64Argument(ctx, inst, 2u); + const bool flush = SharedMemory(ctx, inst).flushDenormals; return SharedAtomic64(ctx, inst, [&](SpirvEmitterState& state, std::uint32_t old) { const AtomicFloatBits bits{state, true}; - return bits.select(bits.equal(old, compare), source, old); + return bits.select(bits.equal(bits.flush(old, flush), bits.flush(compare, flush)), source, old); }); } diff --git a/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp b/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp index c19e8e2ae808..5609782dbd5f 100644 --- a/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp +++ b/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp @@ -129,6 +129,7 @@ class TranslationContext { bool dsWrite2(const RdnaInstruction& inst); bool dsSrc2(const RdnaInstruction& inst, IrOpcode opcode); bool dsAtomic2(const RdnaInstruction& inst, IrOpcode opcode, bool returnsValue); + bool sharedFloatFlush(IrOpcode opcode) const; bool dsAtomic64(const RdnaInstruction& inst, IrOpcode opcode, bool returnsValue); bool dsCondxchg32(const RdnaInstruction& inst); bool dsAppendConsume(const RdnaInstruction& inst, IrOpcode opcode); diff --git a/core/shader/recompiler/Translation/src/MemoryInstructions/SharedMemoryInstructions.cpp b/core/shader/recompiler/Translation/src/MemoryInstructions/SharedMemoryInstructions.cpp index be58eaf47837..04115cbb32e8 100644 --- a/core/shader/recompiler/Translation/src/MemoryInstructions/SharedMemoryInstructions.cpp +++ b/core/shader/recompiler/Translation/src/MemoryInstructions/SharedMemoryInstructions.cpp @@ -31,7 +31,8 @@ MemoryInfo sharedMemoryInfoFromInstruction(const RdnaInstruction& inst) { } bool TranslationContext::dsAtomic(const RdnaInstruction& inst, IrOpcode opcode, bool returnsValue) { - const MemoryInfo memory = sharedMemoryInfoFromInstruction(inst); + MemoryInfo memory = sharedMemoryInfoFromInstruction(inst); + memory.flushDenormals = sharedFloatFlush(opcode); const IrU32 address = readU32(inst.source0); const IrU32 value = readU32(inst.source1); IrValue& active = ir.GetExec(); @@ -211,8 +212,24 @@ bool TranslationContext::dsSrc2(const RdnaInstruction& inst, IrOpcode opcode) { return true; } +bool TranslationContext::sharedFloatFlush(IrOpcode opcode) const { + switch (opcode) { + case IrOpcode::SharedAtomicFMin32: + case IrOpcode::SharedAtomicFMax32: + case IrOpcode::SharedAtomicCmpstF32: + return !floatMode.has_value() || ((floatMode->floatMode >> 4u) & 1u) == 0u; + case IrOpcode::SharedAtomicFMin64: + case IrOpcode::SharedAtomicFMax64: + case IrOpcode::SharedAtomicCmpstF64: + return floatMode.has_value() && ((floatMode->floatMode >> 6u) & 1u) == 0u; + default: + return false; + } +} + bool TranslationContext::dsAtomic2(const RdnaInstruction& inst, IrOpcode opcode, bool returnsValue) { - const MemoryInfo memory = sharedMemoryInfoFromInstruction(inst); + MemoryInfo memory = sharedMemoryInfoFromInstruction(inst); + memory.flushDenormals = sharedFloatFlush(opcode); const IrU32 address = readU32(inst.source0); const IrU32 data0 = readU32(inst.source1); const IrU32 data1 = readU32(inst.source2); @@ -226,7 +243,8 @@ bool TranslationContext::dsAtomic64(const RdnaInstruction& inst, IrOpcode opcode if (inst.gds) { throw std::runtime_error("64-bit GDS atomics are not supported"); } - const MemoryInfo memory = sharedMemoryInfoFromInstruction(inst); + MemoryInfo memory = sharedMemoryInfoFromInstruction(inst); + memory.flushDenormals = sharedFloatFlush(opcode); const IrU32 address = readU32(inst.source0); const IrU64 data0 = readU64(inst.source1); IrValue& active = ir.GetExec(); diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 7cfb30945ce4..2c680aa138da 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -341,7 +341,7 @@ Throughout the project, every function at every stage either **does exactly what - [v_fma_mixlo_f16 and v_fma_mixhi_f16](../../core/shader/recompiler/Translation/src/FloatInstructions.cpp) round the exact product-sum once to f16 with the f64 arithmetic of v_interp_p2_f16, so they need the Float64 capability. On RDNA2 (gfx1036) they follow the `FLOAT_MODE` f16 round and denormal fields, not the f32 round field: -1.5 * 2^-24 + 2^-126 from f32 sources (0xbfc00000, 0x33800000, 0x00800000) gives 0x8001 with f16 denormals kept and round to nearest even, 0x8000 with f16 denormals flushed and 0x8002 with f16 round toward -infinity. Only f16 denormals kept with round to nearest even is translated; another f16 mode throws, as for packed f16. `FP16_OVFL` set is not measured. - [Signaling NaN inputs](../../core/shader/recompiler/Translation/src/FloatInstructions.cpp) of the f32 and f16 unary instructions (`v_sqrt/rcp/rsq/log/exp/sin/cos/fract/floor/ceil/trunc/rndne/rcp_iflag/frexp_mant`), `v_ldexp_f32/f16`, `v_frexp_mant_f16`, `v_div_fixup_f32/f16` and `v_mullit_f32` are returned quieted only with IEEE=1 and unchanged with IEEE=0, measured on RDNA2 (gfx1035) in both modes; shaders without a known float mode follow IEEE=0. `v_pack_b32_f16` quiets each signaling NaN half by the same rule, measured on RDNA2 (gfx1036) in both modes. A signaling NaN result of `v_cubesc/cubetc/cubema_f32` is quieted by the same rule and keeps the sign the instruction gives it, measured on RDNA2 (gfx1036) in both modes. `v_add/sub/subrev/mul/fma/fmac/fmamk/fmaak/mul_legacy_f32` and `v_fma_mix_f32` with f32 sources choose their NaN result on the bits, measured over 1000 operand triples in both modes: the first NaN source in operand order after its modifiers (the subtrahend negated, as the hardware adds its negation), quieted only with IEEE=1, or the default NaN 0xffc00000 for an invalid operation; in the fma forms an invalid product (inf * 0) gives the default NaN even when src2 is a NaN, and in the legacy forms a zero factor makes the product 0 even when the other factor is a NaN (a NaN src2 still wins). `v_mad_legacy_f32` follows the same rule with its separately rounded product, as measured on gfx1010 (#1281): a NaN source quieted only with IEEE=1, inf - inf giving 0xffc00000, the zero rule hiding a NaN factor and a NaN src2 winning. The f16 arithmetic, `v_fma_mix_f32` with f16 sources, `v_mac_legacy_f32` and the separately rounded mad/mac forms (not measurable on RDNA2) follow the same rule on hardware but their NaN bits are left to the driver. `v_cvt_f16_f32`, `v_dot2_f32_f16`, `v_fma_mixlo_f16` and `v_fma_mixhi_f16` always quiet and `v_div_scale_f32` never does: the f32 signaling NaN 0x7f812345 as src0 or src2 gives 0x7e09 from mixlo and mixhi at IEEE=0 and IEEE=1 on RDNA2 (gfx1036), where `v_fma_mix_f32` gives 0x7f812345 at IEEE=0 and 0x7fc12345 at IEEE=1. The payload of an f16 NaN source of mixlo and mixhi is left to the driver's f16 to f32 conversion, which NVIDIA replaces. - [Packed f16 NaN results](../../core/shader/recompiler/Translation/src/FloatInstructions.cpp) (`v_pk_add/mul/fma/min/max_f16`) follow the hardware measured on RDNA2 (gfx1035) at IEEE=0 and IEEE=1 with f16 round-to-nearest-even and f16 denormals kept: with IEEE=1 a signaling NaN input is quieted and min/max return the other operand only for a quiet NaN; with IEEE=0 NaN inputs pass through unquieted and min/max ignore signaling. In `v_pk_fma_f16` an invalid product (inf * 0) gives the default NaN even when src2 is a NaN. A shader without a known float mode is translated as IEEE=0, the mode titles use; a mode with another f16 rounding or that flushes f16 denormals throws. -- [f32 denormals](../../core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp) follow the shader's `FLOAT_MODE` f32 denormal field (bits 5:4) when it flushes them (0, and shaders without a known float mode, as in the 0xc0 most titles use), measured on RDNA2 (gfx1035) over 1444 rows per instruction at IEEE=0 and IEEE=1. `v_add/sub/subrev/mul/mul_legacy/mullit/fma/fmac/fmamk/fmaak/min/max/min3/max3/med3/fract/floor/ceil/frexp_mant/sin/cos_f32` flush their f32 inputs and their result to a zero of the same sign (`v_mullit_f32` measured on RDNA2 (gfx1036) over 6907 rows per mode at IEEE=0 and IEEE=1, so a positive denormal src2 counts as zero); the f32 compares, `v_cvt_i32/u32/rpi_i32/flr_i32_f32`, `v_frexp_exp_i32_f32`, `v_cvt_f64_f32`, `v_cvt_f16_f32`, `v_cvt_pkrtz_f16_f32`, `v_cvt_pknorm_i16/u16_f32` and `v_cvt_pk_u8_f32` flush their f32 inputs. `v_div_fixup_f32` flushes its src1 and src2 and keeps a denormal src0 and result, measured on RDNA2 (gfx1036) over 6859 rows per mode at IEEE=0 and IEEE=1. A product is checked for tininess on its exact value: one below 2^-126 gives zero even when it rounds to 2^-126, computed exactly from the significands for `v_mul_f32`, `v_mul_legacy_f32`, `v_mullit_f32`, and for `v_fma_f32`, `v_fmac_f32`, `v_fmamk_f32`, `v_fmaak_f32` and `v_fma_mix_f32` when the addend is zero; with a nonzero addend the fused result is kept, so an exact result just below 2^-126 that rounds to it is not flushed. The hardware detects tininess after rounding to 24 bits with an unbounded exponent, measured on RDNA2 (gfx1036) for `v_mul_f32` and `v_mullit_f32` at IEEE=0 and IEEE=1: `0x3f7ffffe * 0x00800001` (2^-126 * (1 - 2^-46)) gives `0x00800000` there and zero here, while `0x3f7fffff * 0x00800000` (2^-126 * (1 - 2^-24)) gives zero on both. `v_fma_mix_f32` was measured with f32 sources only; its f16 sources are not flushed. `v_fma_mixlo_f16` and `v_fma_mixhi_f16` flush their f32 sources too and keep a product below 2^-126, measured on RDNA2 (gfx1036). `v_mad_legacy_f32` flushes its inputs, its product and its result in every mode, see its entry. Denormal modes 1 and 2 throw for the other instructions. Not covered, and not measurable on RDNA2 (no such opcodes) or not measured: `v_mac_f32`, `v_mad_f32`, `v_madak_f32` and `v_madmk_f32` (rounded separately), `v_mac_legacy_f32`, `v_dot2_f32_f16`, `v_div_scale_f32` and `v_div_fmas_f32` (on hardware `v_div_fmas_f32` flushes only its result), f32 interpolation and LDS float atomics keep the previous lowering. With f32 denormals kept (3) the results depend on the driver's default denormal behaviour, as no `DenormPreserve` execution mode is requested, and `v_ldexp_f32` flushes in every mode. +- [f32 denormals](../../core/shader/recompiler/Translation/src/TranslationContext/OperandAccess.cpp) follow the shader's `FLOAT_MODE` f32 denormal field (bits 5:4) when it flushes them (0, and shaders without a known float mode, as in the 0xc0 most titles use), measured on RDNA2 (gfx1035) over 1444 rows per instruction at IEEE=0 and IEEE=1. `v_add/sub/subrev/mul/mul_legacy/mullit/fma/fmac/fmamk/fmaak/min/max/min3/max3/med3/fract/floor/ceil/frexp_mant/sin/cos_f32` flush their f32 inputs and their result to a zero of the same sign (`v_mullit_f32` measured on RDNA2 (gfx1036) over 6907 rows per mode at IEEE=0 and IEEE=1, so a positive denormal src2 counts as zero); the f32 compares, `v_cvt_i32/u32/rpi_i32/flr_i32_f32`, `v_frexp_exp_i32_f32`, `v_cvt_f64_f32`, `v_cvt_f16_f32`, `v_cvt_pkrtz_f16_f32`, `v_cvt_pknorm_i16/u16_f32` and `v_cvt_pk_u8_f32` flush their f32 inputs. `v_div_fixup_f32` flushes its src1 and src2 and keeps a denormal src0 and result, measured on RDNA2 (gfx1036) over 6859 rows per mode at IEEE=0 and IEEE=1. A product is checked for tininess on its exact value: one below 2^-126 gives zero even when it rounds to 2^-126, computed exactly from the significands for `v_mul_f32`, `v_mul_legacy_f32`, `v_mullit_f32`, and for `v_fma_f32`, `v_fmac_f32`, `v_fmamk_f32`, `v_fmaak_f32` and `v_fma_mix_f32` when the addend is zero; with a nonzero addend the fused result is kept, so an exact result just below 2^-126 that rounds to it is not flushed. The hardware detects tininess after rounding to 24 bits with an unbounded exponent, measured on RDNA2 (gfx1036) for `v_mul_f32` and `v_mullit_f32` at IEEE=0 and IEEE=1: `0x3f7ffffe * 0x00800001` (2^-126 * (1 - 2^-46)) gives `0x00800000` there and zero here, while `0x3f7fffff * 0x00800000` (2^-126 * (1 - 2^-24)) gives zero on both. `v_fma_mix_f32` was measured with f32 sources only; its f16 sources are not flushed. `v_fma_mixlo_f16` and `v_fma_mixhi_f16` flush their f32 sources too and keep a product below 2^-126, measured on RDNA2 (gfx1036). `v_mad_legacy_f32` flushes its inputs, its product and its result in every mode, see its entry. Denormal modes 1 and 2 throw for the other instructions. Not covered, and not measurable on RDNA2 (no such opcodes) or not measured: `v_mac_f32`, `v_mad_f32`, `v_madak_f32` and `v_madmk_f32` (rounded separately), `v_mac_legacy_f32`, `v_dot2_f32_f16`, `v_div_scale_f32` and `v_div_fmas_f32` (on hardware `v_div_fmas_f32` flushes only its result), f32 interpolation and `ds_add_f32` keep the previous lowering; `ds_min/max/cmpst_f32` flush both operands by the field, see the LDS float atomics entry. With f32 denormals kept (3) the results depend on the driver's default denormal behaviour, as no `DenormPreserve` execution mode is requested, and `v_ldexp_f32` flushes in every mode. - The executable file that [relinker](../../core/relinker/elfpatcher/src/windows/WindowsPeWriter.cpp) generates opens the console when launched, which is inconvenient for playability. - [Overlay output bus](../../core/libs/prx/libSceVideoOut/src/VideoOutDriver.cpp) (libSceVideoOut) - flips on a port opened with `SCE_VIDEO_OUT_BUS_TYPE_OVERLAY` complete and signal their events like main-bus flips, but their buffers are not shown: the overlay is not composited over the main output. Presenting them as whole frames made the window alternate between the two buses - [PA_CL_CLIP_CNTL](../../core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp) (libSceAgcDriver) - `DX_LINEAR_ATTR_CLIP_ENA` (bit 24) clear is drawn like bit 24 set, with Vulkan's clipping of `NoPerspective` outputs; what a clear bit changes on the console is undocumented. @@ -386,7 +386,8 @@ Throughout the project, every function at every stage either **does exactly what - [libScePlayerInvitationDialog](../../core/libs/prx/libScePlayerInvitationDialog/libScePlayerInvitationDialog.cpp) simulates dialog completion without displaying UI or sending invitations, so `scePlayerInvitationDialogGetResult` reports `USER_CANCELED`; its parameter ABI remains unverified. The 40-byte result layout (error code, result, 32 reserved bytes) is taken from [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/Dialog/PlayerInvitationDialog.cs) and the error codes from the other common dialogs, not confirmed on a title. - [Converted unorm images](../../core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp) (10_11_11_UNORM, read and written through an R32_UINT view): samples, gathers, LOD queries, 16-bit data and a DST_SEL of the missing W channel throw. - [Converted unorm image loads](../../core/shader/recompiler/SpirvBackend/src/SpirvImageEmitter.cpp) divide by 2^n - 1 with the buffer format path's `OpFDiv`, which Vulkan allows to be up to 2.5 ULP off, so some drivers are not bit-exact. -- [64-bit LDS atomics](../../core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp) (`ds_*_u64`, `ds_*_b64`, `ds_*_f64`) read and write the two dwords under a workgroup lock stored after the guest LDS, as LDS is a 32-bit array without 64-bit atomics. They are atomic with respect to each other only: 32-bit accesses to the same dwords issued concurrently are not ordered by the lock. 64-bit GDS atomics throw. `ds_min/max(_rtn)_f64` and `ds_cmpst(_rtn)_f64` follow the NaN and signed-zero rules measured for the f32 forms; the f64 forms were not measured on hardware. +- [64-bit LDS atomics](../../core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp) (`ds_*_u64`, `ds_*_b64`, `ds_*_f64`) read and write the two dwords under a workgroup lock stored after the guest LDS, as LDS is a 32-bit array without 64-bit atomics. They are atomic with respect to each other only: 32-bit accesses to the same dwords issued concurrently are not ordered by the lock. 64-bit GDS atomics throw. On the hardware the LDS serialises 32-bit and 64-bit atomics on the same address (256 lanes mixing `ds_add_u32` and `ds_add_u64` on one slot sum exactly), and under the lock the 32-bit adds can be lost: in 20 runs per host and wave size, RADV lost 32 to 96 of the 128 in every run and the RTX 3080 16 to 80 in 18 of 20 wave32 runs and 16 in 3 of 20 wave64 runs, always a multiple of 16. A 64-bit atomic at an address that is 4-byte but not 8-byte aligned faults the wave on gfx1036, as on gfx1035. +- [LDS float atomics](../../core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp) (`ds_min/max/cmpst_f32`, `ds_min/max/cmpst_f64` and their `_rtn` forms) follow the hardware measured on RDNA2 (gfx1036) over 14 x 14 operand sets (zeros, ones, infinities, denormals, quiet and signalling NaNs of both signs and with payloads) in IEEE 0 and 1 with every value 0-3 of the type's denormal field: both operands are flushed to a signed zero when bit 0 of the field is clear (0 and 2; 1 and 3 keep them; the f32 field for the f32 forms, the f16/f64 field for the f64 forms; a shader without a known float mode flushes f32 and keeps f64), then a signalling-NaN data operand is stored quieted, else a signalling-NaN old value is stored quieted, else a quiet-NaN old value is replaced by the data, else a quiet-NaN data operand loses, else the ordered compare with -0 below +0 decides, and the flushed value is what is written, also when the old value wins. `cmpst` compares the flushed bits (both zeros equal, NaN never equal) and leaves memory unchanged when they differ. The returned value is always the old value as it was in memory. `IEEE_MODE` has no effect. The same bit rule serves the buffer float atomics (`AtomicFloatBits`). Not measured: a denormal or signalling-NaN `data1` of `cmpst` (stored as given), and `ds_add_f32`, which keeps the host's `OpFAdd`. - [V# bases off a DWORD boundary](../../core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp) (shader recompiler) - raw accesses use the exact bytes and `s_buffer_load` reads `(base & ~3) + (offset & ~3)`, as measured on gfx1035 (Linux, alignment mode UNALIGNED; the console's mode is unknown). Formatted accesses off their element's alignment and atomics throw. - [32-bit bitfield masks](../../core/shader/recompiler/Translation/src/IntegerInstructions.cpp) (`S_BFM_B32`, `V_BFM_B32`) use the truncating 32-bit shift specified by the [RDNA 1.0 ISA](https://www.amd.com/content/dam/amd/en/documents/radeon-tech-docs/instruction-set-architectures/rdna-shader-instruction-set-architecture.pdf), sections 12.1 (opcode 36) and 12.12 (opcode 867). Width and offset use their low five bits. This matches gfx1035 (Linux) for every width/offset pair, with and without upper operand bits set, and both leave SCC unchanged; not measured on the console. - [Vector buffer offsets that are not a multiple of 4](../../core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp) (shader recompiler) - dword accesses count whole dwords from the V# base, where the hardware reads the exact bytes at base + offset.