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).
This commit is contained in:
2026-05-23 17:04:31 +09:00
parent 827a05e548
commit 38d6eb667c
4 changed files with 84 additions and 63 deletions

View File

@@ -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);
};
};};};
};

View File

@@ -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);
};
};};};
};

View File

@@ -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");

View File

@@ -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);
};
};};};
};