Merge pull request #3932 from CouchRiv/fix-shader-f16-denorm-flush-family
fix(shader): flush f16 denormals in unary, frexp and conversion ops per the float mode
This commit is contained in:
commit
32cb3fea95
|
|
@ -0,0 +1,353 @@
|
|||
#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 <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#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 = 1;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Inputs> Input{};
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
struct alignas(256) Shader {
|
||||
std::array<std::uint32_t, 11> words;
|
||||
};
|
||||
|
||||
struct Vector {
|
||||
std::uint32_t half;
|
||||
std::uint32_t expected[4];
|
||||
};
|
||||
|
||||
struct Case {
|
||||
const char* name;
|
||||
std::uint32_t word;
|
||||
std::span<const Vector> rows;
|
||||
};
|
||||
|
||||
constexpr Vector CeilRows[] = {
|
||||
{0x0001u, {0x5a5a0000u, 0x5a5a3c00u, 0x5a5a0000u, 0x5a5a3c00u}},
|
||||
{0x0200u, {0x5a5a0000u, 0x5a5a3c00u, 0x5a5a0000u, 0x5a5a3c00u}},
|
||||
{0x03ffu, {0x5a5a0000u, 0x5a5a3c00u, 0x5a5a0000u, 0x5a5a3c00u}},
|
||||
{0x8001u, {0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u}},
|
||||
{0x8200u, {0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u}},
|
||||
{0x83ffu, {0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u}},
|
||||
{0x0400u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x8400u, {0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u}},
|
||||
{0x0000u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3c00u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0xbc00u, {0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u}},
|
||||
{0x3800u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
};
|
||||
|
||||
constexpr Vector CvtF32Rows[] = {
|
||||
{0x0001u, {0x00000000u, 0x33800000u, 0x00000000u, 0x33800000u}},
|
||||
{0x0200u, {0x00000000u, 0x38000000u, 0x00000000u, 0x38000000u}},
|
||||
{0x03ffu, {0x00000000u, 0x387fc000u, 0x00000000u, 0x387fc000u}},
|
||||
{0x8001u, {0x80000000u, 0xb3800000u, 0x80000000u, 0xb3800000u}},
|
||||
{0x8200u, {0x80000000u, 0xb8000000u, 0x80000000u, 0xb8000000u}},
|
||||
{0x83ffu, {0x80000000u, 0xb87fc000u, 0x80000000u, 0xb87fc000u}},
|
||||
{0x0400u, {0x38800000u, 0x38800000u, 0x38800000u, 0x38800000u}},
|
||||
{0x8400u, {0xb8800000u, 0xb8800000u, 0xb8800000u, 0xb8800000u}},
|
||||
{0x0000u, {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}},
|
||||
{0x3c00u, {0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u}},
|
||||
{0xbc00u, {0xbf800000u, 0xbf800000u, 0xbf800000u, 0xbf800000u}},
|
||||
{0x3800u, {0x3f000000u, 0x3f000000u, 0x3f000000u, 0x3f000000u}},
|
||||
};
|
||||
|
||||
constexpr Vector CvtNormI16Rows[] = {
|
||||
{0x0001u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x0200u, {0x5a5a0000u, 0x5a5a0001u, 0x5a5a0000u, 0x5a5a0001u}},
|
||||
{0x03ffu, {0x5a5a0000u, 0x5a5a0002u, 0x5a5a0000u, 0x5a5a0002u}},
|
||||
{0x8001u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x8200u, {0x5a5a0000u, 0x5a5affffu, 0x5a5a0000u, 0x5a5affffu}},
|
||||
{0x83ffu, {0x5a5a0000u, 0x5a5afffeu, 0x5a5a0000u, 0x5a5afffeu}},
|
||||
{0x0400u, {0x5a5a0002u, 0x5a5a0002u, 0x5a5a0002u, 0x5a5a0002u}},
|
||||
{0x8400u, {0x5a5afffeu, 0x5a5afffeu, 0x5a5afffeu, 0x5a5afffeu}},
|
||||
{0x0000u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3c00u, {0x5a5a7fffu, 0x5a5a7fffu, 0x5a5a7fffu, 0x5a5a7fffu}},
|
||||
{0xbc00u, {0x5a5a8001u, 0x5a5a8001u, 0x5a5a8001u, 0x5a5a8001u}},
|
||||
{0x3800u, {0x5a5a4000u, 0x5a5a4000u, 0x5a5a4000u, 0x5a5a4000u}},
|
||||
{0xb800u, {0x5a5ac000u, 0x5a5ac000u, 0x5a5ac000u, 0x5a5ac000u}},
|
||||
};
|
||||
|
||||
constexpr Vector CvtNormU16Rows[] = {
|
||||
{0x0001u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x0200u, {0x5a5a0000u, 0x5a5a0002u, 0x5a5a0000u, 0x5a5a0002u}},
|
||||
{0x03ffu, {0x5a5a0000u, 0x5a5a0004u, 0x5a5a0000u, 0x5a5a0004u}},
|
||||
{0x8001u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x8200u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x83ffu, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x0400u, {0x5a5a0004u, 0x5a5a0004u, 0x5a5a0004u, 0x5a5a0004u}},
|
||||
{0x8400u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x0000u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3c00u, {0x5a5affffu, 0x5a5affffu, 0x5a5affffu, 0x5a5affffu}},
|
||||
{0xbc00u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3800u, {0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u}},
|
||||
{0xb800u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
};
|
||||
|
||||
constexpr Vector ExpRows[] = {
|
||||
{0x0001u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x0200u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x03ffu, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x8001u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x8200u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x83ffu, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x0400u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x8400u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x0000u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0x3c00u, {0x5a5a4000u, 0x5a5a4000u, 0x5a5a4000u, 0x5a5a4000u}},
|
||||
{0xbc00u, {0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u}},
|
||||
{0xcb01u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a03fau, 0x5a5a03fau}},
|
||||
{0xcca0u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a002du, 0x5a5a002du}},
|
||||
{0xce3cu, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0001u, 0x5a5a0001u}},
|
||||
{0xc800u, {0x5a5a1c00u, 0x5a5a1c00u, 0x5a5a1c00u, 0x5a5a1c00u}},
|
||||
{0xc400u, {0x5a5a2c00u, 0x5a5a2c00u, 0x5a5a2c00u, 0x5a5a2c00u}},
|
||||
};
|
||||
|
||||
constexpr Vector FloorRows[] = {
|
||||
{0x0001u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x0200u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x03ffu, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x8001u, {0x5a5a8000u, 0x5a5abc00u, 0x5a5a8000u, 0x5a5abc00u}},
|
||||
{0x8200u, {0x5a5a8000u, 0x5a5abc00u, 0x5a5a8000u, 0x5a5abc00u}},
|
||||
{0x83ffu, {0x5a5a8000u, 0x5a5abc00u, 0x5a5a8000u, 0x5a5abc00u}},
|
||||
{0x0400u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x8400u, {0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u}},
|
||||
{0x0000u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3c00u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0xbc00u, {0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u}},
|
||||
{0xb800u, {0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u}},
|
||||
};
|
||||
|
||||
constexpr Vector FractRows[] = {
|
||||
{0x0001u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0001u}},
|
||||
{0x0200u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0200u}},
|
||||
{0x03ffu, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a03ffu}},
|
||||
{0x8001u, {0x5a5a0000u, 0x5a5a3bffu, 0x5a5a0000u, 0x5a5a3bffu}},
|
||||
{0x8200u, {0x5a5a0000u, 0x5a5a3bffu, 0x5a5a0000u, 0x5a5a3bffu}},
|
||||
{0x83ffu, {0x5a5a0000u, 0x5a5a3bffu, 0x5a5a0000u, 0x5a5a3bffu}},
|
||||
{0x0400u, {0x5a5a0400u, 0x5a5a0400u, 0x5a5a0400u, 0x5a5a0400u}},
|
||||
{0x8400u, {0x5a5a3bffu, 0x5a5a3bffu, 0x5a5a3bffu, 0x5a5a3bffu}},
|
||||
{0x0000u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3c00u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0xbc00u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0xb800u, {0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u}},
|
||||
{0x4900u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
};
|
||||
|
||||
constexpr Vector FrexpExpRows[] = {
|
||||
{0x0001u, {0x5a5a0000u, 0x5a5affe9u, 0x5a5a0000u, 0x5a5affe9u}},
|
||||
{0x0200u, {0x5a5a0000u, 0x5a5afff2u, 0x5a5a0000u, 0x5a5afff2u}},
|
||||
{0x03ffu, {0x5a5a0000u, 0x5a5afff2u, 0x5a5a0000u, 0x5a5afff2u}},
|
||||
{0x8001u, {0x5a5a0000u, 0x5a5affe9u, 0x5a5a0000u, 0x5a5affe9u}},
|
||||
{0x8200u, {0x5a5a0000u, 0x5a5afff2u, 0x5a5a0000u, 0x5a5afff2u}},
|
||||
{0x83ffu, {0x5a5a0000u, 0x5a5afff2u, 0x5a5a0000u, 0x5a5afff2u}},
|
||||
{0x0400u, {0x5a5afff3u, 0x5a5afff3u, 0x5a5afff3u, 0x5a5afff3u}},
|
||||
{0x8400u, {0x5a5afff3u, 0x5a5afff3u, 0x5a5afff3u, 0x5a5afff3u}},
|
||||
{0x0000u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3c00u, {0x5a5a0001u, 0x5a5a0001u, 0x5a5a0001u, 0x5a5a0001u}},
|
||||
{0xbc00u, {0x5a5a0001u, 0x5a5a0001u, 0x5a5a0001u, 0x5a5a0001u}},
|
||||
{0x4900u, {0x5a5a0004u, 0x5a5a0004u, 0x5a5a0004u, 0x5a5a0004u}},
|
||||
};
|
||||
|
||||
constexpr Vector FrexpMantRows[] = {
|
||||
{0x0001u, {0x5a5a0000u, 0x5a5a3800u, 0x5a5a0000u, 0x5a5a3800u}},
|
||||
{0x0200u, {0x5a5a0000u, 0x5a5a3800u, 0x5a5a0000u, 0x5a5a3800u}},
|
||||
{0x03ffu, {0x5a5a0000u, 0x5a5a3bfeu, 0x5a5a0000u, 0x5a5a3bfeu}},
|
||||
{0x8001u, {0x5a5a8000u, 0x5a5ab800u, 0x5a5a8000u, 0x5a5ab800u}},
|
||||
{0x8200u, {0x5a5a8000u, 0x5a5ab800u, 0x5a5a8000u, 0x5a5ab800u}},
|
||||
{0x83ffu, {0x5a5a8000u, 0x5a5abbfeu, 0x5a5a8000u, 0x5a5abbfeu}},
|
||||
{0x0400u, {0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u}},
|
||||
{0x8400u, {0x5a5ab800u, 0x5a5ab800u, 0x5a5ab800u, 0x5a5ab800u}},
|
||||
{0x0000u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3c00u, {0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u}},
|
||||
{0xbc00u, {0x5a5ab800u, 0x5a5ab800u, 0x5a5ab800u, 0x5a5ab800u}},
|
||||
{0x4900u, {0x5a5a3900u, 0x5a5a3900u, 0x5a5a3900u, 0x5a5a3900u}},
|
||||
};
|
||||
|
||||
constexpr Vector LogRows[] = {
|
||||
{0x0001u, {0x5a5afc00u, 0x5a5ace00u, 0x5a5afc00u, 0x5a5ace00u}},
|
||||
{0x0200u, {0x5a5afc00u, 0x5a5acb80u, 0x5a5afc00u, 0x5a5acb80u}},
|
||||
{0x03ffu, {0x5a5afc00u, 0x5a5acb00u, 0x5a5afc00u, 0x5a5acb00u}},
|
||||
{0x8001u, {0x5a5afc00u, 0x5a5afe00u, 0x5a5afc00u, 0x5a5afe00u}},
|
||||
{0x8200u, {0x5a5afc00u, 0x5a5afe00u, 0x5a5afc00u, 0x5a5afe00u}},
|
||||
{0x83ffu, {0x5a5afc00u, 0x5a5afe00u, 0x5a5afc00u, 0x5a5afe00u}},
|
||||
{0x0400u, {0x5a5acb00u, 0x5a5acb00u, 0x5a5acb00u, 0x5a5acb00u}},
|
||||
{0x8400u, {0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u}},
|
||||
{0x0000u, {0x5a5afc00u, 0x5a5afc00u, 0x5a5afc00u, 0x5a5afc00u}},
|
||||
{0x3c00u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0xbc00u, {0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u}},
|
||||
{0x4900u, {0x5a5a42a5u, 0x5a5a42a5u, 0x5a5a42a5u, 0x5a5a42a5u}},
|
||||
{0x0801u, {0x5a5aca80u, 0x5a5aca80u, 0x5a5aca80u, 0x5a5aca80u}},
|
||||
};
|
||||
|
||||
constexpr Vector RcpRows[] = {
|
||||
{0x0001u, {0x5a5a7c00u, 0x5a5a7c00u, 0x5a5a7c00u, 0x5a5a7c00u}},
|
||||
{0x0200u, {0x5a5a7c00u, 0x5a5a7800u, 0x5a5a7c00u, 0x5a5a7800u}},
|
||||
{0x03ffu, {0x5a5a7c00u, 0x5a5a7401u, 0x5a5a7c00u, 0x5a5a7401u}},
|
||||
{0x8001u, {0x5a5afc00u, 0x5a5afc00u, 0x5a5afc00u, 0x5a5afc00u}},
|
||||
{0x8200u, {0x5a5afc00u, 0x5a5af800u, 0x5a5afc00u, 0x5a5af800u}},
|
||||
{0x83ffu, {0x5a5afc00u, 0x5a5af401u, 0x5a5afc00u, 0x5a5af401u}},
|
||||
{0x0400u, {0x5a5a7400u, 0x5a5a7400u, 0x5a5a7400u, 0x5a5a7400u}},
|
||||
{0x8400u, {0x5a5af400u, 0x5a5af400u, 0x5a5af400u, 0x5a5af400u}},
|
||||
{0x0000u, {0x5a5a7c00u, 0x5a5a7c00u, 0x5a5a7c00u, 0x5a5a7c00u}},
|
||||
{0x3c00u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0xbc00u, {0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u, 0x5a5abc00u}},
|
||||
{0x7bffu, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0100u, 0x5a5a0100u}},
|
||||
{0x7401u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a03ffu, 0x5a5a03ffu}},
|
||||
{0xfbffu, {0x5a5a8000u, 0x5a5a8000u, 0x5a5a8100u, 0x5a5a8100u}},
|
||||
{0xf404u, {0x5a5a8000u, 0x5a5a8000u, 0x5a5a83fcu, 0x5a5a83fcu}},
|
||||
{0x7800u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0200u, 0x5a5a0200u}},
|
||||
};
|
||||
|
||||
constexpr Vector RsqRows[] = {
|
||||
{0x0001u, {0x5a5a7c00u, 0x5a5a6c00u, 0x5a5a7c00u, 0x5a5a6c00u}},
|
||||
{0x0200u, {0x5a5a7c00u, 0x5a5a59a8u, 0x5a5a7c00u, 0x5a5a59a8u}},
|
||||
{0x03ffu, {0x5a5a7c00u, 0x5a5a5801u, 0x5a5a7c00u, 0x5a5a5801u}},
|
||||
{0x8001u, {0x5a5afc00u, 0x5a5afe00u, 0x5a5afc00u, 0x5a5afe00u}},
|
||||
{0x8200u, {0x5a5afc00u, 0x5a5afe00u, 0x5a5afc00u, 0x5a5afe00u}},
|
||||
{0x83ffu, {0x5a5afc00u, 0x5a5afe00u, 0x5a5afc00u, 0x5a5afe00u}},
|
||||
{0x0400u, {0x5a5a5800u, 0x5a5a5800u, 0x5a5a5800u, 0x5a5a5800u}},
|
||||
{0x8400u, {0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u}},
|
||||
{0x0000u, {0x5a5a7c00u, 0x5a5a7c00u, 0x5a5a7c00u, 0x5a5a7c00u}},
|
||||
{0x3c00u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0xbc00u, {0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u}},
|
||||
{0x4400u, {0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u, 0x5a5a3800u}},
|
||||
};
|
||||
|
||||
constexpr Vector SinRows[] = {
|
||||
{0x0001u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0006u}},
|
||||
{0x0200u, {0x5a5a0000u, 0x5a5a0a48u, 0x5a5a0000u, 0x5a5a0a48u}},
|
||||
{0x03ffu, {0x5a5a0000u, 0x5a5a0e47u, 0x5a5a0000u, 0x5a5a0e47u}},
|
||||
{0x8001u, {0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u, 0x5a5a8006u}},
|
||||
{0x8200u, {0x5a5a8000u, 0x5a5a8a48u, 0x5a5a8000u, 0x5a5a8a48u}},
|
||||
{0x83ffu, {0x5a5a8000u, 0x5a5a8e47u, 0x5a5a8000u, 0x5a5a8e47u}},
|
||||
{0x0400u, {0x5a5a0e48u, 0x5a5a0e48u, 0x5a5a0e48u, 0x5a5a0e48u}},
|
||||
{0x8400u, {0x5a5a8e48u, 0x5a5a8e48u, 0x5a5a8e48u, 0x5a5a8e48u}},
|
||||
{0x0000u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3c00u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0xbc00u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x00a0u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a03edu}},
|
||||
{0x80a0u, {0x5a5a8000u, 0x5a5a8000u, 0x5a5a8000u, 0x5a5a83edu}},
|
||||
{0x3800u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
};
|
||||
|
||||
constexpr Vector SqrtRows[] = {
|
||||
{0x0001u, {0x5a5a0000u, 0x5a5a0c00u, 0x5a5a0000u, 0x5a5a0c00u}},
|
||||
{0x0200u, {0x5a5a0000u, 0x5a5a1da8u, 0x5a5a0000u, 0x5a5a1da8u}},
|
||||
{0x03ffu, {0x5a5a0000u, 0x5a5a1fffu, 0x5a5a0000u, 0x5a5a1fffu}},
|
||||
{0x8001u, {0x5a5a8000u, 0x5a5afe00u, 0x5a5a8000u, 0x5a5afe00u}},
|
||||
{0x8200u, {0x5a5a8000u, 0x5a5afe00u, 0x5a5a8000u, 0x5a5afe00u}},
|
||||
{0x83ffu, {0x5a5a8000u, 0x5a5afe00u, 0x5a5a8000u, 0x5a5afe00u}},
|
||||
{0x0400u, {0x5a5a2000u, 0x5a5a2000u, 0x5a5a2000u, 0x5a5a2000u}},
|
||||
{0x8400u, {0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u}},
|
||||
{0x0000u, {0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u, 0x5a5a0000u}},
|
||||
{0x3c00u, {0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u, 0x5a5a3c00u}},
|
||||
{0xbc00u, {0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u, 0x5a5afe00u}},
|
||||
{0x4400u, {0x5a5a4000u, 0x5a5a4000u, 0x5a5a4000u, 0x5a5a4000u}},
|
||||
};
|
||||
|
||||
constexpr Case Cases[] = {
|
||||
{"v_ceil_f16", 0x7e14b904u, CeilRows},
|
||||
{"v_cvt_f32_f16", 0x7e141704u, CvtF32Rows},
|
||||
{"v_cvt_norm_i16_f16", 0x7e14c704u, CvtNormI16Rows},
|
||||
{"v_cvt_norm_u16_f16", 0x7e14c904u, CvtNormU16Rows},
|
||||
{"v_exp_f16", 0x7e14b104u, ExpRows},
|
||||
{"v_floor_f16", 0x7e14b704u, FloorRows},
|
||||
{"v_fract_f16", 0x7e14bf04u, FractRows},
|
||||
{"v_frexp_exp_i16_f16", 0x7e14b504u, FrexpExpRows},
|
||||
{"v_frexp_mant_f16", 0x7e14b304u, FrexpMantRows},
|
||||
{"v_log_f16", 0x7e14af04u, LogRows},
|
||||
{"v_rcp_f16", 0x7e14a904u, RcpRows},
|
||||
{"v_rsq_f16", 0x7e14ad04u, RsqRows},
|
||||
{"v_sin_f16", 0x7e14c104u, SinRows},
|
||||
{"v_sqrt_f16", 0x7e14ab04u, SqrtRows},
|
||||
};
|
||||
|
||||
constexpr std::uint32_t CaseCount = std::size(Cases);
|
||||
std::array<Shader, CaseCount> Shaders{};
|
||||
|
||||
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, 0x31016facu};
|
||||
}
|
||||
|
||||
std::string Hex(std::uint32_t value) {
|
||||
char text[16];
|
||||
std::snprintf(text, sizeof(text), "0x%08x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device, const Case& item, const Shader& shader, std::uint32_t denorm16, bool ieee) {
|
||||
Input.fill(0u);
|
||||
for (std::uint32_t row = 0; row < item.rows.size(); ++row) {
|
||||
Input[row * Inputs] = item.rows[row].half;
|
||||
}
|
||||
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(shader.words);
|
||||
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;
|
||||
request.context.floatMode = ShaderRecompiler::ShaderFloatMode{(3u << 4u) | (denorm16 << 6u), true, ieee, false};
|
||||
const auto result = ShaderRecompiler::Recompile(request);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void Check(const Case& item, std::uint32_t denorm16, bool ieee) {
|
||||
for (std::uint32_t row = 0; row < item.rows.size(); ++row) {
|
||||
const auto actual = Output[row];
|
||||
const auto expected = item.rows[row].expected[denorm16];
|
||||
Require(actual == expected, std::string(item.name) + " denorm16 " + std::to_string(denorm16) + (ieee ? " ieee" : " no ieee") + " input " +
|
||||
Hex(item.rows[row].half) + " is " + Hex(actual) + ", expected " + Hex(expected));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
for (std::uint32_t index = 0; index < CaseCount; ++index) {
|
||||
Shaders[index].words = {0x34020084u, 0x34040082u, 0xe0381000u, 0x80000401u, 0xbf8c3f70u, 0x7e1402ffu, 0x5a5a5a5au, Cases[index].word,
|
||||
0xe0701000u, 0x80010a02u, 0xbf810000u};
|
||||
for (std::uint32_t denorm16 = 0u; denorm16 < 4u; ++denorm16) {
|
||||
for (const bool ieee : {false, true}) {
|
||||
Run(*device, Cases[index], Shaders[index], denorm16, ieee);
|
||||
Check(Cases[index], denorm16, ieee);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::puts("f16 denormal flush tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -61,6 +61,10 @@ private:
|
|||
void write16Bits(const RdnaOperand& operand, IrU32 value);
|
||||
void writeF16(const RdnaOperand& operand, IrF32 value, std::initializer_list<IrValue*> sources);
|
||||
bool directedF16Rounding() const;
|
||||
IrU32 flushF16Bits(IrU32 bits, std::uint32_t keepBit);
|
||||
IrU32 flushF16Input(IrU32 bits);
|
||||
IrU32 flushF16Result(IrU32 bits);
|
||||
IrF32 flushF16InputValue(IrF32 value);
|
||||
IrU32 convertF32ToF16Bits(IrF32 value, std::initializer_list<IrValue*> sources);
|
||||
void writeF16Conversion(const RdnaOperand& operand, IrF32 value, std::initializer_list<IrValue*> sources);
|
||||
IrU32 readU32(const RdnaOperand& operand);
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ void TranslationContext::vCvtF16F32(const RdnaInstruction& inst) {
|
|||
}
|
||||
|
||||
void TranslationContext::vCvtF32F16(const RdnaInstruction& inst) {
|
||||
const IrF32 value = readF16AsF32(sourceAt(inst, 0u));
|
||||
const IrF32 value = flushF16InputValue(readF16AsF32(sourceAt(inst, 0u)));
|
||||
writeOperand(inst.destination, &value.Value());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,12 +104,13 @@ bool TranslationContext::packedFloat16(const RdnaInstruction& inst, IrOpcode opc
|
|||
|
||||
bool TranslationContext::float16Unary(const RdnaInstruction& inst, IrOpcode opcode) {
|
||||
const RdnaOperand& operand = sourceAt(inst, 0u);
|
||||
const IrF32 argument = readF16AsF32(operand);
|
||||
const IrF32 argument = flushF16InputValue(readF16AsF32(operand));
|
||||
const auto [result, invalid] = unaryFloatSpecials(opcode, argument, IrF32(ir.Emit(opcode, IrType::F32, {&argument.Value()})));
|
||||
IrU32 bits = packHalf2x16(applyF16ResultModifiers(inst.destination, clampF16Overflow(result, {&argument.Value()})), IrF32(ir.ConstantF32(0.0f)));
|
||||
if (opcode == IrOpcode::FPFract32) {
|
||||
bits = IrU32(ir.Select(ir.IEqual(bits.Value(), ir.Constant(0x3c00u)), ir.Constant(0x3bffu), bits.Value()));
|
||||
}
|
||||
bits = flushF16Result(bits);
|
||||
const IrU32 half = readF16Bits(operand);
|
||||
const IrU1 nan(ir.UGreaterThan(ir.BitwiseAnd(half.Value(), ir.Constant(0x7fffu)), ir.Constant(0x7c00u)));
|
||||
const IrU32 special(ir.Select(nan.Value(), quietNan16(half).Value(), ir.Constant(0xfe00u)));
|
||||
|
|
@ -344,11 +345,7 @@ IrU32 TranslationContext::normF32(IrU32 bits, bool signedValue) {
|
|||
|
||||
bool TranslationContext::vLdexpF16(const RdnaInstruction& inst) {
|
||||
const IrU32 source = readF16Bits(sourceAt(inst, 0u));
|
||||
IrU32 bits = source;
|
||||
if (floatMode.has_value() && (floatMode->floatMode & 0x40u) == 0u) {
|
||||
const IrU1 tiny(ir.ULessThan(ir.BitwiseAnd(bits.Value(), ir.Constant(0x7fffu)), ir.Constant(0x0400u)));
|
||||
bits = IrU32(ir.Select(tiny.Value(), ir.BitwiseAnd(bits.Value(), ir.Constant(0x8000u)), bits.Value()));
|
||||
}
|
||||
const IrU32 bits = flushF16Input(source);
|
||||
const IrF16 half(ir.Emit(IrOpcode::BitCastF16U16, IrType::F16, {&ir.Emit(IrOpcode::ConvertU16U32, IrType::U16, {&bits.Value()})}));
|
||||
const IrF32 value(ir.Emit(IrOpcode::ConvertF32F16, IrType::F32, {&half.Value()}));
|
||||
const RdnaOperand& exponentSource = sourceAt(inst, 1u);
|
||||
|
|
@ -368,8 +365,8 @@ bool TranslationContext::vLdexpF16(const RdnaInstruction& inst) {
|
|||
}
|
||||
|
||||
bool TranslationContext::vFrexpF16(const RdnaInstruction& inst, bool exponent) {
|
||||
const IrU32 bits = readF16Bits(sourceAt(inst, 0u));
|
||||
const IrF32 value = readF16AsF32(sourceAt(inst, 0u));
|
||||
const IrU32 bits = flushF16Input(readF16Bits(sourceAt(inst, 0u)));
|
||||
const IrF32 value = flushF16InputValue(readF16AsF32(sourceAt(inst, 0u)));
|
||||
const IrU32 word(ir.BitCastU32(value.Value()));
|
||||
const IrU1 special(ir.LogicalOr(ir.IEqual(ir.BitwiseAnd(bits.Value(), ir.Constant(0x7fffu)), ir.Constant(0u)),
|
||||
ir.Emit(IrOpcode::UGreaterThanEqual32, IrType::U1, {&ir.BitwiseAnd(bits.Value(), ir.Constant(0x7fffu)), &ir.Constant(0x7c00u)})));
|
||||
|
|
@ -388,7 +385,7 @@ bool TranslationContext::vFrexpF16(const RdnaInstruction& inst, bool exponent) {
|
|||
}
|
||||
|
||||
bool TranslationContext::vCvtNormF16(const RdnaInstruction& inst, bool signedValue) {
|
||||
write16Bits(inst.destination, normF16(readF16Bits(sourceAt(inst, 0u)), signedValue));
|
||||
write16Bits(inst.destination, normF16(flushF16Input(readF16Bits(sourceAt(inst, 0u))), signedValue));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -160,6 +160,27 @@ bool TranslationContext::directedF16Rounding() const {
|
|||
return floatMode.has_value() && ((floatMode->floatMode >> 2u) & 3u) != 0u && ((floatMode->floatMode >> 6u) & 3u) == 3u;
|
||||
}
|
||||
|
||||
IrU32 TranslationContext::flushF16Bits(IrU32 bits, std::uint32_t keepBit) {
|
||||
if (!floatMode.has_value() || (floatMode->floatMode & keepBit) != 0u) return bits;
|
||||
const IrU1 tiny(ir.ULessThan(ir.BitwiseAnd(bits.Value(), ir.Constant(0x7fffu)), ir.Constant(0x0400u)));
|
||||
return IrU32(ir.Select(tiny.Value(), ir.BitwiseAnd(bits.Value(), ir.Constant(0x8000u)), bits.Value()));
|
||||
}
|
||||
|
||||
IrU32 TranslationContext::flushF16Input(IrU32 bits) {
|
||||
return flushF16Bits(bits, 0x40u);
|
||||
}
|
||||
|
||||
IrU32 TranslationContext::flushF16Result(IrU32 bits) {
|
||||
return flushF16Bits(bits, 0x80u);
|
||||
}
|
||||
|
||||
IrF32 TranslationContext::flushF16InputValue(IrF32 value) {
|
||||
if (!floatMode.has_value() || (floatMode->floatMode & 0x40u) != 0u) return value;
|
||||
const IrU32 bits(ir.BitCastU32(value.Value()));
|
||||
const IrU1 tiny(ir.ULessThan(ir.BitwiseAnd(bits.Value(), ir.Constant(0x7fffffffu)), ir.Constant(0x38800000u)));
|
||||
return IrF32(ir.BitCastF32(ir.Select(tiny.Value(), ir.BitwiseAnd(bits.Value(), ir.Constant(0x80000000u)), bits.Value())));
|
||||
}
|
||||
|
||||
IrU32 TranslationContext::convertF32ToF16Bits(IrF32 value, std::initializer_list<IrValue*> sources) {
|
||||
const IrF16 half(ir.Emit(IrOpcode::ConvertF16F32, IrType::F16, {&clampF16Overflow(value, sources).Value()}));
|
||||
const IrU32 native(ir.Emit(IrOpcode::ConvertU32U16, IrType::U32, {&ir.Emit(IrOpcode::BitCastU16F16, IrType::U16, {&half.Value()})}));
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue