The VFPU never keeps a NaN's payload (cpu/vfpu/nan_gen): vadd and vsub
produce 0x7F800001, and vmul, vdiv, vscl and vcrs the same with the
sign of s ^ t. The cores returned whatever NaN the host made, which
differs between x86 and ARM64. Now all four cores on both hosts match
the PSP for these ops. The horizontal ops (vdot and friends) are left
for when they move to the accurate dot product.
The IR gets FVfpuNaN and FVfpuProductNaN, scalar and Vec4, run after
the arithmetic. The native backends check for a NaN and branch past
the fixup, which only runs when there is one. PurgeTemps no longer
renames the dest of an FPR op that also reads it, which the product
ops are the first to do.
vsat0 and vsat1 also keep a NaN's bits now. The ARM64 JITs quieted a
signaling NaN through FMIN/FMAX, and the x86-64 IR JIT turned NaN into
0 in vsat0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vec4ClampToZero and Vec2ClampToZero only ever fed Vec4Pack31To8 and
Vec2Pack31To16, for vi2uc and vi2us. The packs now clamp negative lanes
to zero themselves, which saves an op and a vector temp, and lets x64
clamp with PACKUSWB's saturation after an arithmetic shift.
While at it, RISC-V compiles Vec2Unpack16To31, Vec2Pack31To16 and
Vec4Pack32To8, and LoongArch Vec2Unpack16To31, Vec2Pack31To16 and the
non-LSX Vec4Pack32To8, all of which went to the IR interpreter.
LoongArch's Vec2Pack32To16 and Vec2Unpack16To32 now take their scalar
path with LSX too, instead of falling back.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>