Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/execution/MacLegacy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#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 <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 = 8;
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, 28> MacLegacyCode{
0x34020083, 0x34060083, 0xe0302000, 0x80000401, 0xe0302004, 0x80000501, 0xe0302008, 0x80000601,
0xbf8c3f70, 0x7e140306, 0x0c140b04, 0x7e160306, 0xd506000b, 0x20020b04, 0x7e180306, 0xd506030c,
0x40020b04, 0x7e1a0306, 0x0c1a0a80, 0xe0702000, 0x80010a03, 0xe0702004, 0x80010b03, 0xe0702008,
0x80010c03, 0xe070200c, 0x80010d03, 0xbf810000,
};

struct Row {
std::uint32_t a, b, c;
std::array<std::uint32_t, 4> expected;
};

constexpr std::array<Row, 32> Rows{{
{0x00000000u, 0x7f800000u, 0x3f800000u, {0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u}},
{0x80000000u, 0x7f800000u, 0xc0200000u, {0xc0200000u, 0xc0200000u, 0xc0200000u, 0xc0200000u}},
{0x7f800000u, 0x00000000u, 0x3f400000u, {0x3f400000u, 0x3f400000u, 0x3f400000u, 0x3f400000u}},
{0xff800000u, 0x80000000u, 0x40400000u, {0x40400000u, 0x40400000u, 0x40400000u, 0x40400000u}},
{0x00000000u, 0x7fc00000u, 0x3fc00000u, {0x3fc00000u, 0x3fc00000u, 0x3fc00000u, 0x3fc00000u}},
{0x7fc00000u, 0x80000000u, 0xc0800000u, {0xc0800000u, 0xc0800000u, 0xc0800000u, 0xc0800000u}},
{0x00000000u, 0x40000000u, 0x7f800000u, {0x7f800000u, 0x7f800000u, 0x7f800000u, 0x7f800000u}},
{0x80000000u, 0xc0400000u, 0xff800000u, {0xff800000u, 0xff800000u, 0xff800000u, 0xff800000u}},
{0x00000000u, 0x3f800000u, 0x7fc00000u, {0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x7fc00000u}},
{0x3fc00000u, 0x40100000u, 0xbf400000u, {0x40280000u, 0xc0840000u, 0xc0840000u, 0xbf400000u}},
{0xc0c00000u, 0x3f000000u, 0x41200000u, {0x40e00000u, 0x41500000u, 0x40e00000u, 0x41200000u}},
{0x7f800000u, 0x40000000u, 0x3f800000u, {0x7f800000u, 0xff800000u, 0xff800000u, 0x3f800000u}},
{0x7f800000u, 0xbf800000u, 0x7f800000u, {0xffc00000u, 0x7f800000u, 0xffc00000u, 0x7f800000u}},
{0x7fc00000u, 0x3f800000u, 0x3f800000u, {0x7fc00000u, 0xffc00000u, 0x7fc00000u, 0x3f800000u}},
{0x40400000u, 0x40800000u, 0xc1400000u, {0x00000000u, 0xc1c00000u, 0xc1c00000u, 0xc1400000u}},
{0x7f7fffffu, 0x40000000u, 0x3f800000u, {0x7f800000u, 0xff800000u, 0xff800000u, 0x3f800000u}},
{0x3ec00000u, 0xc1480000u, 0x42c88000u, {0x42bf2000u, 0x42d1e000u, 0x42bf2000u, 0x42c88000u}},
{0xc4800000u, 0xbd800000u, 0xc2800000u, {0x00000000u, 0xc3000000u, 0xc3000000u, 0xc2800000u}},
{0x40e00000u, 0x41100000u, 0x3f000000u, {0x427e0000u, 0xc27a0000u, 0xc27a0000u, 0x3f000000u}},
{0x80000000u, 0x80000000u, 0x40a00000u, {0x40a00000u, 0x40a00000u, 0x40a00000u, 0x40a00000u}},
{0x3f800800u, 0x3f800800u, 0xbf800000u, {0x3a000000u, 0xc0000800u, 0xc0000800u, 0xbf800000u}},
{0x3f800001u, 0x3f7fffffu, 0xbf800000u, {0x00000000u, 0xc0000000u, 0xc0000000u, 0xbf800000u}},
{0x3faaaaabu, 0x40400000u, 0xc0800000u, {0x00000000u, 0xc1000000u, 0xc1000000u, 0xc0800000u}},
{0x7f7fffffu, 0x40000000u, 0xff7fffffu, {0x7f800000u, 0xff800000u, 0xff800000u, 0xff7fffffu}},
{0x00800000u, 0x3f000000u, 0x00000000u, {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}},
{0x00000001u, 0x4b000000u, 0x00000000u, {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}},
{0x00000001u, 0x3f800000u, 0x80000000u, {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}},
{0x80000001u, 0x3f800000u, 0x00000000u, {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}},
{0x00800000u, 0x3f800000u, 0x80400000u, {0x00800000u, 0x80800000u, 0x80800000u, 0x00000000u}},
{0x3f800000u, 0x00400000u, 0x00000000u, {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}},
{0x7f812345u, 0x3f800000u, 0x3f800000u, {0x7f812345u, 0xff812345u, 0x7f812345u, 0x3f800000u}},
{0x3f800000u, 0x3f800000u, 0x7f812345u, {0x7f812345u, 0x7f812345u, 0x7f812345u, 0x7f812345u}},
}};

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, 0x11016facu};
}

