wcc/cgen: #151 push all 3 header words for let-global slice/str by-value arg (wwstage)
A let-global slice or str passed by value as an argument was silently
field-dropped by wwstage: pushargsrev's global branch had only the #150-A
struct arm, and wwstage's nodeisslice/nodeisstr are local-keyed (false for
a global), so a global slice/str ident fell to the scalar single-PUSHQ,
pushing one of the three header words {ptr,len,cap} -> the callee read
garbage for .len/.cap. cstage was already correct.
wwstage-only, caller-side only (slice/str params already received
correctly). A global slice/str arm in pushargsrev, type-keyed on
tichase(arg.type_).kind, with two arms byte-matching cstage's two distinct
sequences -- str via cgslicehdr (CX-base, cgen.c:1866), slice per-word
(BX-base, cgen.c:9124). Gate is isletvar-only (a def has no name(SB)
holder; cstage const-folds it -- def-str/slice-by-value is the residual
task #21). cstage unchanged (w6c md5 unchanged); byte-id 990-997 8/8,
no lib pin flips. test/wcc/829 table-driven, byte-id per type.
This commit is contained in:
@@ -755,6 +755,50 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node, memphase: bool) i32 = {
|
||||
return rest + gnw;
|
||||
};
|
||||
}; };
|
||||
// #151: a module-global by-value slice/str arg — the
|
||||
// slice/str twin of the #150 struct arm above. wwstage's
|
||||
// nodeisslice/nodeisstr (below) are LOCAL-keyed
|
||||
// (localfindnode→nil for a global) so a global slice/str
|
||||
// ident returned false there and fell to the scalar
|
||||
// single-PUSHQ default, dropping len+cap. cstage is
|
||||
// type-keyed (node_isslice/node_isstr on n->type) so it
|
||||
// pushed all 3 header words. cstage emits a DIFFERENT
|
||||
// per-type sequence — mirror EACH for byte-id: a slice via
|
||||
// its dedicated push arm (BX-base per-word, cgen.c:9124); a
|
||||
// str falls to cgexpr's cgslicehdr (CX-base AX/BX/CX,
|
||||
// cgen.c:1866) then the node_isstr triple push.
|
||||
// LET-only (NOT deflookup, unlike the #150 struct arm):
|
||||
// cstage's slice arm gates let_islet (cgen.c:1869) and a
|
||||
// def-str is const-folded by cgexpr (LEAQ _S_0, MOVQ
|
||||
// $len) — it has no name(SB) holder. A deflookup here
|
||||
// would LEAQ an undefined main.<def>(SB) (w6l fails); a
|
||||
// def must fall through to the const-fold path instead.
|
||||
if (gst != nil && isletvar(c, nm)) {
|
||||
if (gst.kind == tykind.TY_SLICE) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, nm);
|
||||
emitline("(SB), BX\n");
|
||||
emitline("\tMOVQ\t16(BX), AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
emitline("\tMOVQ\t8(BX), AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
emitline("\tMOVQ\t(BX), AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + 3;
|
||||
};
|
||||
if (gst.kind == tykind.TY_STR) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, nm);
|
||||
emitline("(SB), CX\n");
|
||||
emitline("\tMOVQ\t(CX), AX\n");
|
||||
emitline("\tMOVQ\t8(CX), BX\n");
|
||||
emitline("\tMOVQ\t16(CX), CX\n");
|
||||
emitline("\tPUSHQ\tCX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
return rest + 3;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
// #271: aggregate (struct/array) arg from any source the ≤16B
|
||||
|
||||
Reference in New Issue
Block a user