aboutsummaryrefslogtreecommitdiff
path: root/docs/history/27-float/notes.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/history/27-float/notes.md')
-rw-r--r--docs/history/27-float/notes.md19
1 files changed, 19 insertions, 0 deletions
diff --git a/docs/history/27-float/notes.md b/docs/history/27-float/notes.md
new file mode 100644
index 0000000..4420a32
--- /dev/null
+++ b/docs/history/27-float/notes.md
@@ -0,0 +1,19 @@
+# 27 — floating point
+
+a float is an IEEE-754 binary64 in one 64-bit word. an odd literal only has 63 bits, and bit 0 of a double is part of the number, so a float literal is not an odd word. opcode 600 (`flit`, the even word 1200) is followed by the raw bits, and every decoder consumes that word inside the instruction so a payload with bit 0 set is not executed. 601..611 are add, sub, mul, div, eq, lt, le, int-to-float, float-to-int (trunc toward zero), print and parse. they sit above 533, so the enhancement slots do not move and an old image still means what it meant.
+
+every target here has an FPU: x86_64 SSE2, AArch64, and RV64 with the D extension. the interpreter, the microcore and both bare-metal images use the host `double` (gcc emits the hardware op). the arm64 jit emits `fadd`/`fsub`/`fmul`/`fdiv`, `fcmp` plus `cset` (`mi` and `ls`, not `lt` and `le`, because an unordered compare must not count as less), `scvtf` and `fcvtzs`. the llvm backend uses `fadd` and the rest on a double, bitcast to and from i64. print and parse are `fops.h`, not libc, so a board with no C library writes the same text. the form is an optional minus, the integer digits, a dot, and six fractional digits. a tie in the seventh digit rounds away from zero. the non-finite texts are `nan`, `inf` and `-inf`. a parsed significand keeps at most 15 digits. magnitudes past about 1e32 print as `inf` because the scaled integer no longer fits in 128 bits.
+
+the resident lexer stays inside the zc0 subset: it copies the spelling into `tbuf` and runs opcode 611 (`asm { tbuf #1222 }`), which is the same parser zc0 calls in C. neither compiler source contains a float literal. codegen emits `flit` plus the bits. a local that is assigned a float gets bit 5 of its tag, and a later load is still a float. one integer operand of `+ - * /` or a comparison is converted. the result of a comparison is an int. a call's result is not known to be a float, `++` and `--` stay integer adds and clear the flag, and o3 does not lift these opcodes (the region runs as bytecode). `0.0` is false where a word is tested, because its bits are zero. `-0.0` is true, because the sign bit is set. `f2i` of a value outside int64 saturates in the interpreter, the microcore and the arm64 jit; the llvm conversion is only promised for values that fit, which is all the tests use.
+
+`tests/float.zc` is in the zc0 subset, so the same source runs on the resident compiler, the microcore, the arm64 jit, the llvm backend, the small compiler, the run-only image, and both virt boards (run-only and, on the boards, compiled by the resident compiler). the line is
+
+```
+4.000000 4.500000 3.000000 2.500000 2.500000 0.001500 0.100000 -0.125000 inf -inf nan 1 1 1 0 0 3 -3 3.000000 -2.000000 2
+```
+
+`1 + 1.5` is the second `2.500000`. `10 / 4` at the end is still integer division.
+
+the image grew from 91158 words to 93712. the fixpoint holds. the small compiler's hole was 90000 words and the new image is 90138, so the reservation is 92000 and that machine is 176128 words instead of 172032. the heap, the tables and the run-only map are the same.
+
+`test.sh` after this stage: 315 passed, 0 failed. the twelve new checks are the float line on the interpreter, the microcore, the arm64 jit and the llvm backend, the small microcore and `core.c` at that size, the run-only image, both virt boards running the program and compiling it, and one llvm run with `ZYHOT=1` so every float block is compiled. the line matched on all of them.