← board

riscv32: soft-float drops subnormals

Symptom

qemu-riscv32-static, both float modes:

1e-320 > 0?                   TRUE
(1e-320 * 0.5) * 2.0 = 1e-320?  FALSE   <- the value cannot survive a halving
Exp(-745) > 0 ?               FALSE     <- every other target: a subnormal
Ln(5e-324)                    -746.519513   correct: -744.440072
Ln(1e-320)                    -746.519513   <- same answer for a different input

That last pair is the tell: two different subnormal inputs produce the same logarithm, because both were flushed to the same representable value on the way in.

Scope

target subnormals
x86-64, i386, arm32, aarch64 correct
riscv32 flushed

test/lib_math_fast_tolerance.pas carries the two rows that catch this (exp-denormal-not-flushed, ln-denormal-arg). They pass on every target except riscv32 and are deliberately NOT guarded with an ifdef — the assertion is correct IEEE behaviour and the target is what is wrong. That suite runs natively in lib-test, so this does not red anything today; it will surface if the lib tests are ever added to the cross matrix.

Fix direction

The riscv32 float path is soft-float. Find whether the runtime's add/mul/scale helpers handle the subnormal exponent case at all, or whether they assume a normalized mantissa with the implicit leading 1. The (x*0.5)*2.0 round-trip failing points at multiply/scale rather than at conversion.

Gate

make test + self-host byte-identical, plus the probe above under qemu-riscv32-static matching what arm32 prints, plus test/lib_math_fast_tolerance.pas cross-built for riscv32 reaching MATHFAST OK.

<!-- float category --> Indexed on [[meta-float-accuracy-policy]] — the standing float-accuracy index. Collect, do not fix piecemeal; see the working rule there.