boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit 0ca5b9881732695ee428b3551659bd9512643549
parent f462972eb40f81e1508ef135a24a8692309ca16f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun, 26 Apr 2026 22:46:42 -0700

docs/CC-PUNCHLIST: mark §B + §C + §H + §K.1 as green

Updates each item with the fixture filenames and a short note on
the implementation choice. Replaces the §B "Pick one fix" preamble
with the chosen design (cg-dup + cg-postinc/postdec) and the §H
preamble with the cg-ifelse-merge contract.

Diffstat:
Mdocs/CC-PUNCHLIST.md | 148++++++++++++++++++++++++++++++++++++++++++-------------------------------------
1 file changed, 78 insertions(+), 70 deletions(-)

diff --git a/docs/CC-PUNCHLIST.md b/docs/CC-PUNCHLIST.md @@ -91,56 +91,59 @@ upstream of nearly everything else. Land this first. ### B. Lvalue mechanics -`cg-take-addr` does not preserve the original lval, so any operation -that needs to *use* an lvalue twice (compound assign, inc/dec) is -broken. Pick one fix and document it in -[CC-CONTRACTS §4.1](CC-CONTRACTS.md#41-parsers-responsibilities) row -"`lhs += rhs`": - -- (a) `cg-take-addr` leaves `[orig-lval, ptr-rval]`; or -- (b) introduce `cg-dup` (duplicate top vstack entry). - -- [ ] **Pre-`++` / pre-`--`** - - cg: `cc-cg/NN-preinc.scm` — `int x = 5; ++x; return x;` → exit 6. - - parse: `cc-parse/NN-preinc.c` - - Needs: lhs preservation per above. - -- [ ] **Post-`++` / post-`--` returns old value** - - cg: `cc-cg/NN-postinc.scm` — `int x=5; int y=x++; return x*10+y;` +Picked **(b) `cg-dup`** — duplicate the top vstack entry, used for +compound assign and pre-inc/dec to keep the lhs lval available across +its own load. Post-inc/dec use a dedicated `cg-postinc` / `cg-postdec` +primitive to capture the old rval before the store. See +[CC-CONTRACTS §4.1](CC-CONTRACTS.md#41-parsers-responsibilities). + +- [x] **Pre-`++` / pre-`--`** + - cg: `cc-cg/21-preinc.scm` — `int x = 5; ++x; return x;` → exit 6. + - parse: `cc-parse/21-preinc.c` + - Done: parser dups lhs lval, loads, +1, assigns; pops result. + +- [x] **Post-`++` / post-`--` returns old value** + - cg: `cc-cg/22-postinc.scm` — `int x=5; int y=x++; return x*10+y;` → exit 65. - - parse: `cc-parse/NN-postinc.c` - - Needs: `cg-postinc` / `cg-postdec`, or parser uses `cg-dup` to - keep the old rval before the store. - -- [ ] **Compound assignment on simple lval (`+= -= *= /= %= <<= >>= &= ^= |=`)** - - cg: `cc-cg/NN-cmpd-simple.scm` — `int x=7; x+=3; return x;` → exit 10. - - parse: `cc-parse/NN-cmpd-simple.c` — one fixture per op family is - fine; the cg primitives are shared. - - Needs: same lhs preservation; existing parser sequence (take-addr, - push-deref, load, rhs, arith-conv, binop, assign) works once - preservation is in. - -- [ ] **Compound assignment through pointer** - - cg: `cc-cg/NN-cmpd-ptr.scm` — `int x=7; int *p=&x; *p+=3; return x;` - - parse: `cc-parse/NN-cmpd-ptr.c` - - Needs: validates the indirect-slot path in `cg-assign`. - -- [ ] **`*p++` walking an array** - - cg: `cc-cg/NN-deref-postinc.scm` — sums a 3-element array. - - parse: `cc-parse/NN-deref-postinc.c` - - Needs: composes B above with pointer arithmetic scaling. + - parse: `cc-parse/22-postinc.c` + - Done: `cg-postinc` / `cg-postdec` primitives composed of two + dup+load passes — one to capture the old rval (which lives in a + never-reused spill slot), one to compute the +1/-1 store. + +- [x] **Compound assignment on simple lval (`+= -= *= /= %= <<= >>= &= ^= |=`)** + - cg: `cc-cg/23-cmpd-simple.scm` — `int x=7; x+=3; return x;` → exit 10. + - parse: `cc-parse/23-cmpd-simple.c` — one of every op family. + - Done: parser uses `cg-dup` + `cg-load` + rhs + arith-conv + binop + + assign; the `cg-take-addr`/`cg-push-deref` indirection is gone. + +- [x] **Compound assignment through pointer** + - cg: `cc-cg/24-cmpd-ptr.scm` — `int x=7; int *p=&x; *p+=3; return x;` + - parse: `cc-parse/24-cmpd-ptr.c` + - Done: same parser sequence; `cg-push-deref`'s indirect-slot lval + composes correctly with `cg-dup` + `cg-assign`. + +- [x] **`*p++` walking an array** + - cg: `cc-cg/25-deref-postinc.scm` — walks a 3-element span via *p++. + - parse: `cc-parse/25-deref-postinc.c` + - Done: composes B.2 (post-inc on a ptr lval; pointer scaling falls + out of `cg-binop add`'s ptr branch) with `*p` deref. Also fixed + `cg-arith-conv` to skip the relabel when one operand is ptr/arr + so `cg-binop` still sees a ptr/int pair (previously it saw both + sides relabelled to ptr and skipped the scaling). ### C. `sizeof` -- [ ] **`sizeof e` returns the type's actual size** - - parse: `cc-parse/NN-sizeof-expr.c` — `int x; return sizeof x;` → 4. - - Needs: parser peeks `(opnd-type (cg-top …))`, computes size, pops, - pushes `imm u64 size`. Today returns 8 always - (`parse.scm` line ~836). +- [x] **`sizeof e` returns the type's actual size** + - parse: `cc-parse/26-sizeof-expr.c` — `int x; return sizeof x;` → 4. + - Done: parser peeks `(opnd-type (cg-top …))`, takes its + `ctype-size`, pops, pushes `imm u64 size`. Both forms + (`sizeof e` and `sizeof(e)`) updated. -- [ ] **`sizeof` over struct, array, pointer, char** - - parse: `cc-parse/NN-sizeof-types.c` — sum of representative sizes - against a known integer. +- [x] **`sizeof` over struct, array, pointer, char** + - parse: `cc-parse/27-sizeof-types.c` — sum of `char`, `short`, + `int`, `long`, `int*`, `int[5]`, `struct S{int a; int b;}` → 51. + - Done: the type form already returned `ctype-size ty`; this + fixture just locks the answer in. ### D. Aggregates @@ -273,26 +276,31 @@ accepts an init bv but is never given one. ### H. Conditionals as values -`cg-ifelse` is correct for `if`-statements (thunks push nothing) but -leaks two opnds when both thunks push (ternary, `&&`, `||`). The fix -is a result-merging primitive: caller pre-allocates the result slot, -both branches store into it, vstack ends with one frame opnd. - -- [ ] **Ternary `?:` leaves exactly one rval** - - cg: `cc-cg/NN-ternary.scm` — `int x = c ? 1 : 2; return x;` → exit 1. - - parse: `cc-parse/NN-ternary.c` - - Needs: result-merging primitive (`cg-ifelse-merge` or similar); - parser passes the result type, cg allocates the slot. - -- [ ] **`&&` short-circuit leaves exactly one i32 rval** - - cg: `cc-cg/NN-land.scm` - - parse: `cc-parse/NN-land.c` - - Needs: same merging primitive; result type is `%t-i32` - irrespective of operands. - -- [ ] **`||` short-circuit leaves exactly one i32 rval** - - cg: `cc-cg/NN-lor.scm` - - parse: `cc-parse/NN-lor.c` +Added `cg-ifelse-merge`: caller pre-allocates the result slot, each +thunk pushes one rval that is then loaded and stored into the slot, +and the slot's frame rval is left on the vstack. The merged result +type is taken from the first thunk's pushed type — parser is +responsible for arranging compatible types in the two branches. + +- [x] **Ternary `?:` leaves exactly one rval** + - cg: `cc-cg/28-ternary.scm` — `c ? 7 : 9` with c=1 → exit 7. + - parse: `cc-parse/28-ternary.c` + - Done: parser swaps `cg-ifelse` for `cg-ifelse-merge` in the + `qmark` arm of `parse-binary-rhs`; both branches push their + parsed rval directly. + +- [x] **`&&` short-circuit leaves exactly one i32 rval** + - cg: `cc-cg/29-land.scm` + - parse: `cc-parse/29-land.c` + - Done: parser injects `cg-cast %t-bool` then `cg-cast %t-i32` on + the rhs side so the merged result is i32 ∈ {0,1}; the else-arm + pushes `%t-i32 0`. + +- [x] **`||` short-circuit leaves exactly one i32 rval** + - cg: `cc-cg/30-lor.scm` + - parse: `cc-parse/30-lor.c` + - Done: mirrors §H.2 with the bool-cast on the else-arm and a + constant `%t-i32 1` in the then-arm. ### I. Storage classes @@ -323,12 +331,12 @@ both branches store into it, vstack ends with one frame opnd. ### K. Expressions and conversions -- [ ] **Comma operator (`a, b` as expression)** - - parse: `cc-parse/NN-comma.c` — `int a; int b; (a=1, b=2); return a + b*10;` +- [x] **Comma operator (`a, b` as expression)** + - parse: `cc-parse/31-comma.c` — `int a; int b; (a=1, b=2); return a + b*10;` → exit 21. - - Needs: add `comma` to `%binop-bp` at lowest precedence, left-assoc. - Handler discards lhs (`cg-pop`) before evaluating rhs. tcc.c uses - this in `for` headers. + - Done: added `(comma . (1 . 2))` to `%binop-bp` (left-assoc, below + `assign`'s 4/3 so `parse-call-args ps 4` still won't slurp it as a + call separator); handler `cg-pop`s the lhs and evaluates the rhs. - [ ] **Function-pointer call** - cg: `cc-cg/NN-fnptr-call.scm` — push a fn-typed sym, spill to a