feat(shader): implement the missing non-f64 VOPC compares

Fifty VOPC opcodes threw in the decoder: cmpx f/o/u/tru for f32, cmpx f/t
for i32/u32, the 64-bit integer compares except the seven already present,
and the f16 f/o/u/nge/nlg/ngt/nle/nlt/tru compares and their cmpx forms.
64-bit gt/le/ge are built from SLessThan64/ULessThan64 by swapping and
negating, as the IR has no other 64-bit orderings. emitFloatOrderedCompare
gains the f16 and cmpx forms.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Adrià Franch 2026-10-01 22:17:16 +02:00
parent 8ed454d2fa
commit b6376737bb
7 changed files with 603 additions and 7 deletions

View File

@ -0,0 +1,237 @@
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
#include "Recompiler.hpp"
#include "VulkanTestDevice.hpp"
#include <array>
#include <bit>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <limits>
#include <string>
#include <vector>
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 = 4;
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, 364> CompareCode{
0x34020083, 0x34060082, 0xe0302000, 0x80000401, 0xe0302004, 0x80000501, 0xe0302008, 0x80000601,
0xe030200c, 0x80000701, 0xe0302010, 0x80000801, 0xe0302014, 0x80000901, 0xe0302018, 0x80000e01,
0xe030201c, 0x80000f01, 0x7e140280, 0x7e160280, 0xbf8c3f70, 0xbe9e037e, 0x7e280280, 0x7c200b04,
0x7e280281, 0xbefe031e, 0xd76f000a, 0x04290114, 0xbe9e037e, 0x7e280280, 0x7c2e0b04, 0x7e280281,
0xbefe031e, 0xd76f000a, 0x04290314, 0xbe9e037e, 0x7e280280, 0x7c300b04, 0x7e280281, 0xbefe031e,
0xd76f000a, 0x04290514, 0xbe9e037e, 0x7e280280, 0x7c3e0b04, 0x7e280281, 0xbefe031e, 0xd76f000a,
0x04290714, 0xbe9e037e, 0x7e280280, 0x7d200b04, 0x7e280281, 0xbefe031e, 0xd76f000a, 0x04290914,
0xbe9e037e, 0x7e280280, 0x7d2e0b04, 0x7e280281, 0xbefe031e, 0xd76f000a, 0x04290b14, 0xbe9e037e,
0x7e280280, 0x7da00b04, 0x7e280281, 0xbefe031e, 0xd76f000a, 0x04290d14, 0xbe9e037e, 0x7e280280,
0x7dae0b04, 0x7e280281, 0xbefe031e, 0xd76f000a, 0x04290f14, 0x7d401106, 0xd5010014, 0x01a90280,
0xd76f000a, 0x04291114, 0x7d421106, 0xd5010014, 0x01a90280, 0xd76f000a, 0x04291314, 0x7d461106,
0xd5010014, 0x01a90280, 0xd76f000a, 0x04291514, 0x7d481106, 0xd5010014, 0x01a90280, 0xd76f000a,
0x04291714, 0x7d4a1106, 0xd5010014, 0x01a90280, 0xd76f000a, 0x04291914, 0x7d4c1106, 0xd5010014,
0x01a90280, 0xd76f000a, 0x04291b14, 0x7d4e1106, 0xd5010014, 0x01a90280, 0xd76f000a, 0x04291d14,
0xbe9e037e, 0x7e280280, 0x7d601106, 0x7e280281, 0xbefe031e, 0xd76f000a, 0x04291f14, 0xbe9e037e,
0x7e280280, 0x7d621106, 0x7e280281, 0xbefe031e, 0xd76f000a, 0x04292114, 0xbe9e037e, 0x7e280280,
0x7d641106, 0x7e280281, 0xbefe031e, 0xd76f000a, 0x04292314, 0xbe9e037e, 0x7e280280, 0x7d661106,
0x7e280281, 0xbefe031e, 0xd76f000a, 0x04292514, 0xbe9e037e, 0x7e280280, 0x7d681106, 0x7e280281,
0xbefe031e, 0xd76f000a, 0x04292714, 0xbe9e037e, 0x7e280280, 0x7d6c1106, 0x7e280281, 0xbefe031e,
0xd76f000a, 0x04292914, 0xbe9e037e, 0x7e280280, 0x7d6e1106, 0x7e280281, 0xbefe031e, 0xd76f000a,
0x04292b14, 0x7dc01106, 0xd5010014, 0x01a90280, 0xd76f000a, 0x04292d14, 0x7dc61106, 0xd5010014,
0x01a90280, 0xd76f000a, 0x04292f14, 0x7dcc1106, 0xd5010014, 0x01a90280, 0xd76f000a, 0x04293114,
0x7dce1106, 0xd5010014, 0x01a90280, 0xd76f000a, 0x04293314, 0xbe9e037e, 0x7e280280, 0x7de01106,
0x7e280281, 0xbefe031e, 0xd76f000a, 0x04293514, 0xbe9e037e, 0x7e280280, 0x7de21106, 0x7e280281,
0xbefe031e, 0xd76f000a, 0x04293714, 0xbe9e037e, 0x7e280280, 0x7de41106, 0x7e280281, 0xbefe031e,
0xd76f000a, 0x04293914, 0xbe9e037e, 0x7e280280, 0x7de61106, 0x7e280281, 0xbefe031e, 0xd76f000a,
0x04293b14, 0xbe9e037e, 0x7e280280, 0x7de81106, 0x7e280281, 0xbefe031e, 0xd76f000a, 0x04293d14,
0xbe9e037e, 0x7e280280, 0x7dec1106, 0x7e280281, 0xbefe031e, 0xd76f000a, 0x04293f14, 0xbe9e037e,
0x7e280280, 0x7dee1106, 0x7e280281, 0xbefe031e, 0xd76f000b, 0x042d0114, 0x7d901f0e, 0xd5010014,
0x01a90280, 0xd76f000b, 0x042d0314, 0x7d9e1f0e, 0xd5010014, 0x01a90280, 0xd76f000b, 0x042d0514,
0x7dd01f0e, 0xd5010014, 0x01a90280, 0xd76f000b, 0x042d0714, 0x7dd21f0e, 0xd5010014, 0x01a90280,
0xd76f000b, 0x042d0914, 0x7dd41f0e, 0xd5010014, 0x01a90280, 0xd76f000b, 0x042d0b14, 0x7dd61f0e,
0xd5010014, 0x01a90280, 0xd76f000b, 0x042d0d14, 0x7dd81f0e, 0xd5010014, 0x01a90280, 0xd76f000b,
0x042d0f14, 0x7ddc1f0e, 0xd5010014, 0x01a90280, 0xd76f000b, 0x042d1114, 0x7dde1f0e, 0xd5010014,
0x01a90280, 0xd76f000b, 0x042d1314, 0xbe9e037e, 0x7e280280, 0x7db01f0e, 0x7e280281, 0xbefe031e,
0xd76f000b, 0x042d1514, 0xbe9e037e, 0x7e280280, 0x7dba1f0e, 0x7e280281, 0xbefe031e, 0xd76f000b,
0x042d1714, 0xbe9e037e, 0x7e280280, 0x7dbe1f0e, 0x7e280281, 0xbefe031e, 0xd76f000b, 0x042d1914,
0xbe9e037e, 0x7e280280, 0x7df01f0e, 0x7e280281, 0xbefe031e, 0xd76f000b, 0x042d1b14, 0xbe9e037e,
0x7e280280, 0x7df21f0e, 0x7e280281, 0xbefe031e, 0xd76f000b, 0x042d1d14, 0xbe9e037e, 0x7e280280,
0x7df41f0e, 0x7e280281, 0xbefe031e, 0xd76f000b, 0x042d1f14, 0xbe9e037e, 0x7e280280, 0x7df81f0e,
0x7e280281, 0xbefe031e, 0xd76f000b, 0x042d2114, 0xbe9e037e, 0x7e280280, 0x7dfe1f0e, 0x7e280281,
0xbefe031e, 0xd76f000b, 0x042d2314, 0xd4e9026a, 0x00021f0e, 0xd5010014, 0x01a90280, 0xd76f000b,
0x042d2514, 0xd4a3006a, 0x00020d08, 0xd5010014, 0x01a90280, 0xd76f000b, 0x042d2714, 0xbe9e037e,
0x7e280280, 0xd4f6007e, 0x00020d08, 0x7e280281, 0xbefe031e, 0xd76f000b, 0x042d2914, 0xbe9e037e,
0x7e280280, 0xd417017e, 0x00020b04, 0x7e280281, 0xbefe031e, 0xd76f000b, 0x042d2b14, 0xe0702000,
0x80010a03, 0xe0702004, 0x80010b03, 0xbf810000,
};
constexpr std::array<std::uint32_t, 12> FloatEdges{
0x7fc00000u, 0x3f800000u, 0x80000000u, 0x00000000u, 0x7f800000u, 0xff800000u,
0xbf800000u, 0x3f800000u, 0x00000001u, 0x40490fdbu, 0xffc00001u, 0xc0000000u,
};
constexpr std::array<std::uint16_t, 12> HalfEdges{
0x7e00u, 0x3c00u, 0x8000u, 0x0000u, 0x7c00u, 0xfc00u, 0xbc00u, 0x3c00u, 0x0001u, 0x4248u, 0xfe01u, 0xc000u,
};
constexpr std::array<std::uint64_t, 8> IntegerEdges{
0u, ~0ull, 0x8000000000000000ull, 0x7fffffffffffffffull, 1u, 0x00000001ffffffffull, 0x0000000100000000ull, 0xffffffff00000000ull,
};
float HalfValue(std::uint32_t bits) {
const auto exponent = (bits >> 10u) & 0x1fu;
const auto fraction = bits & 0x3ffu;
float magnitude = 0.0f;
if (exponent == 0x1fu) {
magnitude = fraction != 0u ? std::numeric_limits<float>::quiet_NaN() : std::numeric_limits<float>::infinity();
} else {
magnitude = exponent == 0u ? std::ldexp(static_cast<float>(fraction), -24) : std::ldexp(static_cast<float>(fraction | 0x400u), static_cast<int>(exponent) - 25);
}
return (bits & 0x8000u) != 0u ? -magnitude : magnitude;
}
void FillInput() {
std::uint64_t state = 0x853c49e6748fea9bull;
const auto next = [&] {
state = state * 6364136223846793005ull + 1442695040888963407ull;
return static_cast<std::uint32_t>(state >> 33u);
};
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
auto* words = &Input[tid * Inputs];
words[0] = FloatEdges[tid % FloatEdges.size()];
words[1] = FloatEdges[(tid / FloatEdges.size() + tid) % FloatEdges.size()];
const std::uint64_t a = tid < 16u ? IntegerEdges[tid % IntegerEdges.size()] : (static_cast<std::uint64_t>(next()) << 32u) | next();
const std::uint64_t b = tid < 16u ? IntegerEdges[(tid / IntegerEdges.size() + tid * 3u) % IntegerEdges.size()] : (tid % 5u == 0u ? a : (static_cast<std::uint64_t>(next()) << 32u) | next());
words[2] = static_cast<std::uint32_t>(a);
words[3] = static_cast<std::uint32_t>(a >> 32u);
words[4] = static_cast<std::uint32_t>(b);
words[5] = static_cast<std::uint32_t>(b >> 32u);
words[6] = 0xabcd0000u | HalfEdges[tid % HalfEdges.size()];
words[7] = 0x12340000u | HalfEdges[(tid / HalfEdges.size() + tid * 5u) % HalfEdges.size()];
}
}
std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t count) {
const auto address = reinterpret_cast<std::uintptr_t>(data);
return {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>((address >> 32u) & 0xffffu) | (4u << 16u), count, 0x01016facu};
}
void Run(AgcDriver::VulkanDevice& device) {
Output.fill(0xdeadbeefu);
std::vector<std::uint32_t> userData(8, 0u);
const auto input = BufferDescriptor(Input.data(), static_cast<std::uint32_t>(Input.size()));
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size()));
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(CompareCode);
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}, 0, {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 auto* in = &Input[tid * Inputs];
const float fa = std::bit_cast<float>(in[0]);
const float fb = std::bit_cast<float>(in[1]);
const std::uint64_t ua = in[2] | (static_cast<std::uint64_t>(in[3]) << 32u);
const std::uint64_t ub = in[4] | (static_cast<std::uint64_t>(in[5]) << 32u);
const auto sa = static_cast<std::int64_t>(ua);
const auto sb = static_cast<std::int64_t>(ub);
const float ha = HalfValue(in[6] & 0xffffu);
const float hb = HalfValue(in[7] & 0xffffu);
const std::array<bool, 54> expected{
false,
!std::isnan(fa) && !std::isnan(fb),
std::isnan(fa) || std::isnan(fb),
true,
false,
true,
false,
true,
false,
sa < sb,
sa <= sb,
sa > sb,
sa != sb,
sa >= sb,
true,
false,
sa < sb,
sa == sb,
sa <= sb,
sa > sb,
sa >= sb,
true,
false,
ua <= ub,
ua >= ub,
true,
false,
ua < ub,
ua == ub,
ua <= ub,
ua > ub,
ua >= ub,
true,
false,
!std::isnan(ha) && !std::isnan(hb),
std::isnan(ha) || std::isnan(hb),
!(ha >= hb),
!(ha < hb || ha > hb),
!(ha > hb),
!(ha <= hb),
!(ha < hb),
true,
false,
ha < hb || ha > hb,
!std::isnan(ha) && !std::isnan(hb),
std::isnan(ha) || std::isnan(hb),
!(ha >= hb),
!(ha < hb || ha > hb),
!(ha <= hb),
true,
!(ha >= std::fabs(hb)),
sb <= sa,
ub >= ua,
!std::isnan(fa) && !std::isnan(fb),
};
for (std::uint32_t k = 0; k < expected.size(); ++k) {
const bool actual = ((Output[tid * Results + k / 32u] >> (k % 32u)) & 1u) != 0u;
Require(actual == expected[k], "vopc compares: thread " + std::to_string(tid) + " compare " + std::to_string(k) + " is " + std::to_string(actual) + ", expected " + std::to_string(expected[k]));
}
}
}
}
int main() {
try {
const auto device = OpenVulkanTestDevice();
if (!device) return VulkanTestSkipped;
FillInput();
Run(*device);
Check();
std::puts("vopc compare tests passed");
return 0;
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';
return 1;
}
}

