diff options
| author | 2026-10-12 08:46:23 +0330 | |
|---|---|---|
| committer | 2026-10-12 08:46:23 +0330 | |
| commit | ecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch) | |
| tree | 70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /docs/history/33-fo3 | |
a
Diffstat (limited to 'docs/history/33-fo3')
| -rw-r--r-- | docs/history/33-fo3/notes.md | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/docs/history/33-fo3/notes.md b/docs/history/33-fo3/notes.md new file mode 100644 index 0000000..60d515d --- /dev/null +++ b/docs/history/33-fo3/notes.md @@ -0,0 +1,24 @@ +# 33 — o3 lifts floats + +`o3` used to leave 600..609 in the bytecode, and a float literal could split a region: the word after opcode 600 is raw bits, and a payload of zero is the halt opcode if the lifter reads it as an instruction. discovery and the block lifter now consume that word themselves. print and parse (610 and 611) still leave the region. + +the lifted ops are `fadd`, `fsub`, `fmul`, `fdiv`, `feq`, `flt`, `fle`, `i2f` and `f2i`. two constant operands fold by running that same operation, so the fold is the IEEE result, including a NaN and a signed zero. nothing rewrites `x - x` to zero, `x + 0` to `x`, or `x * 1` to `x`. + +a float variable's install word is negative. that home is a `d` register on arm64 and a `double` alloca on llvm, so a loop that only adds and multiplies does not move the value through an integer register. an integer variable still lives in an `x` register. a freed register keeps its class, because one var index cannot be both. the interpreter runs the same micro-ops through `fops.h`, which is the host FPU unless the build selected `-DZY_SOFTFLOAT`. + +`tests/fo3.zc` prints `5997 5997 4.000000 nan 0 3.250000 1 0 0`. the two 5997s are `(int)` of the same polynomial, plain and `o3`, at 2000 steps. `1.5 + 2.5` folds to 4. `nan - nan` stays `nan`. a negative zero is false in `if` and `while` inside the region. `1.0 < 2.0` is 1, and a NaN is not less than 1. `tests/o3.zc` still lifts 8 regions. + +the fixpoint image is 103655 words, 829240 bytes. the stage-0 image is 99591 words. the small compiler's stage-0 image is 99590 words, inside the 100352 reservation (762 words of room). the run-only map did not move. + +`tests/fbench.zc` times `poly(20000)` without bootstrapping: the slope between 1 repetition and N drops startup and compile time. `(int)` of one call is 59997. before the lift, an o3 copy of that loop did not finish, because the payload of `0.0` was read as halt, so the before number is the plain bytecode. milliseconds per call: + +- interpreter, before 5.318, after (o3) 0.869, about 6.1 times +- llvm, before 0.167, after 0.037, about 4.5 times +- arm64 jit under qemu-user, before 1.620, after 0.292, about 5.5 times +- microcore, before 5.194, after 5.054. it does not lift o3, so both are the bytecode + +the plain loop after the change is the same speed as before (interpreter 5.268, llvm 0.163, arm64 1.625, microcore 5.179). + +`test.sh` after this stage is 401 passed, 0 failed. + +what was still open here, and closed in stage 34: magnitudes past about 1e32 printed as `inf`, and a parsed significand stopped at 15 digits. |