void Run(AgcDriver::VulkanDevice& device) {
Input.fill(0u);
for (std::uint32_t tid = 0; tid < Rows.size(); ++tid) {
const auto& row = Rows[tid];
const std::array<std::uint32_t, 3> words{row.a, row.b, row.c};
std::copy(words.begin(), words.end(), Input.begin() + 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()));
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(MacLegacyCode);
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();
}

std::string Hex(std::uint32_t value) {
char text[16];
std::snprintf(text, sizeof(text), "0x%08x", value);
return text;
}

void Check() {
constexpr std::array<const char*, 4> names{
"v_mac_legacy_f32", "v_mac_legacy_f32_e64 -src0", "v_mac_legacy_f32_e64 |src0| -|src1|", "v_mac_legacy_f32 src0=0",
};
for (std::uint32_t tid = 0; tid < Rows.size(); ++tid) {
const auto& row = Rows[tid];
for (std::uint32_t j = 0; j < row.expected.size(); ++j) {
const auto actual = Output[tid * Results + j];
Require(actual == row.expected[j], std::string("mac legacy: lane ") + std::to_string(tid) + " (" + Hex(row.a) + ", " + Hex(row.b) + ", " + Hex(row.c) + ") " + names[j] + " is " + Hex(actual) + ", expected " + Hex(row.expected[j]));
}
}
}

}

