cgen: fix global-ptr field READ, load ptr value via SB before offset (#15)
Reading gp.f through a module-global pointer miscompiled in BOTH stages, differently: cstage classified gp as a local at boff 0 and derefed BP (MOVQ (BP),BX), wwstage collapsed gp.f to an undefined global symbol f (MOVQ f(SB)). Both now load the pointer value from the global's data slot before the field offset, converging on MOVQ gp(SB),BX; MOVQ off(BX),AX. cstage mirrors the #6 store decline; wwstage gains a global-ptr arm and shares a cgptrfieldload helper with the local arm. Fused, not split: the two stages must emit byte-identical asm, so a one-stage commit would fail the byte-id gate. Sibling byte-divergences filed: #16 (chained-spine gp.x.y), #17 (>32B tagged word-order). Test: table-driven 689_globptr_field_read_run (24 rows, runtime + byte-id).
This commit is contained in:
@@ -11856,7 +11856,17 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
&& (lenfld || capfld || ptrfld)
|
||||
&& dot_lhs && dot_lhs->kind == N_IDENT) {
|
||||
int off = localfind(locals, dot_lhs->str);
|
||||
ins2(c, A_MOVQ, amem(D_BP, off), areg(D_BX));
|
||||
/* #15 — a module-GLOBAL ptr has no local
|
||||
* slot (off==0); load its pointer VALUE from
|
||||
* the data slot via SB, else amem(BP,0) derefs
|
||||
* the saved BP (read twin of the #6 store fix). */
|
||||
if (off == 0 && let_islet(dot_lhs->str))
|
||||
ins2(c, A_MOVQ,
|
||||
mafn(c, dot_lhs->str, c->cur_mod),
|
||||
areg(D_BX));
|
||||
else
|
||||
ins2(c, A_MOVQ, amem(D_BP, off),
|
||||
areg(D_BX));
|
||||
int delta = ptrfld ? 0 : (lenfld ? 8 : 16);
|
||||
ins2(c, A_MOVQ, amem(D_BX, delta), areg(D_AX));
|
||||
break;
|
||||
@@ -11878,7 +11888,17 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (inner && inner->kind == TY_STRUCT
|
||||
&& dot_lhs && dot_lhs->kind == N_IDENT) {
|
||||
int off = localfind(locals, dot_lhs->str);
|
||||
ins2(c, A_MOVQ, amem(D_BP, off), areg(D_BX));
|
||||
/* #15 — module-GLOBAL ptr base: load its pointer
|
||||
* VALUE from the data slot via SB (off==0 = no
|
||||
* local slot), else amem(BP,0) derefs the saved
|
||||
* BP (read twin of the #6 store fix). */
|
||||
if (off == 0 && let_islet(dot_lhs->str))
|
||||
ins2(c, A_MOVQ,
|
||||
mafn(c, dot_lhs->str, c->cur_mod),
|
||||
areg(D_BX));
|
||||
else
|
||||
ins2(c, A_MOVQ, amem(D_BP, off),
|
||||
areg(D_BX));
|
||||
for (Tfield *f = inner->fields; f; f = f->next) {
|
||||
if (strcmp(f->name, n->str) != 0) continue;
|
||||
/* tagged-union field through *struct: BX
|
||||
|
||||
Reference in New Issue
Block a user