w6c+w6c_ww: global-base arm for indexed struct-element field read (fix #21)
The `arr[i].field` N_DOT read branch in both stages was gated on a LOCAL
base lookup (cstage `localfind != 0`, wwstage `localfindnode != nil`). A
module-GLOBAL base (`let g: [2]pt = [...]`) missed it:
- cstage fell to a generic index-load that drops f->offset — it read
element[i] at offset 0, so `g[i].b` returned a's value (g[0].b -> 1,
g[1].b -> 3 instead of 2, 4).
- wwstage fell to the module-qualified SB fallback — garbage, no main.g
load at all.
Silent, byte-id-divergent. This is the READ twin of #11 (the global
`g[i] = v` write fix) and the #15 sibling. Local `[N]struct` bases read
correctly (tests 680/681 cover only those), which is why it was never
caught.
Fix (both stages, converged byte-identical): resolve the global the same
way the N_INDEX arm does — cstage `let_islet || def_isarraydef`, wwstage
`letvartnode || defvartnode` — and dispatch the base load by shape: array
-> LEAQ name(SB) (the symbol IS the storage), slice/ptr -> MOVQ name(SB)
(the symbol's first word IS the .ptr). The field then loads at f->offset
exactly as the local arm does. esz (element stride) and f->offset both
come from the type table (rule 13). Mirrors #11's write-side global-base
resolution. combined.ww embeds (w6c + wwdump) regenerate.
688_global_arr_elem_field: global `[2]pt` reads of .a/.b on both elements
(the .b reads are the bug), a non-8-aligned `[2]rec {tag:u8,x:i32,y:i64}`
to stress f->offset + a u8 sub-word leaf, and a slice-base read
(`let g: []rec = arr;`) that exercises the MOVQ-deref .ptr arm. Runtime
(cstage build+run) + cstage==wwstage byte-id per row. The slice row is
byte-id ONLY: its read asm is correct and identical on both stages, but a
slice-of-struct module global does not data-emit a symbol yet (a separate,
pre-existing data-emission gap, sibling of #10/#20), so it cannot link/run.
This commit is contained in:
@@ -8361,8 +8361,21 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
int is_sl = bu && bu->kind == TY_SLICE;
|
||||
int is_ptr = bu && bu->kind == TY_PTR;
|
||||
int off = localfind(locals, idxbase->str);
|
||||
/* #21 (READ twin of #11): a module-GLOBAL base
|
||||
* makes localfind return 0, so the field-offset-
|
||||
* aware branch was skipped and `g[i].field` fell to
|
||||
* a generic index-load that drops f->offset (reads
|
||||
* element[i] at offset 0). Resolve the global the
|
||||
* same way the N_INDEX arm does (let_islet ||
|
||||
* def_isarraydef) and dispatch the base load by
|
||||
* shape: array -> LEAQ name(SB) (the symbol IS the
|
||||
* storage), slice/ptr -> MOVQ name(SB) (the symbol's
|
||||
* first word IS the .ptr). */
|
||||
int isglobal = (off == 0)
|
||||
&& (let_islet(idxbase->str)
|
||||
|| def_isarraydef(idxbase->str));
|
||||
if (f != NULL && (is_arr || is_sl || is_ptr)
|
||||
&& off != 0) {
|
||||
&& (off != 0 || isglobal)) {
|
||||
int esz = (int)elemt->size;
|
||||
cgexpr(c, n->lhs->rhs, locals);
|
||||
if (esz > 1) {
|
||||
@@ -8371,7 +8384,15 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_IMULQ, areg(D_CX),
|
||||
areg(D_AX));
|
||||
}
|
||||
if (is_arr)
|
||||
if (isglobal && is_arr)
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, idxbase->str),
|
||||
areg(D_BX));
|
||||
else if (isglobal)
|
||||
ins2(c, A_MOVQ,
|
||||
masym(c, idxbase->str),
|
||||
areg(D_BX));
|
||||
else if (is_arr)
|
||||
ins2(c, A_LEAQ,
|
||||
amem(D_BP, off), areg(D_BX));
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user