boot2

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

commit d08722348902363a034ec532e71f67b3151f6047
parent 790ab01a4a5ee273f357f12e3b872736371e3879
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun, 26 Apr 2026 23:46:25 -0700

docs: mark §F.1-4, §G.1-2, §J.1-3, §K.2-6 done in punchlist

All items completed with cg + parse fixtures and impl. §G.2 ships
with a documented limitation: only first 4 incoming args (named +
variadic) live in the saved-register area; >=4 needs LDARG path.

Diffstat:
Mdocs/CC-PUNCHLIST.md | 159++++++++++++++++++++++++++++++++++++++++++-------------------------------------
1 file changed, 85 insertions(+), 74 deletions(-)

diff --git a/docs/CC-PUNCHLIST.md b/docs/CC-PUNCHLIST.md @@ -230,46 +230,55 @@ accepts an init bv but is never given one. ### F. Control flow extensions -- [ ] **`do { } while (e);`** - - cg: `cc-cg/NN-do-while.scm` - - parse: `cc-parse/NN-do-while.c` - - Needs: parser already wires `cg-loop` + `cg-if` + `cg-break`; - this is largely a fixture exercise. - -- [ ] **`for (init; cond; step)` with declaration in `init`** - - parse: `cc-parse/NN-for-decl.c` - - Needs: existing `parse-for-stmt` exercised end-to-end. - -- [ ] **`switch / case / default` with fall-through** - - cg: `cc-cg/NN-switch.scm` — three cases falling through to default. - - parse: `cc-parse/NN-switch.c` - - Needs: validates the existing `swctx` machinery in cg. - -- [ ] **`goto` / labelled statement (forward and backward)** - - cg: `cc-cg/NN-goto.scm` - - parse: `cc-parse/NN-goto.c` - - Needs: replace the `cg-break` hack in `parse-goto-stmt`. Add +- [x] **`do { } while (e);`** + - cg: `cc-cg/63-do-while.scm` + - parse: `cc-parse/63-do-while.c` + - Done: composes existing `cg-loop` + `cg-if` + `cg-break`; + fixture-only. + +- [x] **`for (init; cond; step)` with declaration in `init`** + - parse: `cc-parse/64-for-decl.c` + - Done: existing `parse-for-stmt` exercised end-to-end. + +- [x] **`switch / case / default` with fall-through** + - cg: `cc-cg/64-switch.scm` — three cases falling through to default. + - parse: `cc-parse/65-switch.c` + - Done: validated the existing `swctx` machinery in cg. + +- [x] **`goto` / labelled statement (forward and backward)** + - cg: `cc-cg/65-goto.scm` + - parse: `cc-parse/66-goto.c` + - Done: replaced the `cg-break` hack in `parse-goto-stmt`. Added `cg-emit-label cg name-bv` (drops `::user_<name>`) and `cg-goto cg name-bv` (emits `%b(&::user_<name>)`). - `parse-labelled-stmt` calls `cg-emit-label` before the inner stmt. + `parse-labelled-stmt` now calls `cg-emit-label` before the inner stmt. + - Drive-by fix: `cg-binop` `'le`/`'ge` previously emitted `%xori`, + which is undefined in P1. Replaced with `%li(t1,1) %xor(t0,t0,t1)`. ### G. Variadics -- [ ] **Variadic call: per-arg default-promote** - - cg: `cc-cg/NN-vararg-call.scm` - - parse: `cc-parse/NN-vararg-call.c` - - Needs: parser inspects fn type at `parse-call-args`; for arg index - ≥ named-arg count, emits `cg-promote` and `cg-cast` per CC.md - §Implicit conversions. - -- [ ] **Variadic receive: `__builtin_va_start/arg/end`** - - cg: `cc-cg/NN-vararg-recv.scm` — sums N int-typed variadic args. - - parse: `cc-parse/NN-vararg-recv.c` - - Needs: `cg-va-start cg ap-lval`, `cg-va-arg cg ap-lval ctype`, - `cg-va-end cg ap-lval`. Layout: variadic args sit at a known - offset relative to fixed-arg slots; cg already controls the frame. - - Also needs: a bundled `stdarg.h` (CC.md §Standard library - expectations — "supplied by us"). +- [x] **Variadic call: per-arg default-promote** + - cg: `cc-cg/66-vararg-call.scm` + - parse: `cc-parse/67-vararg-call.c` + - Done: parser inspects fn type at `parse-call-args`; for arg index + ≥ named-arg count, emits `cg-promote` per CC.md §Implicit + conversions. Fixed-arg index emits `cg-cast` to declared param + type (also covers §K.5). + +- [x] **Variadic receive: `__builtin_va_start/arg/end`** + - cg: `cc-cg/69-vararg-recv.scm` — sums N int-typed variadic args. + - parse: `cc-parse/76-vararg-recv.c` + - Done: added `cg-va-start cg`, `cg-va-arg cg ctype`, + `cg-va-end cg` (each pops ap-lval from vstack); + `cg-fn-begin/v` reserves a 4-slot saved-register area and saves + a0..a3 unconditionally so va_arg can read past the named-arg count. + Parser recognizes `__builtin_va_start/arg/end` at parse-primary; + `parse-fn-body` threads the fn ctype's variadic? flag. + - Bundled `cc/headers/stdarg.h` aliases `va_list`/`va_start`/ + `va_arg`/`va_end` to the builtins. + - **Limitation**: only the first 4 incoming args (named + variadic) + live in the saved-register area. Variadic args at index >= 4 need + an `LDARG`-based path that is not yet implemented. ### H. Conditionals as values @@ -306,20 +315,25 @@ both branches store into it, vstack ends with one frame opnd. ### J. Driver / envelope -- [ ] **Entry stub forwards `argc` / `argv` to `main`** - - e2e: gate is "cc-e2e/00-return-argc still green after stub change." - - Needs: confirm against P1's program-entry contract whether `a0`/`a1` - already hold argc/argv at `p1_main`. If yes, the current - fall-through stub is correct and we just document it; if no, - `cg-finish` reads them from P1's argv block. - -- [ ] **`int main()` falling off the end returns 0** - - parse: `cc-parse/NN-main-noret.c` — `int main(){}` → exit 0. - - Needs: ret-slot zero-init guarantee (verify it lands in the - prologue, not just in the conceptual frame layout). - -- [ ] **Multi-function translation unit with forward references** - - parse: `cc-parse/NN-multi-fn.c` +- [x] **Entry stub forwards `argc` / `argv` to `main`** + - e2e: `cc-e2e/00-return-argc` (already green; locked in). + - Done: P1's program-entry contract delivers `a0=argc`, `a1=argv` + at `p1_main` (P1.md §Program Entry). `%call` doesn't clobber + a0/a1, so the existing fall-through stub `%fn(p1_main, 16, + { %call(&cc__main) })` correctly forwards them. Documented in + `cg-finish`. + +- [x] **`int main()` falling off the end returns 0** + - parse: `cc-parse/68-main-noret.c` — `int main(){}` → exit 0. + - Done: `cg-fn-begin` now zero-inits the ret slot in the prologue + when the return type isn't void, so falling through to `::ret` + reads back a defined 0 instead of relying on kernel zero-fill. + +- [x] **Multi-function translation unit with forward references** + - parse: `cc-parse/69-multi-fn.c` + - Done: forward declaration `int helper(int x);` binds an extern + fn sym up-front so `parse-primary` finds it before the + definition appears. ### K. Expressions and conversions @@ -330,41 +344,38 @@ both branches store into it, vstack ends with one frame opnd. Handler discards lhs (`cg-pop`) before evaluating rhs. tcc.c uses this in `for` headers. -- [ ] **Function-pointer call** - - cg: `cc-cg/NN-fnptr-call.scm` — push a fn-typed sym, spill to a +- [x] **Function-pointer call** + - cg: `cc-cg/67-fnptr-call.scm` — push a fn-typed sym, spill to a frame slot, reload, call. - - parse: `cc-parse/NN-fnptr-call.c` — `int (*fp)(int) = f; return fp(41);` - → exit 42. - - Needs: exercises `cg-call`'s `%callr(t0)` branch; verify + - parse: `cc-parse/71-fnptr-call.c` — `int (*fp)(int) = f; return fp(7);` + → exit 21. + - Done: exercises `cg-call`'s `%callr(t0)` branch; verified return-type extraction walks `ptr → fn → ret` correctly. -- [ ] **Enum constant in expressions** - - parse: `cc-parse/NN-enum-const.c` — `enum E { A=1, B=10 }; return A+B;` - → exit 11. - - Needs: existing `cg-push-sym` `'enum-const` branch; just a fixture. +- [x] **Enum constant in expressions** + - parse: `cc-parse/72-enum-const.c` — `enum E { A=1, B=10, C }; + return A+B+C;` → exit 22. + - Done: locked in the existing `parse-primary` `'enum-const` branch. -- [ ] **`void *` ↔ `T *` implicit conversion (no cast required)** - - parse: `cc-parse/NN-voidptr-impl.c` — `void *p; int x=42; p=&x; +- [x] **`void *` ↔ `T *` implicit conversion (no cast required)** + - parse: `cc-parse/73-voidptr-impl.c` — `void *p; int x=42; p=&x; int *q=p; return *q;` → exit 42. - - Needs: parser accepts both directions at assignment, return, and - call sites without an explicit cast. cg's relabel-only path - between pointer types already supports it. + - Done: cg-cast's `to-kind = 'ptr` clause is relabel-only between + any pointer types; `cg-assign` drives the cast each direction. -- [ ] **Implicit narrowing of fixed-arg call arguments to declared +- [x] **Implicit narrowing of fixed-arg call arguments to declared param type** - - parse: `cc-parse/NN-call-narrow.c` — `int f(unsigned char x){return x;} + - parse: `cc-parse/74-call-narrow.c` — `int f(unsigned char x){return x;} int main(){ return f(258); }` → exit 2. - - Needs: `parse-call-args` emits `cg-cast` per fixed arg to the - declared param type (variadic args are §G.1). + - Done: `parse-call-args` now emits `cg-cast` per fixed arg to the + declared param type (variadic args promoted via §G.1). -- [ ] **Pointer comparison is unsigned** - - cg: `cc-cg/NN-ptr-cmp.scm` — verify two frame-slot pointers compare - via `ltu`. - - parse: `cc-parse/NN-ptr-cmp.c` — `int a[2]; return &a[1] > &a[0];` +- [x] **Pointer comparison is unsigned** + - cg: `cc-cg/68-ptr-cmp.scm` — verifies `%ifelse_ltu` dispatch. + - parse: `cc-parse/75-ptr-cmp.c` — `int a[2]; return &a[1] > &a[0];` → exit 1. - - Needs: confirms `cg-binop`'s `lt/le/gt/ge` dispatch picks the - unsigned variant when either operand is `ptr` or `arr`. Likely - already correct; locks it in. + - Done: `cg-binop`'s `lt/le/gt/ge` dispatch already picks the + unsigned variant for ptr/arr operands. Fixtures lock it in. ### L. Aggregates round 2