wcc/cgen: #150 by-value module-global struct-arg base — load main.g(SB) all words (both stages)
Passing a module-global struct by value -- let g: pt = pt{...}; take(g)
-- was silently miscompiled, mirror-opposite on the two stages. cstage's
by-value struct-arg arm hit localfind(g)->0 and read 2 words from the
frame (MOVQ (BP)), never main.g(SB) -> returned garbage. wwstage used the
correct main.g(SB) base but fell through to the scalar single-PUSHQ
default, pushing one word for a 2-word struct -> dropped a field.
Both stages now take the off==0 global branch: LEAQ main.NAME(SB) and copy
all struct-size/8 eightbytes (reusing the GAP-A.ptr/#231 global-base
predicate), converging to one byte-identical sequence. The local path
(off!=0) is unchanged; >16B aggregates (#271) already resolved globals.
Commit A of the cluster; the cstage-only inferred-global-type Sym-repoint
(every let g = ... module-global yields <nil> downstream) is Commit B
(#18). Slice/str global-by-value args have the same wwstage field-drop --
filed (#10 G-valglobal-arg; struct closed here). byte-id 990-997 8/8.
test/wcc/822 table-driven, byte-id per stage.
This commit is contained in:
@@ -9243,6 +9243,25 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
/* load qword(s) directly from the struct's slot */
|
||||
int off = localfind(locals, args[i]->str);
|
||||
int sz = struct_arg_size(args[i]->type);
|
||||
/* #150: a module-global struct source — off==0
|
||||
* is the localfind footgun (GAP-A.ptr/#231
|
||||
* family); the BP loads below read the stack
|
||||
* frame, not main.g(SB). Resolve the global base
|
||||
* into BX (the #129-A.2 struct-global LEAQ shape)
|
||||
* and copy ALL eightbytes from it. */
|
||||
if (off == 0 && (let_islet(args[i]->str)
|
||||
|| def_isstructdef(args[i]->str))) {
|
||||
ins2(c, A_LEAQ, masym(c, args[i]->str),
|
||||
areg(D_BX));
|
||||
if (sz > 8) {
|
||||
ins2(c, A_MOVQ, amem(D_BX, 8),
|
||||
areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
}
|
||||
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
continue;
|
||||
}
|
||||
if (sz > 8) {
|
||||
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
|
||||
Reference in New Issue
Block a user