diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 274b7162..e3842bfc 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -12192,55 +12192,39 @@ fn slotsize(c: *cgen, typn: *node) i32 = { return 8; }; -// registerstruct — compute field offsets + total size for a struct -// type-decl, store in c.structs. Field type sizes use the same -// slotsize logic (with primitives kept at their natural width — we -// only round to 8 for stack slots, not struct interiors). +// fieldsize — slot-padded byte width of a struct field's type-AST, +// consumed by registerstruct's alignment + offset math (≥8→8 / +// ≥4→4 / ≥2→2 ladder at L1875-1877) and by the `*p OP=` deref- +// compound at cgenexpr.ww:3594. Mirror of check.ww:1053 +// `fieldslotsize` (the same dispatch on the populated tinfo); +// slotsize-template precedent at a828c03. cstage SSoT is +// `f->type->size` (cmd/w6c/cgen.c:1386, :1656, :2515, :2535); +// wwstage routes through ti.slotsize for composites since the +// stack-slot pad rules live on tinfo (#48 verdict), and through +// ti.size for the kinds whose natural size already equals their +// in-struct width. +// +// `c: *cgen` retained unused for callsite stability (slotsize / +// localloadop precedent, a828c03 / 68219a1). fn fieldsize(c: *cgen, tnode: *node) i32 = { if (tnode == nil) { return 8; }; - let k: nkind = tnode.kind; - if (k == nkind.N_TTAGGED){ return slotsize(c, tnode); }; - if (k == nkind.N_TNAME) { - let nm: str = tnode.str; - if (streq(nm, "str")) { return primtypesize("str"): i32; }; - let ps: i32 = primsize(nm); - if (ps > 0) { return ps; }; - let si: *structinfo = structlookup(c, nm); - if (si != nil) { return si.totsize; }; - // Enum: size of its storage type. Mirrors the C cgen, which - // reads Type.size off the TY_ENUM (which inherits from .sub). - let en: *enumtype = enumlookup(c, nm); - if (en != nil) { - if (en.storage != nil) { - if (en.storage.kind == nkind.N_TNAME) { - let sps: i32 = primsize(en.storage.str); - if (sps > 0) { return sps; }; - }; - }; - return 4; // default storage is i32 - }; - // Type alias to a tagged-union — recurse through aliaslookup - // so `e: ev` (where `ev = (i64 | i32)`) takes 16B in the - // containing struct rather than the 8B default. - if (c != nil) { - let aliased: *node = aliaslookup(c, nm); - if (aliased != nil) { return fieldsize(c, aliased); }; - }; - return 8; - }; - if (k == nkind.N_TPTR) { return 8; }; - if (k == nkind.N_TSLICE) { return tyslicesize(): i32; }; - if (k == nkind.N_TARRAY) { - // Same shape as slotsize's TARRAY branch. - let lenn: *node = tnode.rhs; - let elemn: *node = tnode.lhs; - let elen: i64 = 1i64; - if (lenn != nil) { - if (lenn.kind == nkind.N_INTLIT) { elen = lenn.uval: i64; }; - }; - let esz: i32 = fieldsize(c, elemn); - return (esz: i64 * elen): i32; - }; + let ti: *tinfo = tnode.type_: *tinfo; + if (ti == nil) { return 8; }; + let k: tykind = ti.kind; + if (k == tykind.TY_STRUCT) { return ti.slotsize: i32; }; + if (k == tykind.TY_ARRAY) { return ti.slotsize: i32; }; + if (k == tykind.TY_TAGGED) { return ti.size: i32; }; + if (k == tykind.TY_SLICE) { return ti.size: i32; }; + if (k == tykind.TY_PTR || k == tykind.TY_FN || + k == tykind.TY_CHAN) { return 8; }; + if (k == tykind.TY_STR) { return ti.size: i32; }; + // Primitives + TY_ENUM keep natural width inside structs + // (cstage parity: cgen.c reads f->type->size directly). TY_TUPLE + // flows here too — pre-collapse fallback was 8, the populated + // ti.size carries the natural sum; ken-thompson 2026-05-23 review: + // keep the corrected behavior, no fixtures in selfhost exercise + // a tuple-typed struct field today (995 byte-id is the gate). + if (ti.size > 0u64) { return ti.size: i32; }; return 8; }; diff --git a/selfhost/cmd/wcc/cgenutil.ww b/selfhost/cmd/wcc/cgenutil.ww index e1f46ff7..c0cf2187 100644 --- a/selfhost/cmd/wcc/cgenutil.ww +++ b/selfhost/cmd/wcc/cgenutil.ww @@ -1820,55 +1820,39 @@ fn slotsize(c: *cgen, typn: *node) i32 = { return 8; }; -// registerstruct — compute field offsets + total size for a struct -// type-decl, store in c.structs. Field type sizes use the same -// slotsize logic (with primitives kept at their natural width — we -// only round to 8 for stack slots, not struct interiors). +// fieldsize — slot-padded byte width of a struct field's type-AST, +// consumed by registerstruct's alignment + offset math (≥8→8 / +// ≥4→4 / ≥2→2 ladder at L1875-1877) and by the `*p OP=` deref- +// compound at cgenexpr.ww:3594. Mirror of check.ww:1053 +// `fieldslotsize` (the same dispatch on the populated tinfo); +// slotsize-template precedent at a828c03. cstage SSoT is +// `f->type->size` (cmd/w6c/cgen.c:1386, :1656, :2515, :2535); +// wwstage routes through ti.slotsize for composites since the +// stack-slot pad rules live on tinfo (#48 verdict), and through +// ti.size for the kinds whose natural size already equals their +// in-struct width. +// +// `c: *cgen` retained unused for callsite stability (slotsize / +// localloadop precedent, a828c03 / 68219a1). fn fieldsize(c: *cgen, tnode: *node) i32 = { if (tnode == nil) { return 8; }; - let k: nkind = tnode.kind; - if (k == nkind.N_TTAGGED){ return slotsize(c, tnode); }; - if (k == nkind.N_TNAME) { - let nm: str = tnode.str; - if (streq(nm, "str")) { return primtypesize("str"): i32; }; - let ps: i32 = primsize(nm); - if (ps > 0) { return ps; }; - let si: *structinfo = structlookup(c, nm); - if (si != nil) { return si.totsize; }; - // Enum: size of its storage type. Mirrors the C cgen, which - // reads Type.size off the TY_ENUM (which inherits from .sub). - let en: *enumtype = enumlookup(c, nm); - if (en != nil) { - if (en.storage != nil) { - if (en.storage.kind == nkind.N_TNAME) { - let sps: i32 = primsize(en.storage.str); - if (sps > 0) { return sps; }; - }; - }; - return 4; // default storage is i32 - }; - // Type alias to a tagged-union — recurse through aliaslookup - // so `e: ev` (where `ev = (i64 | i32)`) takes 16B in the - // containing struct rather than the 8B default. - if (c != nil) { - let aliased: *node = aliaslookup(c, nm); - if (aliased != nil) { return fieldsize(c, aliased); }; - }; - return 8; - }; - if (k == nkind.N_TPTR) { return 8; }; - if (k == nkind.N_TSLICE) { return tyslicesize(): i32; }; - if (k == nkind.N_TARRAY) { - // Same shape as slotsize's TARRAY branch. - let lenn: *node = tnode.rhs; - let elemn: *node = tnode.lhs; - let elen: i64 = 1i64; - if (lenn != nil) { - if (lenn.kind == nkind.N_INTLIT) { elen = lenn.uval: i64; }; - }; - let esz: i32 = fieldsize(c, elemn); - return (esz: i64 * elen): i32; - }; + let ti: *tinfo = tnode.type_: *tinfo; + if (ti == nil) { return 8; }; + let k: tykind = ti.kind; + if (k == tykind.TY_STRUCT) { return ti.slotsize: i32; }; + if (k == tykind.TY_ARRAY) { return ti.slotsize: i32; }; + if (k == tykind.TY_TAGGED) { return ti.size: i32; }; + if (k == tykind.TY_SLICE) { return ti.size: i32; }; + if (k == tykind.TY_PTR || k == tykind.TY_FN || + k == tykind.TY_CHAN) { return 8; }; + if (k == tykind.TY_STR) { return ti.size: i32; }; + // Primitives + TY_ENUM keep natural width inside structs + // (cstage parity: cgen.c reads f->type->size directly). TY_TUPLE + // flows here too — pre-collapse fallback was 8, the populated + // ti.size carries the natural sum; ken-thompson 2026-05-23 review: + // keep the corrected behavior, no fixtures in selfhost exercise + // a tuple-typed struct field today (995 byte-id is the gate). + if (ti.size > 0u64) { return ti.size: i32; }; return 8; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 500013c6..c6a3e8a4 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -12192,55 +12192,39 @@ fn slotsize(c: *cgen, typn: *node) i32 = { return 8; }; -// registerstruct — compute field offsets + total size for a struct -// type-decl, store in c.structs. Field type sizes use the same -// slotsize logic (with primitives kept at their natural width — we -// only round to 8 for stack slots, not struct interiors). +// fieldsize — slot-padded byte width of a struct field's type-AST, +// consumed by registerstruct's alignment + offset math (≥8→8 / +// ≥4→4 / ≥2→2 ladder at L1875-1877) and by the `*p OP=` deref- +// compound at cgenexpr.ww:3594. Mirror of check.ww:1053 +// `fieldslotsize` (the same dispatch on the populated tinfo); +// slotsize-template precedent at a828c03. cstage SSoT is +// `f->type->size` (cmd/w6c/cgen.c:1386, :1656, :2515, :2535); +// wwstage routes through ti.slotsize for composites since the +// stack-slot pad rules live on tinfo (#48 verdict), and through +// ti.size for the kinds whose natural size already equals their +// in-struct width. +// +// `c: *cgen` retained unused for callsite stability (slotsize / +// localloadop precedent, a828c03 / 68219a1). fn fieldsize(c: *cgen, tnode: *node) i32 = { if (tnode == nil) { return 8; }; - let k: nkind = tnode.kind; - if (k == nkind.N_TTAGGED){ return slotsize(c, tnode); }; - if (k == nkind.N_TNAME) { - let nm: str = tnode.str; - if (streq(nm, "str")) { return primtypesize("str"): i32; }; - let ps: i32 = primsize(nm); - if (ps > 0) { return ps; }; - let si: *structinfo = structlookup(c, nm); - if (si != nil) { return si.totsize; }; - // Enum: size of its storage type. Mirrors the C cgen, which - // reads Type.size off the TY_ENUM (which inherits from .sub). - let en: *enumtype = enumlookup(c, nm); - if (en != nil) { - if (en.storage != nil) { - if (en.storage.kind == nkind.N_TNAME) { - let sps: i32 = primsize(en.storage.str); - if (sps > 0) { return sps; }; - }; - }; - return 4; // default storage is i32 - }; - // Type alias to a tagged-union — recurse through aliaslookup - // so `e: ev` (where `ev = (i64 | i32)`) takes 16B in the - // containing struct rather than the 8B default. - if (c != nil) { - let aliased: *node = aliaslookup(c, nm); - if (aliased != nil) { return fieldsize(c, aliased); }; - }; - return 8; - }; - if (k == nkind.N_TPTR) { return 8; }; - if (k == nkind.N_TSLICE) { return tyslicesize(): i32; }; - if (k == nkind.N_TARRAY) { - // Same shape as slotsize's TARRAY branch. - let lenn: *node = tnode.rhs; - let elemn: *node = tnode.lhs; - let elen: i64 = 1i64; - if (lenn != nil) { - if (lenn.kind == nkind.N_INTLIT) { elen = lenn.uval: i64; }; - }; - let esz: i32 = fieldsize(c, elemn); - return (esz: i64 * elen): i32; - }; + let ti: *tinfo = tnode.type_: *tinfo; + if (ti == nil) { return 8; }; + let k: tykind = ti.kind; + if (k == tykind.TY_STRUCT) { return ti.slotsize: i32; }; + if (k == tykind.TY_ARRAY) { return ti.slotsize: i32; }; + if (k == tykind.TY_TAGGED) { return ti.size: i32; }; + if (k == tykind.TY_SLICE) { return ti.size: i32; }; + if (k == tykind.TY_PTR || k == tykind.TY_FN || + k == tykind.TY_CHAN) { return 8; }; + if (k == tykind.TY_STR) { return ti.size: i32; }; + // Primitives + TY_ENUM keep natural width inside structs + // (cstage parity: cgen.c reads f->type->size directly). TY_TUPLE + // flows here too — pre-collapse fallback was 8, the populated + // ti.size carries the natural sum; ken-thompson 2026-05-23 review: + // keep the corrected behavior, no fixtures in selfhost exercise + // a tuple-typed struct field today (995 byte-id is the gate). + if (ti.size > 0u64) { return ti.size: i32; }; return 8; };