session-2026-09-25b.md 3.4 KB

Session save — 2026-09-25 (part b): V3 self-compiles; short-circuit WIP

master @ 757f518 (v3-selfcompiles) — suite 111/111, tree clean (except the user's uncommitted compiler/toto.mod edit).

Headline

The self-compiled V3 (V3 compiled by V3) runs, parses, and emits code; for tests/t_constfold.mod its .ssa is byte-identical to the gm2-built V3's:

./M2       tests/t_constfold.mod -> gen_ssa/TConstFold.ssa
/tmp/M2self tests/t_constfold.mod -> gen_ssa/TConstFold.ssa   (cmp: IDENTICAL)

That is a stage-2 self-hosting fixpoint for a test file.

Fixed today (each with a minimal repro)

  1. Nested modules (ListHandler) — lowered + export hoisting.
  2. Inline record array fields (standard M2) — heap records' array fields now have a descriptor header.
  3. NUL-terminated string model (terminator slot at index = count); stdlib Strings + C shim NUL-based.
  4. p^ / a[i]^ as a VAR actual → pass the pointee address.
  5. De-eagered NIL guards in SymTab and the driver's PrintListing.
  6. Off-by-one string scans in QbeGen (Len/Cpy/App/ParseInt used i < HIGH(s); a literal's last char was dropped → "gen_ssa/" became "gen_ssa").

Current blocker (full self-image)

Compiling the whole compiler source set with /tmp/M2self still aborts, in SymTab.Resolve:

WHILE (n < ResDepth) AND (t >= 0) AND (t < VAL(INTEGER, nTypes))
 AND (tform[t] = FAlias) DO   (* eager AND evaluates tform[-1] when t < 0 *)

V3 evaluates both sides of AND/OR; gm2 short-circuits. The compiler sources rely on short-circuit in ~25 places ((r = InvalidType) OR (tform[r] # …), NIL guards, etc.). Two ways forward:

  • (A) short-circuit AND/OR in V3 — the principled fix (matches gm2), done in the wip/short-circuit branch but 14 tests fail; needs debugging.
  • (B) de-eager every guard site in the compiler sources (rewrite the ~25 (idx = Invalid) OR … patterns as sequential checks) — mechanical but fragile.

WIP: wip/short-circuit (branch @ 26c01d0)

Implements short-circuit AND/OR via deferred-output buffering: QbeGen.DelayBegin buffers the RHS operand's code, DelayEnd restores output, DelayFlush replays it inside the branch; SimExpr (OR) and Term (AND) emit if a { result = 1/0 } else { <RHS>; result = b }. Currently 14 tests fail (e.g. t_bool, t_set, t_pointer), so the branch logic/labels or the buffer replay is wrong. Do not merge as-is.

Next steps

  1. Debug wip/short-circuit until 111/111 (likely the branch/label or Jnz-with-immediate handling) — or take route (B).
  2. Fix the remaining self-image abort(s); get /tmp/M2self to compile the whole set to a byte-identical M2.ssa (full fixpoint).
  3. Cross-stage FileIO selection and bootstrap/fixpoint.sh (Stage1 gm2 → Stage2 V3 → Stage3 V3), with the stage-aware CR flag (-m for gm2, no -m for V3).

Resume

cd .../m2compiler-V3/compiler
./build.sh && ./run_tests.sh            # 111/111 on master

# WIP branch:
git checkout wip/short-circuit          # short-circuit experiment (14 failing)

# self-image check (from master):
(cd src && CRFRAMES="$(pwd)" .../CocoGm2/CR -C M2.atg >/dev/null)
./M2 <full session>                     # writes gen_ssa/M2.ssa
qbe -o /tmp/M2self.s gen_ssa/M2.ssa; cc /tmp/M2self.s ../runtime/syslib/shim.c -o /tmp/M2self -lm
/tmp/M2self tests/t_constfold.mod        # byte-identical output