wwstage: fold chained global-ptr field READ to cstage offset-fold (#16)

wwstage's chained-N_DOT resolver (dotchainresolve) didn't resolve a global
*struct root (only local *T and global value-struct), so gp.sf.len / gp.x.y
bailed to an inner-dot load + shuffle, byte-diverging from cstage's offset-fold.
Both stages already ran correct after #15 (475c003) -- a pure rule-10 asm
divergence. cstage is untouched (the oracle); wwstage aligns up.

Resolve a global N_TPTR root, and extract emitchainbase for the viacx base-load
(byte-identical across the 5 read + 2 store sites it replaces). The chained
STORE caller declines the global-ptr root (yok=false) so it falls to cstage's
address-spine mirror -- matching the #6/#15 decline-to-resolver discipline;
local *T chained stores still fold.

Test: +2 chained rows (gp.sf.len, gp.x.q), runtime + byte-id; proven to fail
byte-id with only the compiler files reverted, pass with the fix.

Sibling follow-ups filed: #17 (>32B tagged word-order), #18 (chained read into
an i64 sink MOVSXD check).
This commit is contained in:
2026-06-23 07:25:33 +09:00
parent 475c003b0d
commit ab3ac67afd
3 changed files with 95 additions and 67 deletions

View File

@@ -4942,6 +4942,28 @@ export fn dotchainresolve(c: *cgen, n: *syntax.node,
};
};
};
// Global `*struct` root (`let gp: *S`): localfindnode is nil and
// letvarstructinfo below only matches a VALUE-struct global, so a
// `*struct` global root needs its own arm. Gate on N_TPTR→N_TNAME
// exactly as the local `*T` arm above; the post-resolution loop peels
// the TY_PTR off cur.type_ and validates the pointee is a struct.
// Mirrors cstage cgen.c's ptr_root + let_islet base resolution
// (LEAQ name(SB),CX; MOVQ (CX),CX). (#16, chained twin of #15.)
if (!resolved && lc == nil) {
let gtn: *syntax.node = letvartnode(c, cur.str);
if (gtn != nil) {
if (gtn.kind == syntax.nkind.N_TPTR) {
let pe: *syntax.node = gtn.lhs;
if (pe != nil) {
if (pe.kind == syntax.nkind.N_TNAME) {
*outisglobal = true;
*outptrroot = true;
resolved = true;
};
};
};
};
};
if (!resolved) {
let gsi: *structinfo = letvarstructinfo(c, cur.str);
if (gsi != nil) {