Tag v3-short-circuit. Main suite 111/111.
V3 evaluated both sides of AND/OR; gm2 (and the compiler's own
sources) rely on short-circuit — e.g. SymTab.Resolve's
… AND (tform[t] = FAlias) dereferences tform[-1] when t is
invalid. Roughly 25 such guard sites exist in the compiler sources, so
matching gm2 is the right fix rather than rewriting them.
The RHS operand is already parsed (and its code emitted) by the time the binary-op action runs, so short-circuit needs deferred code:
QbeGen.DelayBegin redirects output into a small buffer;
DelayEnd restores the previous sink; DelayFlush replays the buffer
at the branch. WEmit routes to the delay buffer while active.SimExpr (OR) and Term (AND) wrap the RHS Term/Fact in
DelayBegin/DelayEnd and emit:
OR: if a then r = 1 else { <RHS>; r = b }AND: if a then { <RHS>; r = b } else r = 0Slot4/StoreW/LoadW)
rather than a QBE phi: a phi must name the right predecessor block,
but the RHS can span several blocks (e.g. a set-membership trap
check), which broke the phi's predecessor list. The slot is robust to
any RHS shape.Suite 111/111 (the earlier WIP failed 14 tests: DelayFlush popped the
wrong buffer index, then the CopyOp-only merge collapsed the two
branches to one compile-time operand).
The self-compiled V3 compiles a single file to byte-identical .ssa,
but the whole compiler source set still aborts, now in the scanner's
GetName (LexName ← GetIdent ← ProcTypeSection) — a bounds trap;
next to diagnose.
compiler/src/{M2.atg,QbeGen.def,QbeGen.mod,M2.lst}.