riscv32's sin loses about nine digits near a zero
Found by compiling examples/ across five backends against the x86-64 oracle
(the umbrella-cross-target-codegen-is-correct attempt, 2026-09-02).
mathdemo | i386:ok arm32:ok riscv32:DIFF aarch64:ok xtensa:ok
The whole difference, 4 diff lines out of 66:
< ok real = double (sin) = 0.000000000
> FAIL real = double (sin) = -0.000000087 want 0.000000000
< ALL OK
> FAILURES
The program grades itself, which is why this is worth a ticket rather than a
shrug: mathdemo prints FAILURES on riscv32 and ALL OK everywhere else, so
anyone running the examples on riscv32 sees a red program.
Why this is F and not the cross-target umbrella
The rule is rank the mechanism, never the datatype. This is not a
control-flow, ABI or codegen divergence that happens to live in float code — the
value is nearly right and wrong in the last digits, which is the signature of
accuracy in the soft-float sin itself, most likely argument reduction near
a zero of the function. That is float math, so it is F and low prio by
definition.
If it turns out to be a wrong branch or a truncated operand rather than accumulated error, it stops being F and belongs under the cross-target umbrella at real priority. Whoever picks it up should establish which it is first — the two have different owners.
Repro
./compiler/pascal26 examples/mathf/mathdemo.pas /tmp/md_x64 && /tmp/md_x64 > /tmp/md.oracle
./compiler/pascal26 --target=riscv32 --platform=posix examples/mathf/mathdemo.pas /tmp/md_rv
tools/run_target.sh riscv32 /tmp/md_rv | diff /tmp/md.oracle -
Bound
HEAD 7cc404961, compiler 709ec4626a67. Only the one row differs; the other
65 lines, including every other float row in the same program, match the oracle
exactly. Not checked against FPC — tools/fpc_diff_probe.sh is the instrument
and would say whether x86-64 or riscv32 is the odd one out against a third
opinion, and I did not run it.
Narrowed the same day — it is not riscv32, it is SOFTFLOAT
Once xtensa could build sysutils (7cc404961), mathdemo built for it too and
produced byte-identical output to riscv32 — the same single row, the same
-0.000000087, the same FAILURES.
mathdemo | i386:ok arm32:ok riscv32:DIFF aarch64:ok xtensa:DIFF
(riscv32 and xtensa outputs: cmp says IDENTICAL)
That is the discriminator. riscv32 and xtensa are the two SOFT-FLOAT targets;
i386 (x87), arm32 and aarch64 (hardware FP) are all correct. Two independent
backends producing the same wrong bits to the last digit is not two codegen
bugs — it is one implementation they share, compiler/builtin/softfloat.pas.
So the ticket is: sin in softfloat.pas loses ~9 digits near a zero, and any
soft-float target shows it. The slug says riscv32 because that is where it was
first seen; the subject is softfloat.
This also means the fix is one file and helps every soft-float target at once, which is worth more than the prio suggests — and that a per-backend investigation would have been the wrong shape entirely.
Still F: the mechanism is accuracy in a float routine. Still worth checking against FPC before assuming ours is the wrong one.