wwstage: copy full tagged-element slot for N_DOT/N_INDEX-base index read (#261)

The #259 store fix unmasked a pre-existing latent cs!=ww in the tagged-
element READ via an N_DOT base (`x.o[i]`) / chained N_INDEX base
(`m[i][j]`): wwstage materialized the element as a SCALAR one-word load +
zeroed tag where cstage copies the full tagged slot — silently dropping
the tag/payload-high word (wrong variant). Three sites all keyed off the
same N_IDENT-only gate; cstage classifies TY_TAGGED for ANY base off the
checker-stamped element type. Align wwstage UP:

- cgindex (cgenexpr.ww): the N_DOT/N_INDEX-base arm now sets
  elem_tagged/elem_slot_sz from n.type_ (the stamped element tinfo),
  mirroring cstage cgen.c:8101 — the full-slot copy arms then fire.
- rhstaggedabicall (cgenutil.ww): the N_INDEX branch reads
  typeistagged(src.type_) for any base instead of an N_IDENT-only
  structural lookup, mirroring cstage's src->type keying — fixes the
  let-init / call-arg widen-source spill.
- forwardtagged (cgenstmt.ww): the return-path passthrough gate now
  accepts N_INDEX/N_DOT tagged rhs (which cgexpr materializes into the
  tagged ABI), not just N_CALL — fixes `return x.o[i]`.

read + call-arg + return + chained 2D all close by construction (one
materialization path). cstage unchanged (pure wwstage-align-up). 949
gains 9 #261 rows (i32 + explicit-void variant per shape proves the tag
survives) and flips the two #259 read-back rows to byteid=1.
This commit is contained in:
2026-06-02 06:02:56 +09:00
parent be23d7227a
commit 0afc272f47
6 changed files with 243 additions and 77 deletions

View File

@@ -2548,27 +2548,17 @@ fn rhstaggedabicall(c: *cgen, src: *node) bool = {
return false;
};
if (src.kind == nkind.N_INDEX) {
let base: *node = src.lhs;
if (base != nil) {
if (base.kind == nkind.N_IDENT) {
let bl: *local = localfindnode(c, base.str);
if (bl != nil) {
let btn: *node = bl.tnode;
if (btn != nil) {
let bk: nkind = btn.kind;
let elemt: *node = nil;
if (bk == nkind.N_TARRAY) { elemt = btn.lhs; };
if (bk == nkind.N_TSLICE) { elemt = btn.lhs; };
if (bk == nkind.N_TPTR) { elemt = btn.lhs; };
if (elemt != nil) {
if (istaggedtype(c, elemt)) {
return true;
};
};
};
};
};
};
// The checker stamps every N_INDEX node's type_ to the element
// tinfo (check.ww:2334-2337 indexresult) for ANY base shape —
// N_IDENT, N_DOT (`x.o[i]`), or chained N_INDEX (`m[i][j]`). Read
// it directly, mirroring cstage cg_widen_tagged_store keying on
// src->type (cmd/w6c/cgen.c:2020-2023). #261: the prior
// N_IDENT-base-only structural lookup missed N_DOT/N_INDEX bases,
// so a tagged element materialized via `x.o[i]` (correct AX/DX
// slot from cgindex) was then spilled by the scalar-widen arm,
// dropping the tag/payload-high word — silent cs≠ww.
if (typeistagged(src.type_: *tinfo)) { return true; };
return false;
};
// N_DOT of a tagged-typed struct field — cgdot loads
// AX=tag, DX=word0, CX=word1[, R8=word2], so downstream