aboutsummaryrefslogtreecommitdiff
path: root/docs/history/31-fpu/notes.md
diff options
context:
space:
mode:
authorGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
committerGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
commitecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch)
tree70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /docs/history/31-fpu/notes.md
a
Diffstat (limited to 'docs/history/31-fpu/notes.md')
-rw-r--r--docs/history/31-fpu/notes.md23
1 files changed, 23 insertions, 0 deletions
diff --git a/docs/history/31-fpu/notes.md b/docs/history/31-fpu/notes.md
new file mode 100644
index 0000000..5fe01d7
--- /dev/null
+++ b/docs/history/31-fpu/notes.md
@@ -0,0 +1,23 @@
+# 31 — hardware float, and a soft fallback
+
+float arithmetic was already a host `double` on the interpreter and the microcore, and the arm64 jit and llvm already lowered 601..609 themselves. this stage makes that split explicit and adds the path for a machine with no FPU.
+
+the arm64 jit emits the FPU directly: `fadd`, `fsub`, `fmul`, `fdiv`, `fcmp` plus `cset` (`mi` and `ls`, so unordered is not less), `scvtf` and `fcvtzs`. print and parse stay calls, because they are formatting. llvm builds `fadd`/`fsub`/`fmul`/`fdiv`, `fcmp` (`oeq`/`olt`/`ole`), `sitofp` and `fptosi` on a double bitcast to i64. neither backend calls a C helper for those opcodes.
+
+the interpreter and the microcore go through `fops.h`. by default that is a `volatile double`, so the C compiler emits the FPU rather than folding the operation: x86_64 `addsd`/`mulsd`/`ucomisd`/`cvtsi2sd`/`cvttsd2si`, AArch64 `fadd`/`fmul`/`fcmp`/`scvtf`/`fcvtzs`, RV64 `fadd.d`/`fmul.d`/`flt.d`/`fcvt.d.l`/`fcvt.l.d` with `-mabi=lp64d`. the virt boards already set the FPU live before any C runs. RISC-V writes `mstatus.FS` to Dirty (`0x6000`). AArch64 clears the FP trap at EL2 and sets `CPACR_EL1.FPEN`. both images are built hard-float (`-march=rv64gc -mabi=lp64d`, `-march=armv8-a`).
+
+`-DZY_SOFTFLOAT` replaces those entry points with an integer IEEE binary64. round ties to even. a NaN becomes a canonical quiet NaN; every other finite result matches the host FPU, including signed zero, subnormals and overflow to infinity. the parser scales with the same add/mul/div, so a soft build and a hard build read a literal the same way. there is still no libc. an AArch64 compile of that path with `-mgeneral-regs-only` is free of `fadd` and of `bl` into a helper.
+
+which path a build takes:
+
+- hosted interpreter, x86_64: hardware, SSE2, via `fops.h`
+- hosted microcore, x86_64: the same
+- arm64 jit under qemu-user: native FPU instructions in the translator
+- llvm backend: native `double` ops
+- RISC-V virt: FPU enabled in the boot stub, `fadd.d` in the microcore
+- AArch64 virt: FPU enabled in the boot stub, `fadd` in the microcore
+- `-DZY_SOFTFLOAT`: integer fallback, selected at build time. the float test line is the same
+
+`test.sh` compiles one interpreter that way and checks `tests/float.zc`. the line is unchanged, so the fixpoint is still 100757 words. the suite after this stage was 369 passed, 0 failed. the one new check is that soft-float interpreter.
+
+what is still open: a call result, a global, a field, a parameter and a return are not yet known to be floats. `-0.0` is still true in `if`, because the sign bit is set. `o3` still does not lift 600..611. magnitudes past about 1e32 still print as `inf`, and a parsed significand is still at most 15 digits.