Branch ast-stage-c. L7 = "flip: lower from the AST instead of
inline; delete the inline emit + Fwd* machinery".
The flip makes Lower the sole emitter. The obstacle is that QbeGen
holds one session state, used by the inline emit during parse; a
per-unit Lower emit would be clobbered by the next unit's inline emit.
So the flip is a big-bang: either remove/suppress the grammar's 533
QbeGen.* call sites, or give QbeGen two states — neither is a
byte-verifiable step.
The pragmatic path is therefore a session re-emit: collect every
unit's AST and re-emit the whole session with Lower after parsing.
That is byte-comparable against the legacy session image and becomes the
flip once the inline emit is removed.
d30abfd, tag v3-lower7-scaffold)Lower.LowerSession/LowerOneUnit/MaterializeGlobals.compiler.frm) collects GetUnit() per file and calls
Lower.LowerSession under -lower.SymTab.Materialize makes a unit's own VAR/CONST visible in
globScope, so GlobalRef resolves "<unit>_<name>" at session end
(the unit scopes are closed by then).Lower.Reset from the M2 root so the owned tables persist
across a session.Still scaffolding (inline emit untouched); suite 200/200, FIXPOINT OK (3,401,129 bytes).
ce2fc67, tag v3-lower7-session)DefUnit now builds an AST (proc headings recorded as
NkProcDecl); LowerDecls replays a bodyless proc as a heading.lower_ok_files added,
and DBasicProg, DQualProg, TQual (def-CONST), TQualP
(def-PROC) byte-match. Fixes: image named after the program module;
MaterializeGlobals also materializes TYPE/CLASS names;
SymTab.ReenterModGlobal keeps nested-module globals'
"<outer>_<name>" symbols; AST.Init once per session under -lower.Suite 204/204; FIXPOINT OK (3,405,813 bytes).
LowerSession needs every unit's
AST alive at once, but AST.MaxNodes = 65536 is sized for one unit;
the compiler's session overflows it (MakeNode → NoNode, later
units dump (nil)). Growing the arena past the 4 MiB sessBuf is
not viable. So the session re-emit cannot handle the compiler —
the flip must instead emit per unit at each unit's END (AST valid,
scope open), which is the two-state / inline-emit-removal problem.storage_prog differs: Lower emits
$malloc_6(l link, ...) where the legacy emits $malloc(...) — the
ext flag in Lower.NoteProc is hardcoded FALSE and Mangled's
ProcLink fails after scopes close.LowerDecls emitted a procedure's parameter loop even when ProcInfo
failed, using an uninitialised np — so the loop ran ~forever inside
FindProc. (MaxProc = 64 is far too small for a whole session, so
ProcInfo failed for most of the compiler's procs.) Fixed
(a9a8ecd): the proc is skipped unless ProcInfo succeeds, and each
ParamInfo is guarded. Also grew the AST arena/pool (caeeeb5) — the
arena/pool data lines are compact z runs, so this is nearly free.
Implemented an open-addressing name index (HashName/HashGetSym/
HashGetProc) for FindSym/FindProc in Lower. Results:
MaxProc=512 completed in <300 s; before it hung).MaxProc ≥ 713), and at MaxProc ∈ {768,1024} the same
run is slow/segfaults (CopySpan via ParamInfo) — the
size/layout-sensitive bug again.Lower, m2s2 (built by m1s1) produces no output on the compiler
input (stage 3). So the index triggers another latent V3 miscompile.Reverted to the green state (a9a8ecd). Suite 204/204.
Three separate latent V3 bugs now block the whole-session re-emit:
(a) the ProcInfo garbage-np loop (fixed), (b) a size/layout-sensitive
miscompile at large tables, (c) a miscompile triggered by the hash code.
Until (b)/(c) are isolated, the session re-emit is impractical, and the
grammar rewrite remains the more predictable flip path.