w6c_ww: emit a bare str/slice global zero-header once, keyed on type kind (fix #10 part b)
Post-#1, size(str) == size(slice) == 24. emitletdataw's str arm (~cgen.ww:2074) and slice arm (~cgen.ww:2139) were sequential `if`s gated on SIZE alone, so a bare 24-byte global matched BOTH and BOTH fired the no-rhs zero fallback — two `DATAW main.g` rows. cstage discriminates on type kind (let_isstr/let_isslice, cgen.c:1026/1036) and emits one; the link+run is correct either way, so the divergence was byte-id-visible only. Gate the two arms on the declared type kind via the new letdeclkind helper (d.lhs.type_, TY_NAMED-peeled — the resolvewalk-stamped type-expression node), mutually exclusive: a 24B global now hits one arm. Falls to the str arm when unstamped, where the zero-init bytes are identical, so byte-id holds for that case too. cstage already correct — no change. New test 686 (5 runtime rows + 5 byte-id rows) pins single-emit + cs==ww.
This commit is contained in:
@@ -32923,6 +32923,24 @@ fn letvarisslice(c: *cgen, name: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letdeclkind — unwrapped (TY_NAMED-peeled) kind of the let decl's
|
||||
// declared type, read off the checker-stamped type-expression node
|
||||
// (d.lhs.type_; resolvewalk stamps N_TNAME/N_TSLICE/… at check.ww:566).
|
||||
// Mirrors cstage type_unwrap(d->type)->kind, the basis of let_isstr/
|
||||
// let_isslice (cgen.c:1026/1036). Post-#1 str and slice share a 24B
|
||||
// header, so emitletdataw's size-only str and slice arms BOTH fired for
|
||||
// a bare 24B global and double-emitted its DATAW (#10 part b); these two
|
||||
// arms now branch on kind, not size. nil-safe: returns TY_VOID when
|
||||
// unstamped so a 24B global still falls to the str arm (zero-init bytes
|
||||
// are identical either way, so byte-id holds for the unstamped case).
|
||||
fn letdeclkind(d: *node) tykind = {
|
||||
if (d.lhs == nil) { return tykind.TY_VOID; };
|
||||
let ti: *tinfo = d.lhs.type_: *tinfo;
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti == nil) { return tykind.TY_VOID; };
|
||||
return ti.kind;
|
||||
};
|
||||
|
||||
// letvarisfloat — slot size for a named float global, or 0 if not
|
||||
// a float-typed let. Walks aliases so the byte-identity contract
|
||||
// matches C cgen's `let_isfloat` (which resolves Type kinds).
|
||||
@@ -33935,7 +33953,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
emitline("\"\n");
|
||||
};
|
||||
};
|
||||
if (sz == primtypesize("str"): i32 && !issg) {
|
||||
if (sz == primtypesize("str"): i32 && !issg && letdeclkind(d) != tykind.TY_SLICE) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
if (r.kind != nkind.N_CAST) { break; };
|
||||
@@ -34000,7 +34018,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (sz == tyslicesize(): i32 && !issg) {
|
||||
if (sz == tyslicesize(): i32 && !issg && letdeclkind(d) == tykind.TY_SLICE) {
|
||||
// Slice: zero-init only (no slice-literal
|
||||
// syntax to honour). Any rhs other than
|
||||
// `nil` is skipped → undefined symbol at
|
||||
|
||||
@@ -1059,6 +1059,24 @@ fn letvarisslice(c: *cgen, name: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letdeclkind — unwrapped (TY_NAMED-peeled) kind of the let decl's
|
||||
// declared type, read off the checker-stamped type-expression node
|
||||
// (d.lhs.type_; resolvewalk stamps N_TNAME/N_TSLICE/… at check.ww:566).
|
||||
// Mirrors cstage type_unwrap(d->type)->kind, the basis of let_isstr/
|
||||
// let_isslice (cgen.c:1026/1036). Post-#1 str and slice share a 24B
|
||||
// header, so emitletdataw's size-only str and slice arms BOTH fired for
|
||||
// a bare 24B global and double-emitted its DATAW (#10 part b); these two
|
||||
// arms now branch on kind, not size. nil-safe: returns TY_VOID when
|
||||
// unstamped so a 24B global still falls to the str arm (zero-init bytes
|
||||
// are identical either way, so byte-id holds for the unstamped case).
|
||||
fn letdeclkind(d: *node) tykind = {
|
||||
if (d.lhs == nil) { return tykind.TY_VOID; };
|
||||
let ti: *tinfo = d.lhs.type_: *tinfo;
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti == nil) { return tykind.TY_VOID; };
|
||||
return ti.kind;
|
||||
};
|
||||
|
||||
// letvarisfloat — slot size for a named float global, or 0 if not
|
||||
// a float-typed let. Walks aliases so the byte-identity contract
|
||||
// matches C cgen's `let_isfloat` (which resolves Type kinds).
|
||||
@@ -2071,7 +2089,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
emitline("\"\n");
|
||||
};
|
||||
};
|
||||
if (sz == primtypesize("str"): i32 && !issg) {
|
||||
if (sz == primtypesize("str"): i32 && !issg && letdeclkind(d) != tykind.TY_SLICE) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
if (r.kind != nkind.N_CAST) { break; };
|
||||
@@ -2136,7 +2154,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (sz == tyslicesize(): i32 && !issg) {
|
||||
if (sz == tyslicesize(): i32 && !issg && letdeclkind(d) == tykind.TY_SLICE) {
|
||||
// Slice: zero-init only (no slice-literal
|
||||
// syntax to honour). Any rhs other than
|
||||
// `nil` is skipped → undefined symbol at
|
||||
|
||||
@@ -32923,6 +32923,24 @@ fn letvarisslice(c: *cgen, name: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letdeclkind — unwrapped (TY_NAMED-peeled) kind of the let decl's
|
||||
// declared type, read off the checker-stamped type-expression node
|
||||
// (d.lhs.type_; resolvewalk stamps N_TNAME/N_TSLICE/… at check.ww:566).
|
||||
// Mirrors cstage type_unwrap(d->type)->kind, the basis of let_isstr/
|
||||
// let_isslice (cgen.c:1026/1036). Post-#1 str and slice share a 24B
|
||||
// header, so emitletdataw's size-only str and slice arms BOTH fired for
|
||||
// a bare 24B global and double-emitted its DATAW (#10 part b); these two
|
||||
// arms now branch on kind, not size. nil-safe: returns TY_VOID when
|
||||
// unstamped so a 24B global still falls to the str arm (zero-init bytes
|
||||
// are identical either way, so byte-id holds for the unstamped case).
|
||||
fn letdeclkind(d: *node) tykind = {
|
||||
if (d.lhs == nil) { return tykind.TY_VOID; };
|
||||
let ti: *tinfo = d.lhs.type_: *tinfo;
|
||||
for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; };
|
||||
if (ti == nil) { return tykind.TY_VOID; };
|
||||
return ti.kind;
|
||||
};
|
||||
|
||||
// letvarisfloat — slot size for a named float global, or 0 if not
|
||||
// a float-typed let. Walks aliases so the byte-identity contract
|
||||
// matches C cgen's `let_isfloat` (which resolves Type kinds).
|
||||
@@ -33935,7 +33953,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
emitline("\"\n");
|
||||
};
|
||||
};
|
||||
if (sz == primtypesize("str"): i32 && !issg) {
|
||||
if (sz == primtypesize("str"): i32 && !issg && letdeclkind(d) != tykind.TY_SLICE) {
|
||||
let r: *node = d.rhs;
|
||||
for (r != nil) {
|
||||
if (r.kind != nkind.N_CAST) { break; };
|
||||
@@ -34000,7 +34018,7 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (sz == tyslicesize(): i32 && !issg) {
|
||||
if (sz == tyslicesize(): i32 && !issg && letdeclkind(d) == tykind.TY_SLICE) {
|
||||
// Slice: zero-init only (no slice-literal
|
||||
// syntax to honour). Any rhs other than
|
||||
// `nil` is skipped → undefined symbol at
|
||||
|
||||
Reference in New Issue
Block a user