Files
AnyPS5/core/libs/tests/VectorMadLegacy.cpp
T
MarcusandClaude Opus 5.5 5377db48fd fix(shader): round the v_mad_legacy_f32 product before the add
VOP3 0x140 is v_mad_legacy_f32 on gfx10.1. Measured on gfx1010 (RX 5700
XT) in wave32 and wave64, IEEE 0 and 1 and f32 denormal modes 0 to 3, it
rounds the product before the add, flushes f32 denormal sources, product
and result in every mode, and gives a +0 product for a zero factor.

The translation multiplies, applies the zero rule and flushTinyProduct,
adds, and keeps the nanResultF32 wrapper. f32DenormalFlushFor returns 3
for the instruction before reading FLOAT_MODE. A sum of two zeros takes
its sign on the bits, as lavapipe returned -0 for +0 + -0. The execution
test pins the measured results and compares NaN bits exactly. RDNA2
(gfx1031), where the encoding is v_fma_legacy_f32 and fused, is noted in
TechnicalDebt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:18:55 +02:00

27 lines
1.1 KiB
C++

#include "Translation/TranslationContext.hpp"
#include "RdnaDecoder/RdnaVectorOpDecoder.hpp"
#include <array>
#include <stdexcept>
using namespace ShaderRecompiler;
static void Require(bool value) { if (!value) throw std::runtime_error("vector legacy mad regression"); }
static void Check(std::uint32_t encoding, RdnaOpcode opcode, IrOpcode expected) {
const std::array<std::uint32_t, 2> code{(encoding << 16u) | 1u, 1u | (2u << 9u) | (3u << 18u)};
const RdnaInstruction instruction = DecodeRdnaVop3(0u, code, 0u);
Require(instruction.op == opcode);
Require(instruction.family == RdnaInstructionFamily::VOP3);
Require(IsVectorAluOpcode(instruction.op));
IrProgram program;
auto& block = program.CreateBlock();
program.SetEntryBlock(block);
TranslationContext context(program, block, 256);
context.TranslateInstruction(instruction);
bool found = false;
for (auto* value : block.Instructions()) found = found || value->Opcode() == expected;
Require(found);
}
int main() {
Check(0x140u, RdnaOpcode::VMadLegacyF32, IrOpcode::FPMul32);
Check(0x150u, RdnaOpcode::VMullitF32, IrOpcode::FPMul32);
}