From 837fdb475389e44df4f999d5609b7e6bb46e586c Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 6 Jun 2026 02:26:29 +0900 Subject: [PATCH] =?UTF-8?q?cgen:=20B5-c4=20#93=20deref-index=20pointee=20c?= =?UTF-8?q?hase=20=E2=80=94=20the=20one=20spurious=20MOVQ,=20#263-polarity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trace at the c3 tip: cs-vs-ww diff on l2_local/kb5_def93 = exactly ONE line, a spurious `MOVQ (AX), AX`. The deciding site is the cgexpr N_UN(STAR) pointee classify (`ru`): the single peel left a 2-LEVEL alias pointee TY_NAMED, the ARRAY skip (#61-C — an array value IS its address, #270-1a) missed, and the scalar load pulled a[0]'s VALUE as the index base — wild pointer, SIGSEGV 139 on cs. KEN #263-POLARITY: cs is the WRONG side; ww chases and is the runtime-correct reference — cs converges on WW's asm. Single-site grant: the one `ru` computation (shared by the FN/ARRAY/TAGGED skip predicates) → type_chase_named. Raw `->under` in cgen.c 59→58. #93 CLOSES. TRAIN INVARIANT holds at the tip: cs-only; _ww binaries bit-identical to the bcd948d baseline md5s across all four commits. cs movers vs the c3 tip bounded to EXACTLY the deref-index shapes: l2_local, kb4_x93, kb5_def93. Zero ww movers. Detector pinned: kb4_xampdef STAYS 139/139 (#94, out-of-train — `&D[i]` indexed def base, a different site). Graduations (cs SEGV-139 / ww 0, BYTE-DIVERGE → 0/0 BYTE-ID): g93_l2_local (the banked rob spelling), g93_def (kb5_def93, the natural `(*p)[2]` def twin). g93_1lvl_ctl (1-level control) held 0/0 byte-id throughout. 944_alias_cgen_b5_run 28→31 rows (84 checks); 944 family green; sizelint 0. --- cmd/w6c/cgen.c | 10 ++++--- test/wcc/944_alias_cgen_b5_run.c | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index 731ea942..6cbde21f 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -4305,10 +4305,14 @@ cgexpr(Cg *c, Node *n, Local *locals) * leaves AX = p's value. The scalar load * below pulled a[0]'s VALUE and `(*p)[i]` * then dereferenced it as the index base — - * a wild pointer, SIGSEGV on both stages. */ + * a wild pointer, SIGSEGV on both stages. + * #93: the single peel left a 2-LEVEL alias + * pointee NAMED — the ARRAY skip missed and + * the scalar load fired (one spurious + * MOVQ (AX),AX, SEGV); ww chases and is the + * runtime-correct reference (#263 polarity). */ Type *rt = n->type; - Type *ru = (rt && rt->kind == TY_NAMED) - ? rt->under : rt; + Type *ru = type_chase_named(rt); if (ru && (ru->kind == TY_FN || ru->kind == TY_ARRAY)) break; diff --git a/test/wcc/944_alias_cgen_b5_run.c b/test/wcc/944_alias_cgen_b5_run.c index 58f72f01..f12be296 100644 --- a/test/wcc/944_alias_cgen_b5_run.c +++ b/test/wcc/944_alias_cgen_b5_run.c @@ -99,6 +99,16 @@ * | live-truncation seed) | 0/0 * g89_ret_named_ctl | bare NAMED struct return control — | * | held 0/0 byte-id throughout | 0/0 + * ---- c4 (#93: deref-index pointee chase, #263-polarity) -------- + * g93_l2_local | `(*p)[2]` over *arr2 (arr2=arr= | + * | [3]int) — cs emitted ONE spurious | + * | MOVQ (AX),AX (pointee ARRAY skip | + * | missed at 2 levels), SEGV 139; ww | + * | was the runtime-correct side | 0/0 + * g93_def | def twin: `(*p)[2]` over &D, D a | + * | 2-lvl alias def array (kb5_def93) | 0/0 + * g93_1lvl_ctl | 1-level pointee control — held 0/0 | + * | byte-id throughout | 0/0 * * K_RUN rows build+run BOTH drivers (cs exit==cswant, ww exit==wwwant) * and assert cstage/wwstage asm byte-id. K_RUN_NOID asserts both run @@ -618,6 +628,41 @@ static const struct row rows[] = { " };\n" " return 0;\n" "};\n", 0, 0, K_RUN, NULL }, + /* ---- c4: #93 — the N_UN(STAR) pointee classify single-peeled, + * so a 2-level alias ARRAY pointee missed the array skip (an + * array value IS its address, #270-1a) and the scalar load + * pulled a[0]'s VALUE as the index base — ONE spurious + * MOVQ (AX),AX, SIGSEGV on cs. ww chases (the runtime-correct + * reference, #263 polarity): cs converges on WW's asm. */ + { "g93_l2_local", + "package main;\n" + "type arr = [3]int;\n" + "type arr2 = arr;\n" + "export fn main() i32 = {\n" + " let a: arr2 = [1000: int, 2000: int, 3000: int];\n" + " let p: *arr2 = &a;\n" + " if ((*p)[2] != 3000) { return 1; };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL }, + { "g93_def", + "package main;\n" + "type arr0 = [3]i64;\n" + "type arr = arr0;\n" + "def D: arr = [18i64, 29i64, 40i64];\n" + "export fn main() i32 = {\n" + " let p: *arr = &D;\n" + " if ((*p)[2] != 40i64) { return 1; };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL }, + { "g93_1lvl_ctl", + "package main;\n" + "type arr = [3]int;\n" + "export fn main() i32 = {\n" + " let a: arr = [1000: int, 2000: int, 3000: int];\n" + " let p: *arr = &a;\n" + " if ((*p)[2] != 3000) { return 1; };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL }, }; static int