From 38d6eb667c030443a2f9443f5c23793b19043d61 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 23 May 2026 17:04:31 +0900 Subject: [PATCH] selfhost/cmd/wcc: inline N_INDEX elem tinfo at 3 tagged push/index sites (#60) pushargsrev and cgindex re-derived an index element's type via indexvaluetnode (a base->TPTR/SLICE/ARRAY .lhs AST walk). The checker stamps the element type on the N_INDEX node itself (indexresult, check.ww:1710; N_INDEX is in the asserttyped gate), so read n.type_ directly at the 3 sites that only need tagged-ness + element size/sign: cgenutil pushargsrev L178/490: pass the N_INDEX arg to istaggedtype/ slotsize (arg.type_ is the element tinfo). cgenexpr cgindex L726: esz = n.type_.size, signed = typeissigned(n.type_). Polarity DOWN per rule 10: cstage has no indexvaluetnode -- it reads base->type->sub->size directly (cmd/w6c/cgen.c:2070-2071, :3518). The new path reads element natural size (tinfo.size == primsize: rune=4, u8=1, str=16, slice=24), matching cstage; it also retires two latent elemsizeofc divergences (elemsizeofc returned slotsize N*8 for *[N]i64 / 2D-array elements where cstage uses sub->size=8) -- those shapes are absent from self-compile, so byte-id stays green. indexvaluetnode is NOT deleted: its remaining callers at cgenexpr L3720/3729 feed cgwidentaggedstore -> resolvetagged -> resolvetype, still node-keyed (nil for non-N_TNAME). Deleting it waits on the resolvetagged -> tinfo migration (#11). make test 133/133 (byte-id 990-997 green, independently re-confirmed on quiescent tree). --- selfhost/cmd/w6c/main.combined.ww | 49 ++++++++++++++++------------ selfhost/cmd/wcc/cgenexpr.ww | 13 +++++--- selfhost/cmd/wcc/cgenutil.ww | 36 ++++++++++---------- selfhost/cmd/wwdump/main.combined.ww | 49 ++++++++++++++++------------ 4 files changed, 84 insertions(+), 63 deletions(-) diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index cdd1e12d..97226fcc 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -10615,13 +10615,15 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = { // Without this gate the widening scalar branch // hardcodes the param's first-variant tag and // the callee reads a fixed arm on garbage. + // #60: arg.type_ is the checker-stamped element + // tinfo (check.ww indexresult); istaggedtype/ + // slotsize read .type_, so feed the N_INDEX node + // directly. cstage reads the element via + // base->type->sub (cmd/w6c/cgen.c:3518). if (arg.kind == nkind.N_INDEX) { - let etn: *node = indexvaluetnode(c, arg); - if (etn != nil) { - if (istaggedtype(c, etn)) { - if (slotsize(c, etn) == slotsize(c, ptype)) { - aistagged = true; - }; + if (istaggedtype(c, arg)) { + if (slotsize(c, arg) == slotsize(c, ptype)) { + aistagged = true; }; }; }; @@ -10926,18 +10928,18 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = { }; // #12: N_INDEX of a sum-typed slice element. cgindex above left // the tagged-CALL ABI in AX/DX/CX/R8; the bare PUSHQ AX below - // would only carry the tag word and drop the payload. + // would only carry the tag word and drop the payload. #60: + // arg.type_ is the element tinfo (istaggedtype/slotsize read + // .type_) — feed the N_INDEX node directly, dropping the + // indexvaluetnode walk. if (arg.kind == nkind.N_INDEX) { - let etn: *node = indexvaluetnode(c, arg); - if (etn != nil) { - if (istaggedtype(c, etn)) { - let isz: i32 = slotsize(c, etn); - if (isz > 24) { emitline("\tPUSHQ\tR8\n"); }; - if (isz > 16) { emitline("\tPUSHQ\tCX\n"); }; - if (isz > 8) { emitline("\tPUSHQ\tDX\n"); }; - emitline("\tPUSHQ\tAX\n"); - return rest + isz / 8; - }; + if (istaggedtype(c, arg)) { + let isz: i32 = slotsize(c, arg); + if (isz > 24) { emitline("\tPUSHQ\tR8\n"); }; + if (isz > 16) { emitline("\tPUSHQ\tCX\n"); }; + if (isz > 8) { emitline("\tPUSHQ\tDX\n"); }; + emitline("\tPUSHQ\tAX\n"); + return rest + isz / 8; }; }; emitline("\tPUSHQ\tAX\n"); @@ -14608,10 +14610,15 @@ fn cgindex(c: *cgen, n: *node) void = { } else { if (base.kind == nkind.N_DOT) { esz = indexbaseesz(c, base); } else { if (base.kind == nkind.N_INDEX) { - let bt: *node = indexvaluetnode(c, base); - if (bt != nil) { - esz = elemsizeofc(c, bt); - signed_elem = elemissignedc(c, bt); + // #60: chained `names[i][k]` — n.type_ is the checker- + // stamped outer element tinfo (indexresult over the inner + // index's value type). cstage reads base->type->sub->size + // for esz (cmd/w6c/cgen.c:2070-2071). Drops the + // indexvaluetnode walk. + let et: *tinfo = n.type_: *tinfo; + if (et != nil) { + esz = et.size: i32; + signed_elem = typeissigned(et); }; };};}; }; diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index dcd508c2..15674293 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -723,10 +723,15 @@ fn cgindex(c: *cgen, n: *node) void = { } else { if (base.kind == nkind.N_DOT) { esz = indexbaseesz(c, base); } else { if (base.kind == nkind.N_INDEX) { - let bt: *node = indexvaluetnode(c, base); - if (bt != nil) { - esz = elemsizeofc(c, bt); - signed_elem = elemissignedc(c, bt); + // #60: chained `names[i][k]` — n.type_ is the checker- + // stamped outer element tinfo (indexresult over the inner + // index's value type). cstage reads base->type->sub->size + // for esz (cmd/w6c/cgen.c:2070-2071). Drops the + // indexvaluetnode walk. + let et: *tinfo = n.type_: *tinfo; + if (et != nil) { + esz = et.size: i32; + signed_elem = typeissigned(et); }; };};}; }; diff --git a/selfhost/cmd/wcc/cgenutil.ww b/selfhost/cmd/wcc/cgenutil.ww index 56e5ef63..71866849 100644 --- a/selfhost/cmd/wcc/cgenutil.ww +++ b/selfhost/cmd/wcc/cgenutil.ww @@ -174,13 +174,15 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = { // Without this gate the widening scalar branch // hardcodes the param's first-variant tag and // the callee reads a fixed arm on garbage. + // #60: arg.type_ is the checker-stamped element + // tinfo (check.ww indexresult); istaggedtype/ + // slotsize read .type_, so feed the N_INDEX node + // directly. cstage reads the element via + // base->type->sub (cmd/w6c/cgen.c:3518). if (arg.kind == nkind.N_INDEX) { - let etn: *node = indexvaluetnode(c, arg); - if (etn != nil) { - if (istaggedtype(c, etn)) { - if (slotsize(c, etn) == slotsize(c, ptype)) { - aistagged = true; - }; + if (istaggedtype(c, arg)) { + if (slotsize(c, arg) == slotsize(c, ptype)) { + aistagged = true; }; }; }; @@ -485,18 +487,18 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = { }; // #12: N_INDEX of a sum-typed slice element. cgindex above left // the tagged-CALL ABI in AX/DX/CX/R8; the bare PUSHQ AX below - // would only carry the tag word and drop the payload. + // would only carry the tag word and drop the payload. #60: + // arg.type_ is the element tinfo (istaggedtype/slotsize read + // .type_) — feed the N_INDEX node directly, dropping the + // indexvaluetnode walk. if (arg.kind == nkind.N_INDEX) { - let etn: *node = indexvaluetnode(c, arg); - if (etn != nil) { - if (istaggedtype(c, etn)) { - let isz: i32 = slotsize(c, etn); - if (isz > 24) { emitline("\tPUSHQ\tR8\n"); }; - if (isz > 16) { emitline("\tPUSHQ\tCX\n"); }; - if (isz > 8) { emitline("\tPUSHQ\tDX\n"); }; - emitline("\tPUSHQ\tAX\n"); - return rest + isz / 8; - }; + if (istaggedtype(c, arg)) { + let isz: i32 = slotsize(c, arg); + if (isz > 24) { emitline("\tPUSHQ\tR8\n"); }; + if (isz > 16) { emitline("\tPUSHQ\tCX\n"); }; + if (isz > 8) { emitline("\tPUSHQ\tDX\n"); }; + emitline("\tPUSHQ\tAX\n"); + return rest + isz / 8; }; }; emitline("\tPUSHQ\tAX\n"); diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 44829cf5..dd994544 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -10615,13 +10615,15 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = { // Without this gate the widening scalar branch // hardcodes the param's first-variant tag and // the callee reads a fixed arm on garbage. + // #60: arg.type_ is the checker-stamped element + // tinfo (check.ww indexresult); istaggedtype/ + // slotsize read .type_, so feed the N_INDEX node + // directly. cstage reads the element via + // base->type->sub (cmd/w6c/cgen.c:3518). if (arg.kind == nkind.N_INDEX) { - let etn: *node = indexvaluetnode(c, arg); - if (etn != nil) { - if (istaggedtype(c, etn)) { - if (slotsize(c, etn) == slotsize(c, ptype)) { - aistagged = true; - }; + if (istaggedtype(c, arg)) { + if (slotsize(c, arg) == slotsize(c, ptype)) { + aistagged = true; }; }; }; @@ -10926,18 +10928,18 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node) i32 = { }; // #12: N_INDEX of a sum-typed slice element. cgindex above left // the tagged-CALL ABI in AX/DX/CX/R8; the bare PUSHQ AX below - // would only carry the tag word and drop the payload. + // would only carry the tag word and drop the payload. #60: + // arg.type_ is the element tinfo (istaggedtype/slotsize read + // .type_) — feed the N_INDEX node directly, dropping the + // indexvaluetnode walk. if (arg.kind == nkind.N_INDEX) { - let etn: *node = indexvaluetnode(c, arg); - if (etn != nil) { - if (istaggedtype(c, etn)) { - let isz: i32 = slotsize(c, etn); - if (isz > 24) { emitline("\tPUSHQ\tR8\n"); }; - if (isz > 16) { emitline("\tPUSHQ\tCX\n"); }; - if (isz > 8) { emitline("\tPUSHQ\tDX\n"); }; - emitline("\tPUSHQ\tAX\n"); - return rest + isz / 8; - }; + if (istaggedtype(c, arg)) { + let isz: i32 = slotsize(c, arg); + if (isz > 24) { emitline("\tPUSHQ\tR8\n"); }; + if (isz > 16) { emitline("\tPUSHQ\tCX\n"); }; + if (isz > 8) { emitline("\tPUSHQ\tDX\n"); }; + emitline("\tPUSHQ\tAX\n"); + return rest + isz / 8; }; }; emitline("\tPUSHQ\tAX\n"); @@ -14608,10 +14610,15 @@ fn cgindex(c: *cgen, n: *node) void = { } else { if (base.kind == nkind.N_DOT) { esz = indexbaseesz(c, base); } else { if (base.kind == nkind.N_INDEX) { - let bt: *node = indexvaluetnode(c, base); - if (bt != nil) { - esz = elemsizeofc(c, bt); - signed_elem = elemissignedc(c, bt); + // #60: chained `names[i][k]` — n.type_ is the checker- + // stamped outer element tinfo (indexresult over the inner + // index's value type). cstage reads base->type->sub->size + // for esz (cmd/w6c/cgen.c:2070-2071). Drops the + // indexvaluetnode walk. + let et: *tinfo = n.type_: *tinfo; + if (et != nil) { + esz = et.size: i32; + signed_elem = typeissigned(et); }; };};}; };