Completes the fused-FMA slice deferred by the VOP3P first slice (#145).
v_pk_fma_f16 previously failed emission loudly because an f32
multiply-add followed by an f16 pack rounds twice; the pinned miss is
fma(0x4100, 0x7522, 0x04EA) = 0x7A6B fused vs 0x7A6A via f32.
The f32 product of two f16 values is exact, so only the addition needs
correcting: compute sum = RN(product + addend), recover the exact
residual with Knuth 2Sum, and if the sum is inexact with an even
significand, step one ulp towards the true value. That is round-to-odd,
and rounding the f32 result to f16 with round-to-nearest-even then
matches a true fused f16 FMA exactly (24 significand bits >= 11 + 2).
Inf/NaN inputs turn the residual into NaN, the ordered compare skips the
parity fix, and IEEE special behaviour passes through unchanged. The
op_sel/op_sel_hi/neg_lo/neg_hi source modifiers apply to src2 through
the existing operand path; clamp stays rejected like the other packed
ops.
Every op in the 2Sum chain is decorated NoContraction: without it the
AMD RDNA3 Windows driver folds the sequence, collapses the residual to
zero, and the midpoint case decays to the double-rounded result. This
was caught by running the emitted shader on a real device (see below).
Verification:
- A mirror of the emitted sequence was checked against an exact
integer reference (every finite f16 is m * 2^-24, so a*b + c is an
exact Int128 multiple of 2^-48, rounded once to f16 RNE) across 34M
cases: directed midpoint pins, random sweeps over all operand
classes, tiny-addend midpoint stress, subnormal products, and
Inf/NaN propagation. 0 mismatches.
- ShaderDump gains a pk-f16 program covering all five packed opcodes,
both fma modifier paths, and the pinned constants; all programs
decode and emit.
- The executable exec program now computes the pinned fma and its
negated-addend twin (0x7A6B7A6B / 0x7A6A7A6A, straddling an f16
midpoint) and stores them at offsets 20/24; GpuConformance checks
both on device. All values match on an AMD Radeon RX 7700 XT.