From 324df92e1d2df1675be1fdffbcf5f5ce0a1fd973 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 25 May 2026 00:49:47 +0900 Subject: [PATCH] cgen: unify cstage slice-let onto shared 3-word store path Delete the vestigial inline slice-let builder in N_LET; a `let s: []T = buf[lo:hi]` now routes through cgexpr's N_SLICE path plus the generic 3-word store -- exactly as cstage's own str-let and the wwstage already do. cap is unchanged (still hi-lo); the cap = base_cap-lo fix is the following commit. The builder duplicated cgexpr's N_SLICE base/hi dispatch and was a strict subset of it, so for local bases the deletion is value-neutral (ptr=base+lo, len=hi-lo, cap=hi-lo); only the routing bytes move, aligning cstage down to the leaner wwstage and closing find-4 (rule-10). Verified byte-identical cs==ww across the slice-let matrix {array,slice}x{local,global}x{hi-default,hi-explicit}. Also fixes a cstage miscompile: the builder loaded a global-base sub-slice via localfind->0 + BP-relative (no let_islet/masym), so a `let s = G[lo:hi]` over a global array or slice G emitted LEAQ/MOVQ 0(BP) garbage instead of the symbol address. Routing through the global-aware shared path makes these correct (ken-confirmed broken->correct). --- cmd/w6c/cgen.c | 62 +++++++------------------------------------------- 1 file changed, 8 insertions(+), 54 deletions(-) diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index 3476cccb..686be800 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -6566,60 +6566,14 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame) cg_widen_tagged_store(c, locals, lu, n->rhs, D_BP, off, sz); break; } - /* slice expression initialiser: build a {ptr, len, cap} header - * referring to the source. Element size assumed to be 1 - * (u8) for now; real element-size scaling is a future TODO. */ - if (n->rhs && n->rhs->kind == N_SLICE && lu - && lu->kind == TY_SLICE) { - Node *base = n->rhs->lhs; - Node *lo = n->rhs->rhs; - Node *hi = n->rhs->cond; - Type *bt = base ? base->type : NULL; - Type *bu = (bt && bt->kind == TY_NAMED) ? bt->under : bt; - /* load base address */ - if (base->kind == N_IDENT) { - int boff = localfind(*locals, base->str); - if (bu && bu->kind == TY_ARRAY) { - ins2(c, A_LEAQ, amem(D_BP, boff), areg(D_AX)); - } else { - /* slice/str/ptr: load .ptr */ - ins2(c, A_MOVQ, amem(D_BP, boff), areg(D_AX)); - } - } else { - cgexpr(c, base, *locals); - } - ins1(c, A_PUSHQ, areg(D_AX)); /* save base addr */ - /* lo (default 0) */ - if (lo) cgexpr(c, lo, *locals); - else cgexpr_int(c, 0); - ins1(c, A_PUSHQ, areg(D_AX)); /* save lo */ - /* hi (default base length) */ - if (hi) { - cgexpr(c, hi, *locals); - } else if (bu && bu->kind == TY_ARRAY) { - cgexpr_int(c, (long long)bu->alen); - } else if (base->kind == N_IDENT && bu && - (bu->kind == TY_SLICE || bu->kind == TY_STR)) { - int boff = localfind(*locals, base->str); - ins2(c, A_MOVQ, amem(D_BP, boff + 8), areg(D_AX)); - } else { - cgexpr_int(c, 0); - } - ins2(c, A_MOVQ, areg(D_AX), areg(D_BX)); /* BX = hi */ - ins1(c, A_POPQ, areg(D_CX)); /* CX = lo */ - ins1(c, A_POPQ, areg(D_AX)); /* AX = base */ - ins2(c, A_ADDQ, areg(D_CX), areg(D_AX)); /* AX = base+lo */ - ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, off + 0)); - ins2(c, A_SUBQ, areg(D_CX), areg(D_BX)); /* BX = hi-lo */ - ins2(c, A_MOVQ, areg(D_BX), amem(D_BP, off + 8)); - ins2(c, A_MOVQ, areg(D_BX), amem(D_BP, off + 16)); - break; - } - /* Generic slice rhs (e.g. fn returning []u8, slice ident, - * slice-typed param). cgexpr leaves (AX=ptr, BX=len, CX= - * cap); store all three into the local slot. Runs after - * the alloc and N_SLICE specialisations above so they keep - * their direct-store shape. */ + /* Every slice initialiser routes here — fn-return, slice + * ident, slice param, and sub-slice `buf[lo:hi]`. cgexpr + * leaves (AX=ptr, BX=len, CX=cap); store all three. The + * sub-slice case once had a vestigial inline builder that + * duplicated cgexpr's N_SLICE path and mishandled global + * bases; dropping it aligns cstage onto wwstage's shared + * store path (find-4). Runs after the alloc specialisation + * above so that keeps its direct {ptr,0,n} shape. */ if (n->rhs && lu && lu->kind == TY_SLICE && sz == 24) { cgexpr(c, n->rhs, *locals); ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, off + 0));