From ba8b0c85b80e74de092c410f625a496831d18ead Mon Sep 17 00:00:00 2001 From: Nawid3333 <102778966+Nawid3333@users.noreply.github.com> Date: Sat, 17 Oct 2026 05:12:37 +0200 Subject: [PATCH] shader: keep quiet NaNs with payload bits out of the packed f16 min/max sNaN path (#1579) V_PK_MIN_F16 and V_PK_MAX_F16 return the quieted NaN for a signaling NaN operand and the other operand for a quiet one (per half, as V_MIN_F16 and V_MAX_F16 do). The signaling test masked the half with 0x7c00 and checked for a nonzero payload, so a quiet NaN with payload bits such as 0x7e01 was taken as signaling and returned. Mask with 0x7e00 so the quiet bit must be clear. Two more vectors in PackedMinMaxF16NanAndSignedZeroEdges cover it. Co-authored-by: Claude Opus 5.5 --- .../shader/recompiler/frontend/translate/Float.cpp | 2 +- tests/ShaderRecompilerComputeTests.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/graphics/shader/recompiler/frontend/translate/Float.cpp b/src/graphics/shader/recompiler/frontend/translate/Float.cpp index e88ddc5b4..d8a9c9e69 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Float.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Float.cpp @@ -27,7 +27,7 @@ void Translator::PackedFloat16(const Decoder::Instruction& inst, IR::ValueOpcode if (quiet_snan) { const auto quiet_snan_lane = [&](const Decoder::Operand& operand, bool high) { const auto bits = ReadU16LaneAsU32(operand, high, false); - const auto exponent = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x7c00u))); + const auto exponent = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x7e00u))); const auto payload = ir.BitwiseAnd(bits, IR::U32(IR::Value(0x01ffu))); const auto snan = ir.LogicalAnd(ir.IEqual(exponent, IR::U32(IR::Value(0x7c00u))), ir.INotEqual(payload, IR::U32(IR::Value(0u)))); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 692e88d44..429175e6e 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -25880,13 +25880,17 @@ TestCase PackedMinMaxF16NanAndSignedZeroEdges() { AppendVMovLiteral(&code, 3, 0x80007e00u); AppendVMovLiteral(&code, 4, 0x40007d01u); AppendVMovLiteral(&code, 5, 0x7d014000u); + AppendVMovLiteral(&code, 6, 0x40007e01u); + AppendVMovLiteral(&code, 7, 0x7e013c00u); AppendVop3p(&code, 0x11, 10, Vgpr(0), Vgpr(1), 0, 0x3); AppendVop3p(&code, 0x12, 11, Vgpr(2), Vgpr(3), 0, 0x3); AppendVop3p(&code, 0x11, 12, Vgpr(4), Vgpr(5), 0, 0x3); AppendVop3p(&code, 0x12, 13, Vgpr(4), Vgpr(5), 0, 0x3); + AppendVop3p(&code, 0x11, 14, Vgpr(6), Vgpr(7), 0, 0x3); + AppendVop3p(&code, 0x12, 15, Vgpr(6), Vgpr(7), 0, 0x3); - for (u32 i = 0; i < 4; i++) { + for (u32 i = 0; i < 6; i++) { AppendStoreVgpr(&code, 10 + i, i); } AppendEnd(&code); @@ -25894,7 +25898,7 @@ TestCase PackedMinMaxF16NanAndSignedZeroEdges() { return {"PackedMinMaxF16NanAndSignedZeroEdges", code, {}, - {0x80004000u, 0x00004000u, 0x7f017f01u, 0x7f017f01u}, + {0x80004000u, 0x00004000u, 0x7f017f01u, 0x7f017f01u, 0x40003c00u, 0x40003c00u}, {O::V_MOV_B32, O::V_PK_MIN_F16, O::V_PK_MAX_F16, O::BUFFER_STORE_DWORD, O::S_ENDPGM}}; }