feat(shader): accept float modifiers on v_cndmask_b32, v_mul_legacy_f32 and v_ldexp_f16
- v_cndmask_b32: neg/abs on DPP; neg/abs applied on the bits, as the hardware does - v_mul_legacy_f32: neg/abs on DPP and SDWA, clamp/omod on SDWA and VOP3 - v_ldexp_f16: neg/abs on src0 for VOP3, DPP and SDWA; NaN result chosen on the bits Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
00407df8a9
commit
e58e2f0605
|
|
@ -0,0 +1,192 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Inputs = 4;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Inputs> Input{};
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 77> Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0x7d8a0c80, 0x7e1402ff, 0xdeadbeef,
|
||||
0x7e1602ff, 0xdeadbeef, 0x7e1802ff, 0xdeadbeef, 0x7e1a02ff, 0xdeadbeef, 0x7e1c02ff, 0xdeadbeef,
|
||||
0x7e1e02ff, 0xdeadbeef, 0x7e2002ff, 0xdeadbeef, 0x7e2202ff, 0xdeadbeef, 0x7e2402ff, 0xdeadbeef,
|
||||
0x7e2602ff, 0xdeadbeef, 0x7e2802ff, 0xdeadbeef, 0x7e2a02ff, 0xdeadbeef, 0x7e2c02ff, 0xdeadbeef,
|
||||
0x7e2e02ff, 0xdeadbeef, 0x7e3002ff, 0xdeadbeef, 0x7e3202ff, 0xdeadbeef, 0x02140afa, 0xff10e404,
|
||||
0x02160afa, 0xffe0e404, 0xd501020c, 0x21aa0b04, 0x021a0af9, 0x16360604, 0x0e1c0afa, 0xff90e404,
|
||||
0x0e1e0af9, 0x16360604, 0x0e200af9, 0x06062604, 0x0e220af9, 0x16064604, 0xd5078012, 0x1a020b04,
|
||||
0xd5070013, 0x32020b04, 0xd5078314, 0x42020b04, 0xd53b0015, 0x22020b04, 0x762c0afa, 0xff20e404,
|
||||
0x762e0af9, 0x06360604, 0xd53b0118, 0x02020b04, 0xe0781000, 0x80010a03, 0xe0781010, 0x80010e03,
|
||||
0xe0781020, 0x80011203, 0xe0781030, 0x80011603, 0xbf810000,
|
||||
};
|
||||
|
||||
constexpr std::uint32_t Rows[32][4] = {
|
||||
{0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u},
|
||||
{0x00000000u, 0x7f800000u, 0x00000001u, 0x00000000u},
|
||||
{0x3fc00000u, 0x3fc00000u, 0x00000001u, 0x00000000u},
|
||||
{0x3fc00000u, 0x7f800000u, 0x00000000u, 0x00000000u},
|
||||
{0xbf800000u, 0x3f800000u, 0x00000001u, 0x00000000u},
|
||||
{0x3fc00000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0xc0000000u, 0xabcdbc00u, 0x00000000u, 0x00000000u},
|
||||
{0x3fc00000u, 0xff800000u, 0x00000000u, 0x00000000u},
|
||||
{0xc0000000u, 0xff61b1e6u, 0x00000000u, 0x00000000u},
|
||||
{0x3e800000u, 0xc0000000u, 0x00000001u, 0x00000000u},
|
||||
{0x3e800000u, 0xbf800000u, 0x00000001u, 0x00000000u},
|
||||
{0x3f800000u, 0xbf800000u, 0x00000000u, 0x00000000u},
|
||||
{0xc0000000u, 0x7f800000u, 0x00000001u, 0x00000000u},
|
||||
{0x3e800000u, 0x3f800000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x3fc00000u, 0x00000001u, 0x00000000u},
|
||||
{0x807fffffu, 0x00000000u, 0x00000001u, 0x00000000u},
|
||||
{0x3f19999au, 0x00000001u, 0x00000001u, 0x00000000u},
|
||||
{0x3f19999au, 0x00003555u, 0x00000000u, 0x00000000u},
|
||||
{0x3f19999au, 0xffffffe2u, 0x00000001u, 0x00000000u},
|
||||
{0x00003c00u, 0x00000000u, 0x00000001u, 0x00000000u},
|
||||
{0x00003c00u, 0x00003c00u, 0x00000000u, 0x00000000u},
|
||||
{0x00007e01u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x807fffffu, 0x00000001u, 0x00000000u},
|
||||
{0x00000000u, 0x7fc00001u, 0x00000001u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x80000000u, 0xc0000000u, 0x00000001u, 0x00000000u},
|
||||
{0x80000000u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x80000000u, 0x807fffffu, 0x00000000u, 0x00000000u},
|
||||
{0x80000000u, 0x7fc00001u, 0x00000001u, 0x00000000u},
|
||||
{0x80000000u, 0xffc00000u, 0x00000000u, 0x00000000u},
|
||||
{0x80000000u, 0x00007e01u, 0x00000001u, 0x00000000u}
|
||||
};
|
||||
constexpr std::uint32_t Expected[32][15] = {
|
||||
{0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x7f800000u, 0xff800000u, 0x7f800000u, 0xff800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x3fc00000u, 0xbfc00000u, 0x3fc00000u, 0xbfc00000u, 0xc0100000u, 0x40100000u, 0x3f800000u, 0xc0900000u, 0x3f800000u, 0xc1100000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0xbfc00000u, 0x3fc00000u, 0xbfc00000u, 0xbfc00000u, 0xff800000u, 0x7f800000u, 0x3f800000u, 0xff800000u, 0x3f800000u, 0xff800000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x3f800000u, 0xbf800000u, 0x3f800000u, 0xbf800000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x40000000u, 0x00000000u, 0x40800000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0xbfc00000u, 0x3fc00000u, 0xbfc00000u, 0xbfc00000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x40000000u, 0x40000000u, 0x40000000u, 0xc0000000u, 0x2c4dbc00u, 0xac4dbc00u, 0x2c4dbc00u, 0xaccdbc00u, 0x2bcdbc00u, 0xad4dbc00u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0xbfc00000u, 0x3fc00000u, 0xbfc00000u, 0xbfc00000u, 0xff800000u, 0xff800000u, 0x00000000u, 0x7f800000u, 0x00000000u, 0x7f800000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x40000000u, 0x40000000u, 0x40000000u, 0xc0000000u, 0x7f800000u, 0xff800000u, 0x3f800000u, 0xff800000u, 0x3f800000u, 0xff800000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0xc0000000u, 0xc0000000u, 0x40000000u, 0x40000000u, 0xbf000000u, 0xbf000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x40000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0xbf800000u, 0xbf800000u, 0x3f800000u, 0x3f800000u, 0xbe800000u, 0xbe800000u, 0x00000000u, 0x3f000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0xbf800000u, 0x3f800000u, 0xbf800000u, 0xbf800000u, 0xbf800000u, 0xbf800000u, 0x00000000u, 0x40000000u, 0x00000000u, 0x40800000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x7f800000u, 0xff800000u, 0x7f800000u, 0xff800000u, 0x7f800000u, 0x7f800000u, 0x00000000u, 0x7f800000u, 0x00000000u, 0x7f800000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0xbe800000u, 0x3e800000u, 0xbe800000u, 0xbe800000u, 0xbe800000u, 0x3e800000u, 0x3e800000u, 0xbf000000u, 0x3e000000u, 0xbf800000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x80000000u, 0x00000000u, 0x80000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x3fc00000u, 0xbfc00000u, 0x3fc00000u, 0xbfc00000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead7fffu, 0xdead7fffu, 0x0000ffffu, 0xdead7fffu},
|
||||
{0x00000001u, 0x80000001u, 0x00000001u, 0x80000001u, 0x80000001u, 0x00000001u, 0x00000001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead1d9au, 0xdead1d9au, 0x00009d9au, 0xdead1d9au},
|
||||
{0xbf19999au, 0x3f19999au, 0xbf19999au, 0xbf19999au, 0x80002000u, 0x00002000u, 0x00002000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead7c00u, 0xdead7c00u, 0x0000fc00u, 0xdead7c00u},
|
||||
{0xffffffe2u, 0xffffffe2u, 0x7fffffe2u, 0x7fffffe2u, 0x7fffffe2u, 0x7fffffe2u, 0x00000000u, 0x7fffffe2u, 0x00000000u, 0xffffffe2u, 0x00000000u, 0xdead0000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdeadbc00u, 0xdead3c00u, 0x0000bc00u, 0xdead3c00u},
|
||||
{0x80003c00u, 0x00003c00u, 0x80003c00u, 0x80003c00u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdeadfc00u, 0xdead7c00u, 0x0000fc00u, 0xdead7c00u},
|
||||
{0x80007e01u, 0x00007e01u, 0x80007e01u, 0x80007e01u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdeadfe01u, 0xdead7e01u, 0x0000fe01u, 0xdead7e01u},
|
||||
{0x807fffffu, 0x807fffffu, 0x007fffffu, 0x007fffffu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x7fc00001u, 0xffc00001u, 0x7fc00001u, 0xffc00001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0xc0000000u, 0xc0000000u, 0x40000000u, 0x40000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x7fc00001u, 0xffc00001u, 0x7fc00001u, 0xffc00001u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u},
|
||||
{0x00007e01u, 0x80007e01u, 0x00007e01u, 0x80007e01u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0xdead8000u, 0xdead0000u, 0x00008000u, 0xdead0000u}
|
||||
};
|
||||
constexpr std::uint32_t Checked[32] = {0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x7fffu, 0x780fu, 0x780fu, 0x780fu, 0x780fu, 0x780fu, 0x780fu, 0x780fu, 0x780fu, 0x780fu, 0x7fffu, 0x7fffu, 0x780fu, 0x780fu, 0x780fu, 0x780fu, 0x780fu};
|
||||
constexpr const char* Names[15] = {
|
||||
"v_cndmask_b32_dpp v10, -v4, v5, vcc_lo",
|
||||
"v_cndmask_b32_dpp v11, |v4|, -|v5|, vcc_lo",
|
||||
"v_cndmask_b32_e64 v12, -v4, |v5|, vcc_lo",
|
||||
"v_cndmask_b32_sdwa v13, -|v4|, -v5, vcc_lo",
|
||||
"v_mul_legacy_f32_dpp v14, -v4, |v5|",
|
||||
"v_mul_legacy_f32_sdwa v15, -|v4|, -v5",
|
||||
"v_mul_legacy_f32_sdwa v16, v4, v5 clamp",
|
||||
"v_mul_legacy_f32_sdwa v17, v4, -v5 mul:2",
|
||||
"v_mul_legacy_f32_e64 v18, v4, v5 clamp div:2",
|
||||
"v_mul_legacy_f32_e64 v19, -v4, v5 mul:4",
|
||||
"v_mul_legacy_f32_e64 v20, |v4|, -|v5| clamp",
|
||||
"v_ldexp_f16_e64 v21, -v4, v5",
|
||||
"v_ldexp_f16_dpp v22, |v4|, v5",
|
||||
"v_ldexp_f16_sdwa v23, -|v4|, v5",
|
||||
"v_ldexp_f16_e64 v24, |v4|, v5",
|
||||
};
|
||||
|
||||
void Fill(std::uint32_t tid, std::uint32_t* words) {
|
||||
std::copy(std::begin(Rows[tid]), std::end(Rows[tid]), words);
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t bytes) {
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(data);
|
||||
return {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>((address >> 32u) & 0xffffu), bytes, 0x01016facu};
|
||||
}
|
||||
|
||||
std::string Hex(std::uint32_t value) {
|
||||
char text[16];
|
||||
std::snprintf(text, sizeof(text), "0x%08x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Expect(std::uint32_t tid, std::uint32_t actual, std::uint32_t expected, const char* name) {
|
||||
Require(actual == expected, std::string("vop2 modifier forms: lane ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected));
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) Fill(tid, &Input[tid * Inputs]);
|
||||
Output.fill(0xdeadbeefu);
|
||||
std::vector<std::uint32_t> userData(8, 0u);
|
||||
const auto input = BufferDescriptor(Input.data(), static_cast<std::uint32_t>(Input.size() * 4u));
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(input.begin(), input.end(), userData.begin());
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
const std::span<const std::uint32_t> code(Code);
|
||||
const std::array<ShaderRecompiler::MemoryRegion, 1> memory{{{reinterpret_cast<std::uintptr_t>(code.data()), std::as_bytes(code)}}};
|
||||
const ShaderRecompiler::ShaderComputeStageInfo compute{{Threads, 1, 1}, 0u, {false, false, false}, false, 1};
|
||||
ShaderRecompiler::RecompileRequest request{
|
||||
{ShaderStage::Compute, reinterpret_cast<std::uintptr_t>(code.data()), code, 0, {}},
|
||||
{32, 0, userData, compute, std::nullopt, std::nullopt, memory},
|
||||
device.Target(),
|
||||
{0, 0, 0, 128}
|
||||
};
|
||||
request.useCache = false;
|
||||
const auto result = ShaderRecompiler::Recompile(request);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void Check() {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const std::uint32_t* in = &Input[tid * Inputs];
|
||||
const std::uint32_t* out = &Output[tid * Results];
|
||||
for (std::uint32_t i = 0; i < 15; ++i) {
|
||||
if ((Checked[tid] >> i) & 1u) Expect(tid, out[i], Expected[tid][i], Names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
Run(*device);
|
||||
Check();
|
||||
std::puts("vop2 modifier forms tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1026,11 +1026,22 @@ bool isVop2FloatOpcode(RdnaOpcode opcode) {
|
|||
case RdnaOpcode::VFmamkF16:
|
||||
case RdnaOpcode::VFmaakF16:
|
||||
case RdnaOpcode::VMaxF16:
|
||||
case RdnaOpcode::VMinF16: return true;
|
||||
case RdnaOpcode::VMinF16:
|
||||
case RdnaOpcode::VMulLegacyF32: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasUnsupportedVop2SourceModifiers(RdnaOpcode opcode, bool src0Modified, bool src1Modified) {
|
||||
if (isVop2FloatOpcode(opcode) || opcode == RdnaOpcode::VCndmaskB32) {
|
||||
return false;
|
||||
}
|
||||
if (opcode == RdnaOpcode::VLdexpF16) {
|
||||
return src1Modified;
|
||||
}
|
||||
return src0Modified || src1Modified;
|
||||
}
|
||||
|
||||
bool usesInexactClampControl(RdnaOpcode opcode) {
|
||||
return opcode == RdnaOpcode::VCvtU32F32 || opcode == RdnaOpcode::VCvtI32F32 ||
|
||||
opcode == RdnaOpcode::VCvtU16F16 || opcode == RdnaOpcode::VCvtI16F16;
|
||||
|
|
@ -1329,8 +1340,7 @@ void validateVop2Sdwa(const RdnaInstruction& instruction, std::uint32_t opcode,
|
|||
throw std::invalid_argument("VOP2 SDWA output modifiers are not supported");
|
||||
}
|
||||
if (isFullWidthVop2Sdwa(fields)) {
|
||||
if (!isVop2FloatOpcode(instruction.op) && instruction.op != RdnaOpcode::VCndmaskB32 &&
|
||||
(fields.src0Neg != 0u || fields.src0Abs != 0u || fields.src1Neg != 0u || fields.src1Abs != 0u)) {
|
||||
if (hasUnsupportedVop2SourceModifiers(instruction.op, fields.src0Neg != 0u || fields.src0Abs != 0u, fields.src1Neg != 0u || fields.src1Abs != 0u)) {
|
||||
throw std::invalid_argument("VOP2 SDWA source modifiers are not supported");
|
||||
}
|
||||
return;
|
||||
|
|
@ -1440,8 +1450,7 @@ void decodeVop2Dpp(std::uint32_t programCounter, std::span<const std::uint32_t>
|
|||
instruction.source1.negateHi = instruction.source1.negate;
|
||||
}
|
||||
|
||||
if (!isVop2FloatOpcode(instruction.op) && !packedFmac &&
|
||||
(instruction.source0.negate || instruction.source0.absolute || instruction.source1.negate || instruction.source1.absolute)) {
|
||||
if (!packedFmac && hasUnsupportedVop2SourceModifiers(instruction.op, instruction.source0.negate || instruction.source0.absolute, instruction.source1.negate || instruction.source1.absolute)) {
|
||||
throw std::invalid_argument("VOP2 DPP integer source modifiers are not supported");
|
||||
}
|
||||
finalizeVop2Instruction(code, wordIndex, instruction);
|
||||
|
|
@ -1863,7 +1872,8 @@ bool supportsNativeVop3SourceModifiers(RdnaOpcode opcode) {
|
|||
case RdnaOpcode::VMinF64:
|
||||
case RdnaOpcode::VMaxF64:
|
||||
case RdnaOpcode::VLdexpF64:
|
||||
case RdnaOpcode::VTrigPreopF64: return true;
|
||||
case RdnaOpcode::VTrigPreopF64:
|
||||
case RdnaOpcode::VLdexpF16: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1877,6 +1887,7 @@ bool supportsNativeVop3ResultModifiers(RdnaOpcode opcode) {
|
|||
case RdnaOpcode::VSubF32:
|
||||
case RdnaOpcode::VSubrevF32:
|
||||
case RdnaOpcode::VMulF32:
|
||||
case RdnaOpcode::VMulLegacyF32:
|
||||
case RdnaOpcode::VMinF32:
|
||||
case RdnaOpcode::VMaxF32:
|
||||
case RdnaOpcode::VMacF32:
|
||||
|
|
@ -1947,6 +1958,12 @@ void checkNativeVop3Modifiers(RdnaOpcode opcode, bool permlane, bool carryInOut,
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (opcode == RdnaOpcode::VLdexpF16) {
|
||||
if ((abs & ~1u) != 0u || opSel != 0u || clamp != 0u || omod != 0u || (neg & ~1u) != 0u) {
|
||||
throw std::invalid_argument("VOP3 source modifiers are not implemented");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (opcode == RdnaOpcode::VCndmaskB32) {
|
||||
if ((abs & ~0x3u) != 0u || opSel != 0u || clamp != 0u || omod != 0u || (neg & ~0x3u) != 0u) {
|
||||
throw std::invalid_argument("VOP3 source modifiers are not implemented");
|
||||
|
|
|
|||
|
|
@ -173,11 +173,16 @@ IrU32 TranslationContext::normF16(IrU32 bits, bool signedValue) {
|
|||
}
|
||||
|
||||
bool TranslationContext::vLdexpF16(const RdnaInstruction& inst) {
|
||||
const IrF32 value = readF16AsF32(sourceAt(inst, 0u));
|
||||
const IrU32 bits = readF16Bits(sourceAt(inst, 0u));
|
||||
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 IrU32 exponent(ir.Emit(IrOpcode::BitFieldSExtract, IrType::U32, {&readU32(sourceAt(inst, 1u)).Value(), &ir.Constant(0u), &ir.Constant(16u)}));
|
||||
const IrU32 clamped(ir.Emit(IrOpcode::SMax32, IrType::U32, {&ir.Emit(IrOpcode::SMin32, IrType::U32, {&exponent.Value(), &ir.Constant(64u)}), &ir.Constant(static_cast<std::uint32_t>(-64))}));
|
||||
IrValue& power = ir.BitCastF32(ir.ShiftLeftLogical(ir.IAdd(clamped.Value(), ir.Constant(127u)), ir.Constant(23u)));
|
||||
writeF16(inst.destination, IrF32(ir.Emit(IrOpcode::FPMul32, IrType::F32, {&value.Value(), &power})));
|
||||
const IrF16 scaled(ir.Emit(IrOpcode::ConvertF16F32, IrType::F16, {&ir.Emit(IrOpcode::FPMul32, IrType::F32, {&value.Value(), &power})}));
|
||||
const IrU32 result(ir.Emit(IrOpcode::ConvertU32U16, IrType::U32, {&ir.Emit(IrOpcode::BitCastU16F16, IrType::U16, {&scaled.Value()})}));
|
||||
const IrU1 nan(ir.UGreaterThan(ir.BitwiseAnd(bits.Value(), ir.Constant(0x7fffu)), ir.Constant(0x7c00u)));
|
||||
write16Bits(inst.destination, IrU32(ir.Select(nan.Value(), ir.BitwiseOr(bits.Value(), ir.Constant(0x200u)), result.Value())));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -802,17 +802,9 @@ bool TranslationContext::vCndmaskB32(const RdnaInstruction& inst) {
|
|||
const IrU1 condition = readMask(maskOperand);
|
||||
const RdnaOperand& falseOperand = sourceAt(inst, 0u);
|
||||
const RdnaOperand& trueOperand = sourceAt(inst, 1u);
|
||||
IrValue* result = nullptr;
|
||||
if (falseOperand.negate || falseOperand.absolute || trueOperand.negate || trueOperand.absolute) {
|
||||
IrValue* falseValue = readOperand(falseOperand, IrType::F32);
|
||||
IrValue* trueValue = readOperand(trueOperand, IrType::F32);
|
||||
result = &ir.Emit(IrOpcode::SelectF32, IrType::F32, {&condition.Value(), trueValue, falseValue});
|
||||
} else {
|
||||
const IrU32 falseValue = readU32(falseOperand);
|
||||
const IrU32 trueValue = readU32(trueOperand);
|
||||
result = &ir.Select(condition.Value(), trueValue.Value(), falseValue.Value());
|
||||
}
|
||||
writeOperand(inst.destination, result);
|
||||
const IrU32 falseValue = readU32(falseOperand);
|
||||
const IrU32 trueValue = readU32(trueOperand);
|
||||
writeOperand(inst.destination, &ir.Select(condition.Value(), trueValue.Value(), falseValue.Value()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue