cgen: B6-c3 addr-of/field-walk/index spine single peels fold into type_chase_named — 14 lines

The exact B6-c3 set (rob b6 spec §2, numbering at 4cac1cb): :3949
(&ident classify ou), :4006 (&mod.G leaf lu), :4124/:4128 (&p.f
ptr-field fallback bu/inner), :5029/:5035/:5052 (indexed-elem
struct-field STORE elemu/inner/bu), :5937 (assign-region esub peel),
:10953/:10956 (chained N_DOT ptr lu/inner), :11046/:11052/:11067
(indexed-elem struct-field READ twin), :11285 (index-region esub peel
— gates key the chased esubu exactly as the ident arm, per the EYES
condition). Raw `->under` in cgen.c 41→27.

RE-ATTRIBUTION (ken c3-STOP addendum, adjudicated on his independent
scratch build): kb6_idxf and kb6_ampf did NOT land on the oracle's
predicted post-states — and the train direction is CORRECT anyway.
Bit-proven mechanism: post-chase cs_alias asm == ww_PLAIN (the
byte-id-gate-proven canonical dedicated shape) for BOTH rows; it is
WWSTAGE that is alias-blind at these two sites (ww_alias != ww_plain
— its indexed-elem struct-field store/read gates and the &p.f
ptr-field fallback don't fire on alias bases and fall to generic-but-
runtime-correct routes). Converging cs onto ww_alias would re-blind
cs — canonical is the convergence target. ampf's pre-c3 byte-id was
both-stages-on-the-generic-route identity (gate-blind, #263-class),
NOT M5 latency — oracle self-correction banked. Both rows pinned
K_RUN_NOID (cs-0 + ww-0, byte-id waived) + plain-control rows pin the
convergence target; they graduate to full byte-id when the filed
ww-side W2 fold (task #102) lands (ww gate chase; kw1/#100/W1 precedent; zero
metric-1 content). chdot/esub byte-NEUTRAL bound held.

TRAIN INVARIANT: cs-only; w6c_ww/ww_ww bit-identical to the 4cac1cb
baselines (b6bddc8e…/4e9ca874…). cs movers c2→c3 bounded to exactly
{kb6_idxf, kb6_ampf} — the named c3 family; both run-cells ok/0 held;
rest of corpus + five mains byte-NEUTRAL; detectors unmoved; 989
ratchet zero flips.

944_alias_cgen_b6_run grows 8→14 rows, 22→38 checks: idxf_2lvl/
ampf_2lvl NOID pins + idxf_plain_ctl/ampf_plain_ctl canonical-shape
pins + chdot_2lvl/esub_2lvl controls. All 944-family suites green;
sizelint 0.
This commit is contained in:
2026-06-06 04:01:24 +09:00
parent 9659a0dfbe
commit 7a85210b13
2 changed files with 123 additions and 30 deletions

View File

@@ -3945,8 +3945,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
if (opnd && opnd->kind == N_IDENT) {
int off = localfind(locals, opnd->str);
Type *ot = opnd->type;
Type *ou = (ot && ot->kind == TY_NAMED)
? ot->under : ot;
Type *ou = type_chase_named(ot);
if (off != 0) {
ins2(c, A_LEAQ, amem(D_BP, off), areg(D_AX));
} else if (ou && ou->kind == TY_FN) {
@@ -4002,8 +4001,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
&& (opnd->lhs->type == NULL
|| opnd->lhs->type == ty_err)) {
Type *lt = opnd->type;
Type *lu = (lt && lt->kind == TY_NAMED)
? lt->under : lt;
Type *lu = type_chase_named(lt);
if (lu && lu->kind == TY_FN)
ins2(c, A_LEAQ,
mafn(c, opnd->str,
@@ -4120,12 +4118,9 @@ cgexpr(Cg *c, Node *n, Local *locals)
if (!amped && opnd->lhs
&& opnd->lhs->kind == N_IDENT) {
Type *bt = opnd->lhs->type;
Type *bu = (bt && bt->kind == TY_NAMED)
? bt->under : bt;
Type *bu = type_chase_named(bt);
if (bu && bu->kind == TY_PTR && bu->sub) {
Type *inner = bu->sub;
if (inner->kind == TY_NAMED)
inner = inner->under;
Type *inner = type_chase_named(bu->sub);
if (inner && inner->kind == TY_STRUCT) {
for (Tfield *f = inner->fields;
f; f = f->next) {
@@ -5025,14 +5020,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
Node *idx = n->lhs->lhs->rhs;
if (idxbase && idxbase->kind == N_IDENT && idx) {
Type *elemt = n->lhs->lhs->type;
Type *elemu = (elemt && elemt->kind == TY_NAMED)
? elemt->under : elemt;
Type *elemu = type_chase_named(elemt);
Type *struct_t = NULL;
int viaptr = 0;
if (elemu && elemu->kind == TY_PTR) {
Type *inner = elemu->sub;
if (inner && inner->kind == TY_NAMED)
inner = inner->under;
Type *inner = type_chase_named(elemu->sub);
if (inner && inner->kind == TY_STRUCT) {
struct_t = inner;
viaptr = 1;
@@ -5048,8 +5040,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
n->lhs->str) == 0)
{ f = fl; break; }
Type *bt = idxbase->type;
Type *bu = (bt && bt->kind == TY_NAMED)
? bt->under : bt;
Type *bu = type_chase_named(bt);
int is_arr = bu && bu->kind == TY_ARRAY;
int is_sl = bu && bu->kind == TY_SLICE;
int is_ptr = bu && bu->kind == TY_PTR;
@@ -5933,8 +5924,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
int elem_is_str = eff && eff->sub && type_isstr(eff->sub);
int elem_is_slice = eff && eff->sub && type_isslice(eff->sub);
Type *esub = eff ? eff->sub : NULL;
Type *esubu = (esub && esub->kind == TY_NAMED)
? esub->under : esub;
Type *esubu = type_chase_named(esub);
int elem_tagged = esubu && esubu->kind == TY_TAGGED;
/* Tagged-union element: route widening through a
* scratch slot, then copy slot bytes to &arr[i].
@@ -10940,10 +10930,9 @@ cgexpr(Cg *c, Node *n, Local *locals)
* field. (Surfaced building ww-w6l.) */
if (n->lhs->kind == N_DOT) {
Type *lt = n->lhs->type;
Type *lu = (lt && lt->kind == TY_NAMED) ? lt->under : lt;
Type *lu = type_chase_named(lt);
if (lu && lu->kind == TY_PTR && lu->sub) {
Type *inner = lu->sub;
if (inner->kind == TY_NAMED) inner = inner->under;
Type *inner = type_chase_named(lu->sub);
if (inner && inner->kind == TY_STRUCT) {
for (Tfield *f = inner->fields; f; f = f->next) {
if (strcmp(f->name, n->str) != 0) continue;
@@ -11032,14 +11021,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
&& n->lhs->lhs->kind == N_IDENT) {
Node *idxbase = n->lhs->lhs;
Type *elemt = n->lhs->type;
Type *elemu = (elemt && elemt->kind == TY_NAMED)
? elemt->under : elemt;
Type *elemu = type_chase_named(elemt);
Type *struct_t = NULL;
int viaptr = 0;
if (elemu && elemu->kind == TY_PTR) {
Type *inner = elemu->sub;
if (inner && inner->kind == TY_NAMED)
inner = inner->under;
Type *inner = type_chase_named(elemu->sub);
if (inner && inner->kind == TY_STRUCT) {
struct_t = inner;
viaptr = 1;
@@ -11053,8 +11039,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
if (strcmp(fl->name, n->str) == 0)
{ f = fl; break; }
Type *bt = idxbase->type;
Type *bu = (bt && bt->kind == TY_NAMED)
? bt->under : bt;
Type *bu = type_chase_named(bt);
int is_arr = bu && bu->kind == TY_ARRAY;
int is_sl = bu && bu->kind == TY_SLICE;
int is_ptr = bu && bu->kind == TY_PTR;
@@ -11271,8 +11256,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
int esz = 1;
if (eff && eff->sub) esz = (int)eff->sub->size;
Type *esub = eff ? eff->sub : NULL;
Type *esubu = (esub && esub->kind == TY_NAMED)
? esub->under : esub;
Type *esubu = type_chase_named(esub);
int elem_tagged = esubu && esubu->kind == TY_TAGGED;
if (n->lhs->kind == N_IDENT && u) {

View File

@@ -55,6 +55,35 @@
* checker-blocked upstream (#86/#99) — the pin is the b5 |
* suite's tuparg_cast_bound99 two-key cells, which must |
* not move.) |
* ---- c3 (addr-of/field-walk/index spine: :3949 :4006 ---------
* :4124/:4128 :5029/:5035/:5052 :5937 :10953/:10956 -----
* :11046/:11052/:11067 :11285, numbering at 4cac1cb) ----
* idxf_2lvl / | kb6_idxf (indexed-elem struct field |
* ampf_2lvl | write+read) / kb6_ampf (&p.b over |
* | alias ptr): the c3 chase moved cs |
* | onto the PLAIN-canonical dedicated |
* | shape (cs_alias == ww_PLAIN, bit- |
* | proven, ken c3-STOP addendum) — but |
* | WWSTAGE is the alias-blind side at |
* | these two sites (ww_alias != |
* | ww_plain, generic-but-correct |
* | routes). Two-cell NOID pins; byte-id |
* | graduates with the filed ww-side W2 |
* | fold, task #102 (ww indexed-elem |
* | field gates + &p.f fallback don't |
* | fire on alias bases). ampf's pre-c3 |
* | byte-id was both-on-generic |
* | identity, not latency (oracle |
* | self-correction) | 0/0
* idxf_plain_ctl / | plain no-alias twins — pin the |
* ampf_plain_ctl | canonical dedicated shape byte-id |
* | BOTH stages (the convergence target |
* | the NOID rows graduate onto) | 0/0
* chdot_2lvl | kb6_chdot: chained dot over alias |
* | hops — latent control | 0/0
* esub_2lvl | kb6_esub: [3]my32b narrow-elem index |
* | (#61/#101-kin at the INDEX sites) — |
* | latent control | 0/0
*
* K_RUN rows build+run BOTH drivers (cs exit==cswant, ww exit==wwwant)
* and assert cstage/wwstage asm byte-id. K_BUILDERR rows must FAIL
@@ -97,6 +126,8 @@ slurp_eq(const char *a, const char *b)
#define K_RUN 0 /* build+run BOTH, exits==wants, + byte-id */
#define K_BUILDERR 1 /* build FAILS with experr on BOTH drivers;
* experr_ww overrides the ww-side text */
#define K_RUN_NOID 2 /* build+run BOTH, exits==wants, byte-id
* SKIPPED — cite the blocking task */
struct row { const char *label; const char *src;
int cswant; int wwwant; int kind;
@@ -229,6 +260,84 @@ static const struct row rows[] = {
" if (g(a) != 5) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
/* ---- c3: addr-of/field-walk/index spine */
/* The c3 chase put cs on the PLAIN-canonical dedicated shape
* (cs_alias == ww_PLAIN, bit-proven — ken c3-STOP addendum);
* WWSTAGE is the alias-blind side here: its indexed-elem
* struct-field store/read gates don't fire on alias bases and
* fall to a generic-but-correct route. Byte-id waived until the
* filed ww-side W2 fold (task #102) lands; idxf_plain_ctl pins the
* convergence target. */
{ "idxf_2lvl",
"package main;\n"
"type el0 = struct { a: i64, b: i64 };\n"
"type el = el0;\n"
"export fn main() i32 = {\n"
" let xs: [2]el;\n"
" xs[0].a = 1; xs[0].b = 2;\n"
" xs[1].a = 3; xs[1].b = 4;\n"
" if (xs[1].b != 4 || xs[0].b != 2) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN_NOID, NULL, NULL }, /* byte-id: task #102 */
{ "idxf_plain_ctl",
"package main;\n"
"type el0 = struct { a: i64, b: i64 };\n"
"export fn main() i32 = {\n"
" let xs: [2]el0;\n"
" xs[0].a = 1; xs[0].b = 2;\n"
" xs[1].a = 3; xs[1].b = 4;\n"
" if (xs[1].b != 4 || xs[0].b != 2) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
/* &p.b ptr-field fallback twin of the same re-attribution: the
* pre-c3 byte-id here was BOTH stages on the generic spine
* (gate-blind identity, not M5 latency — oracle self-correction
* banked in ken's c3-STOP addendum). */
{ "ampf_2lvl",
"package main;\n"
"type st0 = struct { a: i64, b: i64 };\n"
"type st = st0;\n"
"export fn main() i32 = {\n"
" let x: st; x.a = 1; x.b = 2;\n"
" let p: *st = &x;\n"
" let q: *i64 = &p.b;\n"
" *q = 9;\n"
" if (x.b != 9) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN_NOID, NULL, NULL }, /* byte-id: task #102 */
{ "ampf_plain_ctl",
"package main;\n"
"type st0 = struct { a: i64, b: i64 };\n"
"export fn main() i32 = {\n"
" let x: st0; x.a = 1; x.b = 2;\n"
" let p: *st0 = &x;\n"
" let q: *i64 = &p.b;\n"
" *q = 9;\n"
" if (x.b != 9) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
{ "chdot_2lvl",
"package main;\n"
"type in0 = struct { v: i64 };\n"
"type in1 = in0;\n"
"type out0 = struct { inner: in1, n: i64 };\n"
"type out1 = out0;\n"
"export fn main() i32 = {\n"
" let s: out1; s.inner.v = 7; s.n = 3;\n"
" let p: *out1 = &s;\n"
" if (p.inner.v != 7) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
{ "esub_2lvl",
"package main;\n"
"type my32 = u32;\n"
"type my32b = my32;\n"
"export fn main() i32 = {\n"
" let xs: [3]my32b;\n"
" xs[0] = 5; xs[1] = 6; xs[2] = 7;\n"
" if (xs[0]: i64 + xs[1]: i64 + xs[2]: i64 != 18) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
};
static int