|
@@ -0,0 +1,46 @@
|
|
|
|
|
+# Short-circuit AND/OR
|
|
|
|
|
+
|
|
|
|
|
+Tag `v3-short-circuit`. Main suite **111/111**.
|
|
|
|
|
+
|
|
|
|
|
+## Why
|
|
|
|
|
+
|
|
|
|
|
+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.
|
|
|
|
|
+
|
|
|
|
|
+## How
|
|
|
|
|
+
|
|
|
|
|
+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 = 0`
|
|
|
|
|
+- The merge uses a **4-byte memory slot** (`Slot4`/`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.
|
|
|
|
|
+
|
|
|
|
|
+## Result
|
|
|
|
|
+
|
|
|
|
|
+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).
|
|
|
|
|
+
|
|
|
|
|
+## Still open (task 2: full self-image)
|
|
|
|
|
+
|
|
|
|
|
+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.
|
|
|
|
|
+
|
|
|
|
|
+## Files
|
|
|
|
|
+
|
|
|
|
|
+`compiler/src/{M2.atg,QbeGen.def,QbeGen.mod,M2.lst}`.
|