int main() {
try {
const auto device = OpenVulkanTestDevice();
if (!device) return VulkanTestSkipped;
Run(*device);
Check();
std::puts("mac legacy tests passed");
return 0;
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';
return 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class TranslationContext {
bool vDivFmasF32(const RdnaInstruction& inst);
bool vDivFixupF32(const RdnaInstruction& inst);
bool vFrexpMantF32(const RdnaInstruction& inst);
bool vFmaLegacyF32(const RdnaInstruction& inst);
bool vFmaLegacyF32(const RdnaInstruction& inst, bool accumulate);
bool vLdexpF32(const RdnaInstruction& inst);
IrU32 readF16Bits(const RdnaOperand& operand);
IrU32 normF16(IrU32 bits, bool signedValue);
Expand All @@ -201,7 +201,7 @@ class TranslationContext {
bool vCvtNormF16(const RdnaInstruction& inst, bool signedValue);
bool vCvtPknormF16(const RdnaInstruction& inst, bool signedValue);
bool vSatPkU8I16(const RdnaInstruction& inst);
bool vMulLegacyF32(const RdnaInstruction& inst, bool accumulate);
bool vMulLegacyF32(const RdnaInstruction& inst);
bool vMullitF32(const RdnaInstruction& inst);
void emitFloat16ClassCompare(const RdnaInstruction& inst, bool cmpx);
bool float64Operation(const RdnaInstruction& inst, IrOpcode opcode);
Expand Down
13 changes: 4 additions & 9 deletions core/shader/recompiler/Translation/src/FloatInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,17 +371,12 @@ bool TranslationContext::vSatPkU8I16(const RdnaInstruction& inst) {
return true;
}

bool TranslationContext::vMulLegacyF32(const RdnaInstruction& inst, bool accumulate) {
bool TranslationContext::vMulLegacyF32(const RdnaInstruction& inst) {
IrValue* lhs = readOperand(sourceAt(inst, 0u), IrType::F32);
IrValue* rhs = readOperand(sourceAt(inst, 1u), IrType::F32);
const auto isZero = [&](IrValue* value) { return IrU1(ir.IEqual(ir.BitwiseAnd(ir.BitCastU32(*value), ir.Constant(0x7fffffffu)), ir.Constant(0u))); };
const IrU1 zero(ir.LogicalOr(isZero(lhs).Value(), isZero(rhs).Value()));
IrValue* result = &ir.Emit(IrOpcode::SelectF32, IrType::F32, {&zero.Value(), &ir.ConstantF32(0.0f), nanResultF32({lhs, rhs}, &flushTinyProduct(lhs, rhs, &ir.Emit(IrOpcode::FPMul32, IrType::F32, {lhs, rhs})).Value())});
if (accumulate) {
IrValue* addend = readOperand(accumulatorOperand(inst), IrType::F32);
result = &ir.Emit(IrOpcode::FPAdd32, IrType::F32, {result, addend});
}
writeOperand(inst.destination, result);
writeOperand(inst.destination, &ir.Emit(IrOpcode::SelectF32, IrType::F32, {&zero.Value(), &ir.ConstantF32(0.0f), nanResultF32({lhs, rhs}, &flushTinyProduct(lhs, rhs, &ir.Emit(IrOpcode::FPMul32, IrType::F32, {lhs, rhs})).Value())}));
return true;
}

Expand Down Expand Up @@ -647,10 +642,10 @@ bool TranslationContext::minMaxF16(const RdnaInstruction& inst, IrOpcode opcode)
return true;
}

bool TranslationContext::vFmaLegacyF32(const RdnaInstruction& inst) {
bool TranslationContext::vFmaLegacyF32(const RdnaInstruction& inst, bool accumulate) {
IrValue* lhs = readOperand(sourceAt(inst, 0u), IrType::F32);
IrValue* rhs = readOperand(sourceAt(inst, 1u), IrType::F32);
IrValue* addend = readOperand(sourceAt(inst, 2u), IrType::F32);
IrValue* addend = readOperand(accumulate ? accumulatorOperand(inst) : sourceAt(inst, 2u), IrType::F32);
const auto isZero = [&](IrValue* value) { return IrU1(ir.IEqual(ir.BitwiseAnd(ir.BitCastU32(*value), ir.Constant(0x7fffffffu)), ir.Constant(0u))); };
const IrU1 zero(ir.LogicalOr(isZero(lhs).Value(), isZero(rhs).Value()));
const auto factor = [&](IrValue* value) { return &ir.Emit(IrOpcode::SelectF32, IrType::F32, {&zero.Value(), &ir.ConstantF32(0.0f), value}); };
Expand Down
7 changes: 4 additions & 3 deletions core/shader/recompiler/Translation/src/VectorInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ std::uint32_t TranslationContext::f32DenormalFlushFor(const RdnaInstruction& ins
flush = 1u;
break;
case RdnaOpcode::VMadLegacyF32:
case RdnaOpcode::VMacLegacyF32:
return 3u;
default:
return 0u;
Expand Down Expand Up @@ -622,9 +623,9 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) {
case RdnaOpcode::VSatPkU8I16:
return vSatPkU8I16(inst);
case RdnaOpcode::VMulLegacyF32:
return vMulLegacyF32(inst, false);
return vMulLegacyF32(inst);
case RdnaOpcode::VMacLegacyF32:
return vMulLegacyF32(inst, true);
return vFmaLegacyF32(inst, true);
case RdnaOpcode::VMullitF32:
return vMullitF32(inst);
case RdnaOpcode::VCmpClassF32:
Expand Down Expand Up @@ -1043,7 +1044,7 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) {
case RdnaOpcode::VFmaF32:
return floatTernary(inst, roundsProductSeparately(inst) ? IrOpcode::FPMad32 : IrOpcode::FPFma32, false, true);
case RdnaOpcode::VMadLegacyF32:
return vFmaLegacyF32(inst);
return vFmaLegacyF32(inst, false);
case RdnaOpcode::VMin3F32:
return ieeeMode ? ieeeMinMaxF32(inst, IrOpcode::FPMinTri32) : floatTernary(inst, IrOpcode::FPMinTri32, false, false);
case RdnaOpcode::VMax3F32:
Expand Down
Loading
Loading