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:
Adrià Franch 2026-10-04 11:45:59 +02:00
parent 00407df8a9
commit e58e2f0605
4 changed files with 225 additions and 19 deletions

View File

@ -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;
}
}

View File

@ -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");

View File

@ -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;
}

View File

@ -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;
}