Skip to content

riscv_fpu: pre-approved scalar FPU conformance fixes#241

Merged
LekKit merged 4 commits into
LekKit:stagingfrom
pufit:fix/fpu-lgtm
Jun 24, 2026
Merged

riscv_fpu: pre-approved scalar FPU conformance fixes#241
LekKit merged 4 commits into
LekKit:stagingfrom
pufit:fix/fpu-lgtm

Conversation

@SolAstrius

@SolAstrius SolAstrius commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

The four scalar-FPU fixes that were already reviewed and marked LGTM in #239 / #240.

What's here

  • Drop func_opt_size on the FP op dispatch. The scalar FP path is interpreted, not JIT'd, so size-optimizing the dispatch only costs throughput — roughly 2x interpreter FP at zero size cost elsewhere.
  • sqrt(-0.0) returns -0.0 without raising invalid. IEEE 754 squareRoot(-0) is -0 with no exception; only a negative non-zero (or -inf) operand is invalid. The -0 carve-out is gated on a new FPU_LIB_FPxx_NEGATIVE_ZERO constant so the intent reads clearly (per review feedback).
  • fnmadd negates the operands, not the result. fnmadd computes -(rs1*rs2) - rs3 as a single fused op; negating fma(rs1, rs2, rs3) instead rounds rs1*rs2 + rs3 and then flips the sign, which under directed rounding modes can land on the wrong side. Negate rs1 and rs3 so the one rounding sees the correctly-signed value.
  • Mal-boxed narrow operands read as the canonical NaN. Per the RISC-V NaN-boxing rule, a narrow (f32) operand that isn't correctly NaN-boxed in its 64-bit register must read as the canonical NaN. Value reads route through riscv_read_s across arithmetic, conversions, sign-injection, min/max, compares, classification, and the FMA family. fmv.x.w keeps the raw riscv_view_s read (it moves the register bits verbatim).

The scalar FP path is interpreted, not JIT'd, so size-optimizing its
dispatch only costs throughput. Dropping func_opt_size is roughly 2x
interpreter FP at zero size cost on the rest of the build.

Signed-off-by: Sol Astrius Phoenix <sol@astrius.ink>
IEEE 754 squareRoot(-0) is -0 with no exception; only a negative
non-zero (or -inf) operand is invalid. Gate the invalid path on a new
FPU_LIB_FPxx_NEGATIVE_ZERO constant so the -0 carve-out reads clearly.

Signed-off-by: Sol Astrius Phoenix <sol@astrius.ink>
fnmadd computes -(rs1*rs2) - rs3 as a single fused operation. Negating
the result of fma(rs1, rs2, rs3) instead rounds rs1*rs2 + rs3 and then
flips the sign, which under the directed rounding modes can land on the
wrong side of the result. Negate rs1 and rs3 so the one rounding sees
the correctly-signed value.

Signed-off-by: Sol Astrius Phoenix <sol@astrius.ink>
Per the RISC-V NaN-boxing rule, a narrow (f32) operand that is not
correctly NaN-boxed in its 64-bit register must read as the canonical
NaN. Route the value reads through riscv_read_s (the NaN-unboxing read)
across arithmetic, conversions, sign-injection, min/max, compares,
classification, and the FMA family. fmv.x.w keeps the raw riscv_view_s
read, as it moves the register bits verbatim.

Signed-off-by: Sol Astrius Phoenix <sol@astrius.ink>
@SolAstrius

Copy link
Copy Markdown
Contributor Author

@purplesyringa

@LekKit LekKit merged commit c26a2a4 into LekKit:staging Jun 24, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants