742 Commits

Author SHA1 Message Date
69e5a777e7 The two ports' findings, and the one arm in the header check that would close them 2026-09-13 23:32:04 +07:00
4c184e68ce A poem of forty-seven kana, and the one raylib call a Flan string cannot make 2026-09-13 23:28:40 +07:00
acc928a203 The b3 note belongs under the table, not inside it 2026-09-13 23:28:39 +07:00
35c33c7b8b The idiv in b3 is most of the denominator, and the two b2 numbers now agree 2026-09-13 23:28:27 +07:00
219a42ed5b The handoff carries the headline and what was left undone 2026-09-13 23:27:29 +07:00
f9f37e524a A note that the old handoff's environment note is now stale 2026-09-13 23:27:20 +07:00
69129fc29f p2's -O0 build is smaller because nothing unrolled the loop 2026-09-13 23:27:07 +07:00
65eeb09378 The corpus numbers, and the rows they came from 2026-09-13 23:26:48 +07:00
1195e90476 The noise is gone and the reporting half is verified by breaking the test on purpose 2026-09-13 23:25:48 +07:00
3c4ca20fea The robustness fixture says its failure is deliberate, and stops printing a linker's words 2026-09-13 23:24:21 +07:00
fdf7531c37 Nine filters that rewrite the buffer they are handed, and the half of them a headless run can pin 2026-09-13 23:22:37 +07:00
fbaf376281 The linker error in dune test is deliberate, and a plan to stop it looking otherwise 2026-09-13 23:21:42 +07:00
eacf7c489f The arithmetic condition landed without restarts, and why that is a question 2026-09-13 23:20:11 +07:00
c9394a6bcd The mismatch is reachable from flan reload, and the guard does not close it 2026-09-13 23:18:25 +07:00
ed32915501 The two redefinition builders refuse to be crossed 2026-09-13 23:15:40 +07:00
11474ecbda The benchmark table, filled in 2026-09-13 23:15:17 +07:00
f9f476dc41 COST.md, with the benchmarks measured and the corpus table still to come 2026-09-13 23:14:57 +07:00
1933295a70 A pixel format is twenty-four names, not an int 2026-09-13 23:13:49 +07:00
8ae77db92c A redefined function that takes and returns a struct, on both backends 2026-09-13 23:12:43 +07:00
2a7fcb6001 The plan for the last two ports, and the one question nobody is awake to answer 2026-09-13 23:10:14 +07:00
385445faa7 Merge branch 'worktree-agent-a1df35fb41dc83276' into dev-loop 2026-09-13 23:10:00 +07:00
9ee398e817 The two cases that would have passed while being wrong
An i32 min / -1 and an f32 cast out of range. The first is where the two
backends disagreed silently rather than both dying -- x86 divided in 64 bits
and truncated on the store, answering -2147483648, where LLVM emitted poison --
and it is the only case that exercises the widening on the way into the
condition, so a bug there would have left every other row passing. The second
is the one place the two backends reach the same answer by deliberately
different routes, f32 bounds here and widened doubles there, and the survey is
what says the routes agree.
2026-09-13 23:09:08 +07:00
188e6bc72f A plan for measuring the aggregate case across the reload boundary 2026-09-13 23:07:26 +07:00
b0f4fb73e1 The x86 backend stops leaving a divide by zero to the hardware
Item 3 of HANDOFF-x86-rt.md, which was blocked on the language decision rather
than on code. check_div and check_cast sit beside check_at and check_slice and
reuse bounds_call unchanged; flan_arith_error takes three extras, so the
channel lands in r9 and the argument registers are exactly full.

Three things differ from the LLVM side because the instruction set does: two
branches rather than one branch and a select, since there is no select and a
second compare on the cold path is free; the cast bounds compared in the
source's own precision rather than widened to a double, which is exact because
every bound is a power of two; and NaN excluded by choosing the direction of
each compare, because ucomis sets CF, ZF and PF together when either operand is
unordered.

Both programs now print byte-identical stdout, stderr and exit status through
either backend.
2026-09-13 23:07:23 +07:00
82c8b38dda The alias is verified in both directions, and the handoff says so 2026-09-13 23:07:22 +07:00
368866c63d A scratch directory per run, after two of them shared one 2026-09-13 23:05:12 +07:00
6c15eef5e5 Do not time a program that only waits for the timeout 2026-09-13 23:02:04 +07:00
957ba076bc Merge branch 'worktree-agent-ab6daf83988bee428' into dev-loop 2026-09-13 22:59:11 +07:00
921155408e The clean survey: ninety-nine match, and the edit described as it stands 2026-09-13 22:56:41 +07:00
a431cddd3b A divide by zero names the file and the line, and is answerable
Three arithmetic situations had no defined behaviour and the two backends
disagreed about all three: a divide or remainder by zero, which was a raw
SIGFPE with no message and no location; (/ min -1), whose quotient is one past
the top of the type; and a float to integer cast whose value does not fit,
which LLVM called undefined and would fold to anything.

They now signal ArithError with `error`, exactly as a bad index signals
BoundsError, and die with a sentence naming the file, the line and the operands
only if nothing answered. The guards ride the same --checks flag as the bounds
check and are elided with it.

No restart is established at the failing operation. The sketch this started
from asked for use-value, and the implementation ruled it out: a restart frame
is allocated by the restart-case that offers it, on its own stack, so the
runtime cannot hold one on a program's behalf and use-value here would mean an
alloca and a restart frame at every division in every checked build. That is
the cost already refused for indexing, buying a silently different answer.

The x86 backend is unchanged and is the next commit.
2026-09-13 22:55:26 +07:00
69d10bec4e Arithmetic with no answer is a condition: the plan 2026-09-13 22:55:26 +07:00
60d4c762e1 Merge branch 'worktree-agent-ab6daf83988bee428' into dev-loop 2026-09-13 22:50:40 +07:00
54da06d111 An @x86 alias, and the two scripts that ask what the backend costs 2026-09-13 22:49:38 +07:00
dc2b5ed02a The measurements the handoff was missing: the baseline held exactly 2026-09-13 22:49:19 +07:00
0483ae81e8 What the 98 is and is not 2026-09-13 22:48:52 +07:00
c4e68dcc3c The full survey: 98 match, nothing differs, nothing refused 2026-09-13 22:48:18 +07:00
4b9a6c0852 The targeted survey: both probes match, and what p10 proves 2026-09-13 22:46:55 +07:00
624a94af7b A smaller hunk, and the restart-case shape that is not a counterexample 2026-09-13 22:46:16 +07:00
1e816702b6 The handoff for both guards: one correct, one wrong 2026-09-13 22:43:52 +07:00
5442c11389 The handoff for the x86 redefinition emitter, as built 2026-09-13 22:43:06 +07:00
939417446d Item 5's guard dropped, item 4's reached and correct 2026-09-13 22:42:42 +07:00
bd69f684ed An --x86 host reloads an --x86 module, checked by running it 2026-09-13 22:40:52 +07:00
69ea66deca An x86 redefinition emitter, and GOT addressing for the host's symbols 2026-09-13 22:38:48 +07:00
b0f21ae513 Item 5's guard is reachable in ten lines, and a stub handoff 2026-09-13 22:36:14 +07:00
8e0e99f439 A stub handoff for the cost lane 2026-09-13 22:35:19 +07:00
dd5eac2821 The plan for an x86 redefinition emitter, written before the work 2026-09-13 22:32:55 +07:00
b1cc67b36f Second handoff: the backend is correct and is not yet the dev backend 2026-09-13 21:27:03 +07:00
e725a5aab4 Merge branch 'worktree-agent-af9064091c0602dc8' into dev-loop 2026-09-13 21:24:12 +07:00
6363635bae DISCUSS item 18, and the handoff: the aggregate return that was never there
Item 17 left two correctness items and a loose end. The loose end is the
answer to the first item: flan_vec_as_slice's Flan-level return type is Unit,
so is_void answers before is_agg is ever tested, and that is the convention
rather than one symbol's accident. So there was no sret-for-Rt to build, and
building one would have been untestable and wrong.

The second item is built and tested by the only thing that can test it, a
preloaded dlsym, because a dev build with nothing yet redefined prints what a
release build prints whether or not anything reads a cell.

Survey: 93 MATCH / 0 DIFFER / 2 refused before, 97 / 0 / 0 after; 97 / 0 / 0
again with --dev on both sides.
2026-09-13 21:23:43 +07:00
81f7e464ec The indirection cell on the x86 backend, and --x86 --dev with it
FnAddr (Fnval n) emitted the symbol, which is right for a whole-program build
and wrong the instant anything is redefined into it. It now reads the cell,
and so does every direct call, which is what emit.ml's body_of does and is the
half that matters: a redefinition is one store, and it has to reach call sites
that already exist.

What is emitted, all of it behind dev:

  - one cell per function in .data, .globl, initialised to the body this build
    compiled. Spelled exactly as Emit.cellname spells it, because the point of
    having one here is that an LLVM-built module binds
    @"flan.cell.<n>" = external global ptr against it. nm -D over the two
    builds of the same program gives identical sets of 68 cell symbols.
  - the cell load placed after the arguments, which emit.ml has as a
    load-bearing comment: a redefinition landing between two calls must not
    land in the middle of one. CallPtr stays the other way round.
  - the flan_dev_reg_enable constructor, which arms the allocation registry.

Not emitted: Emit.cellptr, the deeper spelling for a name the host was never
built with. It cannot arise in a whole-program build and belongs with the
redefinition module that would introduce one.

The --x86 --dev refusal is relaxed, and the argument is that flan dev never
reaches this fork: --x86 is read only by flan build, and the daemon builds
host and modules through Build.executable / Build.shared without it. So the
flag means a host whose call sites are redefinable, and nothing claims the
module that would redefine through them exists.

Two things were needed to believe any of that. First, the corpus with --dev on
both sides: 97 MATCH, 0 DIFFER, same as without it. Before the constructor was
added that read 96/1 — registry.flan asks (live? ...) and got four zeroes,
which is the whole of what a dev host does differently besides the cells.

Second, and the corpus cannot do this one: a dev build starts with every cell
pointing at the body this build compiled, so it prints what a release build
prints whether anything reads the cell or not. spike/x86/cells.sh preloads a
shared object whose constructor dlsyms flan.cell.twice and stores a different
body there -- the one store a redefinition ends in, done from outside, no
compiler involved. Both dev builds then print the new answer for a direct call
and for a function value, and both release builds are unchanged, which is what
says the change came from the indirection and not from symbol interposition.

One thing the later lane inherits, now written in both headers rather than
left to be discovered. x86.ml licenses its own calling convention on the
grounds that a dev build is compiled entirely here and a release build
entirely by LLVM, so the two never meet in one process. A cell an LLVM-built
module can store into is the first thing that could make that false: the
conventions agree on scalars and disagree on every aggregate, so an
Emit.redefinition module dlopened into an --x86 host would be right until the
first redefined function took or returned a struct. The answer is a
redefinition emitter here, not a classifier.
2026-09-13 21:17:39 +07:00