View File

@ -453,6 +453,56 @@ enum class RdnaOpcode : std::uint16_t {
VCmpNeU64,
VCmpxNeI64,
VCmpxNeU64,
VCmpxFF32,
VCmpxOF32,
VCmpxUF32,
VCmpxTruF32,
VCmpxFI32,
VCmpxTI32,
VCmpxFU32,
VCmpxTU32,
VCmpFI64,
VCmpLtI64,
VCmpLeI64,
VCmpGtI64,
VCmpNeI64,
VCmpGeI64,
VCmpTI64,
VCmpxFI64,
VCmpxLtI64,
VCmpxEqI64,
VCmpxLeI64,
VCmpxGtI64,
VCmpxGeI64,
VCmpxTI64,
VCmpFU64,
VCmpLeU64,
VCmpGeU64,
VCmpTU64,
VCmpxFU64,
VCmpxLtU64,
VCmpxEqU64,
VCmpxLeU64,
VCmpxGtU64,
VCmpxGeU64,
VCmpxTU64,
VCmpFF16,
VCmpOF16,
VCmpUF16,
VCmpNgeF16,
VCmpNlgF16,
VCmpNgtF16,
VCmpNleF16,
VCmpNltF16,
VCmpTruF16,
VCmpxFF16,
VCmpxLgF16,
VCmpxOF16,
VCmpxUF16,
VCmpxNgeF16,
VCmpxNlgF16,
VCmpxNleF16,
VCmpxTruF16,
VCmpxLtU32,
VCmpxEqU32,
VCmpxLeU32,

View File

@ -427,6 +427,56 @@ bool IsVectorAluOpcode(RdnaOpcode opcode) {
case RdnaOpcode::VCmpGtU64:
case RdnaOpcode::VCmpNeU64:
case RdnaOpcode::VCmpxNeI64:
case RdnaOpcode::VCmpxFF32:
case RdnaOpcode::VCmpxOF32:
case RdnaOpcode::VCmpxUF32:
case RdnaOpcode::VCmpxTruF32:
case RdnaOpcode::VCmpxFI32:
case RdnaOpcode::VCmpxTI32:
case RdnaOpcode::VCmpxFU32:
case RdnaOpcode::VCmpxTU32:
case RdnaOpcode::VCmpFI64:
case RdnaOpcode::VCmpLtI64:
case RdnaOpcode::VCmpLeI64:
case RdnaOpcode::VCmpGtI64:
case RdnaOpcode::VCmpNeI64:
case RdnaOpcode::VCmpGeI64:
case RdnaOpcode::VCmpTI64:
case RdnaOpcode::VCmpxFI64:
case RdnaOpcode::VCmpxLtI64:
case RdnaOpcode::VCmpxEqI64:
case RdnaOpcode::VCmpxLeI64:
case RdnaOpcode::VCmpxGtI64:
case RdnaOpcode::VCmpxGeI64:
case RdnaOpcode::VCmpxTI64:
case RdnaOpcode::VCmpFU64:
case RdnaOpcode::VCmpLeU64:
case RdnaOpcode::VCmpGeU64:
case RdnaOpcode::VCmpTU64:
case RdnaOpcode::VCmpxFU64:
case RdnaOpcode::VCmpxLtU64:
case RdnaOpcode::VCmpxEqU64:
case RdnaOpcode::VCmpxLeU64:
case RdnaOpcode::VCmpxGtU64:
case RdnaOpcode::VCmpxGeU64:
case RdnaOpcode::VCmpxTU64:
case RdnaOpcode::VCmpFF16:
case RdnaOpcode::VCmpOF16:
case RdnaOpcode::VCmpUF16:
case RdnaOpcode::VCmpNgeF16:
case RdnaOpcode::VCmpNlgF16:
case RdnaOpcode::VCmpNgtF16:
case RdnaOpcode::VCmpNleF16:
case RdnaOpcode::VCmpNltF16:
case RdnaOpcode::VCmpTruF16:
case RdnaOpcode::VCmpxFF16:
case RdnaOpcode::VCmpxLgF16:
case RdnaOpcode::VCmpxOF16:
case RdnaOpcode::VCmpxUF16:
case RdnaOpcode::VCmpxNgeF16:
case RdnaOpcode::VCmpxNlgF16:
case RdnaOpcode::VCmpxNleF16:
case RdnaOpcode::VCmpxTruF16:
case RdnaOpcode::VCmpxNeU64:
case RdnaOpcode::VCmpxLtU32:
case RdnaOpcode::VCmpxEqU32:

View File

@ -314,6 +314,56 @@ constexpr VopcOpcodeInfo vopcOpcodes[] = {
{0xfbu, RdnaOpcode::VCmpxNgtF16},
{0xfdu, RdnaOpcode::VCmpxNeqF16},
{0xfeu, RdnaOpcode::VCmpxNltF16},
{0x10u, RdnaOpcode::VCmpxFF32},
{0x17u, RdnaOpcode::VCmpxOF32},
{0x18u, RdnaOpcode::VCmpxUF32},
{0x1fu, RdnaOpcode::VCmpxTruF32},
{0x90u, RdnaOpcode::VCmpxFI32},
{0x97u, RdnaOpcode::VCmpxTI32},
{0xd0u, RdnaOpcode::VCmpxFU32},
{0xd7u, RdnaOpcode::VCmpxTU32},
{0xa0u, RdnaOpcode::VCmpFI64, false},
{0xa1u, RdnaOpcode::VCmpLtI64, false},
{0xa3u, RdnaOpcode::VCmpLeI64, false},
{0xa4u, RdnaOpcode::VCmpGtI64, false},
{0xa5u, RdnaOpcode::VCmpNeI64, false},
{0xa6u, RdnaOpcode::VCmpGeI64, false},
{0xa7u, RdnaOpcode::VCmpTI64, false},
{0xb0u, RdnaOpcode::VCmpxFI64, false},
{0xb1u, RdnaOpcode::VCmpxLtI64, false},
{0xb2u, RdnaOpcode::VCmpxEqI64, false},
{0xb3u, RdnaOpcode::VCmpxLeI64, false},
{0xb4u, RdnaOpcode::VCmpxGtI64, false},
{0xb6u, RdnaOpcode::VCmpxGeI64, false},
{0xb7u, RdnaOpcode::VCmpxTI64, false},
{0xe0u, RdnaOpcode::VCmpFU64, false},
{0xe3u, RdnaOpcode::VCmpLeU64, false},
{0xe6u, RdnaOpcode::VCmpGeU64, false},
{0xe7u, RdnaOpcode::VCmpTU64, false},
{0xf0u, RdnaOpcode::VCmpxFU64, false},
{0xf1u, RdnaOpcode::VCmpxLtU64, false},
{0xf2u, RdnaOpcode::VCmpxEqU64, false},
{0xf3u, RdnaOpcode::VCmpxLeU64, false},
{0xf4u, RdnaOpcode::VCmpxGtU64, false},
{0xf6u, RdnaOpcode::VCmpxGeU64, false},
{0xf7u, RdnaOpcode::VCmpxTU64, false},
{0xc8u, RdnaOpcode::VCmpFF16},
{0xcfu, RdnaOpcode::VCmpOF16},
{0xe8u, RdnaOpcode::VCmpUF16},
{0xe9u, RdnaOpcode::VCmpNgeF16},
{0xeau, RdnaOpcode::VCmpNlgF16},
{0xebu, RdnaOpcode::VCmpNgtF16},
{0xecu, RdnaOpcode::VCmpNleF16},
{0xeeu, RdnaOpcode::VCmpNltF16},
{0xefu, RdnaOpcode::VCmpTruF16},
{0xd8u, RdnaOpcode::VCmpxFF16},
{0xddu, RdnaOpcode::VCmpxLgF16},
{0xdfu, RdnaOpcode::VCmpxOF16},
{0xf8u, RdnaOpcode::VCmpxUF16},
{0xf9u, RdnaOpcode::VCmpxNgeF16},
{0xfau, RdnaOpcode::VCmpxNlgF16},
{0xfcu, RdnaOpcode::VCmpxNleF16},
{0xffu, RdnaOpcode::VCmpxTruF16},
};
constexpr VectorOpcodeInfo vop3Opcodes[] = {
@ -664,6 +714,27 @@ bool isVopcFloatCompareOpcode(RdnaOpcode opcode) {
case RdnaOpcode::VCmpxNgtF16:
case RdnaOpcode::VCmpxNeqF16:
case RdnaOpcode::VCmpxNltF16:
case RdnaOpcode::VCmpxFF32:
case RdnaOpcode::VCmpxOF32:
case RdnaOpcode::VCmpxUF32:
case RdnaOpcode::VCmpxTruF32:
case RdnaOpcode::VCmpFF16:
case RdnaOpcode::VCmpOF16:
case RdnaOpcode::VCmpUF16:
case RdnaOpcode::VCmpNgeF16:
case RdnaOpcode::VCmpNlgF16:
case RdnaOpcode::VCmpNgtF16:
case RdnaOpcode::VCmpNleF16:
case RdnaOpcode::VCmpNltF16:
case RdnaOpcode::VCmpTruF16:
case RdnaOpcode::VCmpxFF16:
case RdnaOpcode::VCmpxLgF16:
case RdnaOpcode::VCmpxOF16:
case RdnaOpcode::VCmpxUF16:
case RdnaOpcode::VCmpxNgeF16:
case RdnaOpcode::VCmpxNlgF16:
case RdnaOpcode::VCmpxNleF16:
case RdnaOpcode::VCmpxTruF16:
case RdnaOpcode::VCmpClassF32:
case RdnaOpcode::VCmpxClassF32: return true;
default: return false;
@ -1141,6 +1212,36 @@ bool isVopcCompareExec(RdnaOpcode opcode) {
case RdnaOpcode::VCmpxGeU32:
case RdnaOpcode::VCmpxNeI64:
case RdnaOpcode::VCmpxNeU64:
case RdnaOpcode::VCmpxFF32:
case RdnaOpcode::VCmpxOF32:
case RdnaOpcode::VCmpxUF32:
case RdnaOpcode::VCmpxTruF32:
case RdnaOpcode::VCmpxFI32:
case RdnaOpcode::VCmpxTI32:
case RdnaOpcode::VCmpxFU32:
case RdnaOpcode::VCmpxTU32:
case RdnaOpcode::VCmpxFI64:
case RdnaOpcode::VCmpxLtI64:
case RdnaOpcode::VCmpxEqI64:
case RdnaOpcode::VCmpxLeI64:
case RdnaOpcode::VCmpxGtI64:
case RdnaOpcode::VCmpxGeI64:
case RdnaOpcode::VCmpxTI64:
case RdnaOpcode::VCmpxFU64:
case RdnaOpcode::VCmpxLtU64:
case RdnaOpcode::VCmpxEqU64:
case RdnaOpcode::VCmpxLeU64:
case RdnaOpcode::VCmpxGtU64:
case RdnaOpcode::VCmpxGeU64:
case RdnaOpcode::VCmpxTU64:
case RdnaOpcode::VCmpxFF16:
case RdnaOpcode::VCmpxLgF16:
case RdnaOpcode::VCmpxOF16:
case RdnaOpcode::VCmpxUF16:
case RdnaOpcode::VCmpxNgeF16:
case RdnaOpcode::VCmpxNlgF16:
case RdnaOpcode::VCmpxNleF16:
case RdnaOpcode::VCmpxTruF16:
case RdnaOpcode::VCmpxLtI16:
case RdnaOpcode::VCmpxEqI16:
case RdnaOpcode::VCmpxLeI16:

View File

@ -117,7 +117,8 @@ private:
void emitIntegerCompare(const RdnaInstruction& inst, IrOpcode opcode, IrType type, bool scalar, bool cmpx);
void emitInteger16Compare(const RdnaInstruction& inst, IrOpcode opcode, bool signedValue, bool cmpx);
void emitFloatCompare(const RdnaInstruction& inst, IrOpcode opcode, bool half, bool cmpx);
void emitFloatOrderedCompare(const RdnaInstruction& inst, bool ordered);
void emitInteger64Order(const RdnaInstruction& inst, bool signedValue, bool swap, bool negate, bool cmpx);
void emitFloatOrderedCompare(const RdnaInstruction& inst, bool ordered, bool half, bool cmpx);
void emitFloatClassCompare(const RdnaInstruction& inst, bool cmpx);
void vCvtF32Ubyte(const RdnaInstruction& inst, std::uint32_t byteIndex);
void vCvtF32U32(const RdnaInstruction& inst);

View File

@ -54,14 +54,21 @@ void TranslationContext::emitFloatCompare(const RdnaInstruction& inst, IrOpcode
emitCompareResult(inst, IrU1(ir.Emit(opcode, IrType::U1, {lhs, rhs})), false, cmpx);
}
void TranslationContext::emitFloatOrderedCompare(const RdnaInstruction& inst, bool ordered) {
IrValue* lhs = readOperand(sourceAt(inst, 0u), IrType::F32);
IrValue* rhs = readOperand(sourceAt(inst, 1u), IrType::F32);
void TranslationContext::emitInteger64Order(const RdnaInstruction& inst, bool signedValue, bool swap, bool negate, bool cmpx) {
IrValue* lhs = readOperand(sourceAt(inst, swap ? 1u : 0u), IrType::U64);
IrValue* rhs = readOperand(sourceAt(inst, swap ? 0u : 1u), IrType::U64);
IrValue& less = ir.Emit(signedValue ? IrOpcode::SLessThan64 : IrOpcode::ULessThan64, IrType::U1, {lhs, rhs});
emitCompareResult(inst, IrU1(negate ? ir.LogicalNot(less) : less), false, cmpx);
}
void TranslationContext::emitFloatOrderedCompare(const RdnaInstruction& inst, bool ordered, bool half, bool cmpx) {
IrValue* lhs = half ? &readF16AsF32(sourceAt(inst, 0u)).Value() : readOperand(sourceAt(inst, 0u), IrType::F32);
IrValue* rhs = half ? &readF16AsF32(sourceAt(inst, 1u)).Value() : readOperand(sourceAt(inst, 1u), IrType::F32);
IrValue& lhsNan = ir.Emit(IrOpcode::FPIsNan32, IrType::U1, {lhs});
IrValue& rhsNan = ir.Emit(IrOpcode::FPIsNan32, IrType::U1, {rhs});
IrValue& unordered = ir.LogicalOr(lhsNan, rhsNan);
IrValue& result = ordered ? ir.LogicalNot(unordered) : unordered;
emitCompareResult(inst, IrU1(result), false, false);
emitCompareResult(inst, IrU1(result), false, cmpx);
}
void TranslationContext::emitFloatClassCompare(const RdnaInstruction& inst, bool cmpx) {

View File

@ -145,6 +145,156 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) {
case RdnaOpcode::VCmpxNeU64:
emitIntegerCompare(inst, IrOpcode::INotEqual64, IrType::U64, false, true);
return true;
case RdnaOpcode::VCmpxFF32:
emitCompareConstant(inst, false, false, true);
return true;
case RdnaOpcode::VCmpxOF32:
emitFloatOrderedCompare(inst, true, false, true);
return true;
case RdnaOpcode::VCmpxUF32:
emitFloatOrderedCompare(inst, false, false, true);
return true;
case RdnaOpcode::VCmpxTruF32:
emitCompareConstant(inst, true, false, true);
return true;
case RdnaOpcode::VCmpxFI32:
emitCompareConstant(inst, false, false, true);
return true;
case RdnaOpcode::VCmpxTI32:
emitCompareConstant(inst, true, false, true);
return true;
case RdnaOpcode::VCmpxFU32:
emitCompareConstant(inst, false, false, true);
return true;
case RdnaOpcode::VCmpxTU32:
emitCompareConstant(inst, true, false, true);
return true;
case RdnaOpcode::VCmpFI64:
emitCompareConstant(inst, false, false, false);
return true;
case RdnaOpcode::VCmpLtI64:
emitInteger64Order(inst, true, false, false, false);
return true;
case RdnaOpcode::VCmpLeI64:
emitInteger64Order(inst, true, true, true, false);
return true;
case RdnaOpcode::VCmpGtI64:
emitInteger64Order(inst, true, true, false, false);
return true;
case RdnaOpcode::VCmpNeI64:
emitIntegerCompare(inst, IrOpcode::INotEqual64, IrType::U64, false, false);
return true;
case RdnaOpcode::VCmpGeI64:
emitInteger64Order(inst, true, false, true, false);
return true;
case RdnaOpcode::VCmpTI64:
emitCompareConstant(inst, true, false, false);
return true;
case RdnaOpcode::VCmpxFI64:
emitCompareConstant(inst, false, false, true);
return true;
case RdnaOpcode::VCmpxLtI64:
emitInteger64Order(inst, true, false, false, true);
return true;
case RdnaOpcode::VCmpxEqI64:
emitIntegerCompare(inst, IrOpcode::IEqual64, IrType::U64, false, true);
return true;
case RdnaOpcode::VCmpxLeI64:
emitInteger64Order(inst, true, true, true, true);
return true;
case RdnaOpcode::VCmpxGtI64:
emitInteger64Order(inst, true, true, false, true);
return true;
case RdnaOpcode::VCmpxGeI64:
emitInteger64Order(inst, true, false, true, true);
return true;
case RdnaOpcode::VCmpxTI64:
emitCompareConstant(inst, true, false, true);
return true;
case RdnaOpcode::VCmpFU64:
emitCompareConstant(inst, false, false, false);
return true;
case RdnaOpcode::VCmpLeU64:
emitInteger64Order(inst, false, true, true, false);
return true;
case RdnaOpcode::VCmpGeU64:
emitInteger64Order(inst, false, false, true, false);
return true;
case RdnaOpcode::VCmpTU64:
emitCompareConstant(inst, true, false, false);
return true;
case RdnaOpcode::VCmpxFU64:
emitCompareConstant(inst, false, false, true);
return true;
case RdnaOpcode::VCmpxLtU64:
emitInteger64Order(inst, false, false, false, true);
return true;
case RdnaOpcode::VCmpxEqU64:
emitIntegerCompare(inst, IrOpcode::IEqual64, IrType::U64, false, true);
return true;
case RdnaOpcode::VCmpxLeU64:
emitInteger64Order(inst, false, true, true, true);
return true;
case RdnaOpcode::VCmpxGtU64:
emitInteger64Order(inst, false, true, false, true);
return true;
case RdnaOpcode::VCmpxGeU64:
emitInteger64Order(inst, false, false, true, true);
return true;
case RdnaOpcode::VCmpxTU64:
emitCompareConstant(inst, true, false, true);
return true;
case RdnaOpcode::VCmpFF16:
emitCompareConstant(inst, false, false, false);
return true;
case RdnaOpcode::VCmpOF16:
emitFloatOrderedCompare(inst, true, true, false);
return true;
case RdnaOpcode::VCmpUF16:
emitFloatOrderedCompare(inst, false, true, false);
return true;
case RdnaOpcode::VCmpNgeF16:
emitFloatCompare(inst, IrOpcode::FPUnordLessThan32, true, false);
return true;
case RdnaOpcode::VCmpNlgF16:
emitFloatCompare(inst, IrOpcode::FPUnordEqual32, true, false);
return true;
case RdnaOpcode::VCmpNgtF16:
emitFloatCompare(inst, IrOpcode::FPUnordLessThanEqual32, true, false);
return true;
case RdnaOpcode::VCmpNleF16:
emitFloatCompare(inst, IrOpcode::FPUnordGreaterThan32, true, false);
return true;
case RdnaOpcode::VCmpNltF16:
emitFloatCompare(inst, IrOpcode::FPUnordGreaterThanEqual32, true, false);
return true;
case RdnaOpcode::VCmpTruF16:
emitCompareConstant(inst, true, false, false);
return true;
case RdnaOpcode::VCmpxFF16:
emitCompareConstant(inst, false, false, true);
return true;
case RdnaOpcode::VCmpxLgF16:
emitFloatCompare(inst, IrOpcode::FPOrdNotEqual32, true, true);
return true;
case RdnaOpcode::VCmpxOF16:
emitFloatOrderedCompare(inst, true, true, true);
return true;
case RdnaOpcode::VCmpxUF16:
emitFloatOrderedCompare(inst, false, true, true);
return true;
case RdnaOpcode::VCmpxNgeF16:
emitFloatCompare(inst, IrOpcode::FPUnordLessThan32, true, true);
return true;
case RdnaOpcode::VCmpxNlgF16:
emitFloatCompare(inst, IrOpcode::FPUnordEqual32, true, true);
return true;
case RdnaOpcode::VCmpxNleF16:
emitFloatCompare(inst, IrOpcode::FPUnordGreaterThan32, true, true);
return true;
case RdnaOpcode::VCmpxTruF16:
emitCompareConstant(inst, true, false, true);
return true;
case RdnaOpcode::VCmpEqU16:
emitInteger16Compare(inst, IrOpcode::IEqual32, false, false);
return true;
@ -335,10 +485,10 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) {
emitFloatCompare(inst, IrOpcode::FPUnordGreaterThanEqual32, true, true);
return true;
case RdnaOpcode::VCmpOF32:
emitFloatOrderedCompare(inst, true);
emitFloatOrderedCompare(inst, true, false, false);
return true;
case RdnaOpcode::VCmpUF32:
emitFloatOrderedCompare(inst, false);
emitFloatOrderedCompare(inst, false, false, false);
return true;
case RdnaOpcode::VCmpClassF32:
emitFloatClassCompare(inst, false);