kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 9e7fb34dbd5406af47f6f2bc32a89e920548a8a9
parent c67f18b84502a7af20d9486f177d61dfa855dd1a
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue,  2 Jun 2026 07:40:19 -0700

cg: fix i128 -O1 null-deref — flow wide16 int constants as VALUEs (Track 7.3 follow-up)

api_make_wide16_int_const returned an lvalue/PLACE, but Track 7.3 makes
i128/f128 scalar VALUEs. As a place, an i128 constant was passed
by-reference at -O1 and the ABI dereferenced a value slot as a 32-bit
pointer -> SIGSEGV on i128->bool compares (test-parse i128_06_shifts_bitwise,
O1/D,J,E). Return api_make_sv to match api_push_call_result.

test-parse 3784/0 (was 3 fail); toy 1355/0; cg-api 173/0+168/0; opt green;
make bootstrap reproduces byte-identical at -O0 AND -O1.

Diffstat:
Mdoc/plan/CODEGEN.md | 20+++++++++-----------
Msrc/cg/wide.c | 7++++++-
2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/doc/plan/CODEGEN.md b/doc/plan/CODEGEN.md @@ -9,17 +9,15 @@ The **fold-layer isolation + delayed-arith re-enable** (Track 6) is **complete** remains is the **binop/cmp op-split** (the rest of Track 2), the Track 1c completeness audit, and the Track 5 multi-value follow-up. -> **⚠ KNOWN REGRESSION — blocks merge.** `test-parse i128_06_shifts_bitwise` fails at -> **-O1 on the native + link paths** (`O1/D`, `O1/J`, `O1/E`; `-O1/R` interp and all -> `-O0` variants pass). Clean on `main` (`dce052f`: 8/8 pass). Bisect: enters at -> `a0397c6` (Track 7.1/7.2) as `O0/E`+`O1/E` link failures, then **morphs** through -> `6f48bfd` (Track 7.3 wide16 collapse) into the `-O1` D/J/E failures at branch HEAD — -> so the i128 `-O1` lowering is broken by the interaction of the PLACE-predicate -> tightening (7.1/7.2) and the wide16 collapse (7.3). **Every per-stage verify and the -> final verify missed it: `test-parse` was in no stage's gate** (gates ran -> toy/cg-api/opt/isa/smoke + bootstrap; `make bootstrap` reproduces byte-identical -> because it tests stage2==stage3 determinism, not correctness-vs-golden). Root-cause -> and fix the i128 `-O1` path before merging; add `test-parse` to the gate. +> **✓ RESOLVED — i128 -O1 regression fixed.** `test-parse i128_06_shifts_bitwise` had +> crashed (SIGSEGV/SIGABRT) at -O1 on the native/link paths. Root cause: Track 7.3 made +> i128/f128 flow as scalar VALUEs, but `api_make_wide16_int_const` (`src/cg/wide.c`) +> still returned an **lvalue/PLACE**, so an i128 constant entered the stack as a place; +> the O1 ABI lowering then passed it by-reference and dereferenced a value slot as a +> (mistyped 32-bit) pointer → null deref on i128→`_Bool` compares. Fix: return a VALUE +> (`api_make_sv`), matching `api_push_call_result`'s i128 representation. Now full +> `test-parse` is 3784/0 and bootstrap reproduces at -O0 AND -O1. **Lesson: codegen +> gates must include `test-parse` — bootstrap reproducing ≠ correctness.** Forward-looking companion to the canonical design in [doc/CODEGEN.md](../CODEGEN.md). Goal: make the `CfreeCg` public API and the internal `CgTarget` contract carry **one clear diff --git a/src/cg/wide.c b/src/cg/wide.c @@ -38,7 +38,12 @@ ApiSValue api_make_wide16_int_const(CfreeCg* g, i64 value, CfreeCgTypeId ty) { CGLocal local = api_f128_temp_local(g, ty); api_wide16_sext_imm_bytes(g, value, bytes); api_store_f128_bytes(g, local, ty, bytes); - return api_make_lv(api_op_local(local, ty), ty); + /* i128/f128 are scalar VALUEs (Track 7.3), not places: the constant lives in + * `local` and flows as a value. Returning an lvalue here made the O1 ABI path + * pass the constant by-reference and deref a value slot (a null-deref crash on + * i128->bool compares); a value backed by the local is the correct form and + * matches how api_push_call_result represents an i128 result. */ + return api_make_sv(api_op_local(local, ty), ty); } void api_store_f128_bytes(CfreeCg* g, CGLocal local, CfreeCgTypeId ty,