cgen: str chained-*struct field read -> 3-word -- Phase 2 C4.6 caseB (both stages)
The chained N_DOT path (o.p.f, depth>=2, base AX) still loaded a str-typed field as 2 words, dropping cap -- the C4.6 sibling deferred to caseB. Fold the str case onto the adjacent 3-word slice-field arm (widen kind-gate: cstage type_isstr, ww typeisstr; never size==24). Emits len->BX+8, cap->CX+16, ptr->AX+0 LAST (AX is the base). cstage==wwstage byte-identical; the slice arm is unchanged for slices. test/wcc/934: table-driven runtime .cap-survives over the chained read; the row interposes a CX-clobbering call so a 2-word read cannot coincidentally pass on stale CX (per the 933 discriminator lesson). Verified fail-before/pass-after on both drivers. main.combined.ww regenerated via the canonical make path (md5-stable).
This commit is contained in:
@@ -6061,20 +6061,13 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
Type *ft = f->type;
|
||||
Type *fu = (ft && ft->kind == TY_NAMED)
|
||||
? ft->under : ft;
|
||||
/* str field: load (ptr, len) into (AX, BX). */
|
||||
if (fu && fu->kind == TY_STR) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_AX, (int)f->offset + 8),
|
||||
areg(D_BX));
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_AX, (int)f->offset + 0),
|
||||
areg(D_AX));
|
||||
goto dot_done;
|
||||
}
|
||||
/* slice field: load (ptr, len, cap) into
|
||||
/* str IS []u8 — same 3-word {ptr,len,cap} as a
|
||||
* slice field: load (ptr, len, cap) into
|
||||
* (AX, BX, CX). AX is the *struct base, so
|
||||
* load .ptr (which targets AX) LAST. */
|
||||
if (fu && fu->kind == TY_SLICE) {
|
||||
* load .ptr (which targets AX) LAST. str folds
|
||||
* onto the slice arm (#1/Phase 3 collapse). */
|
||||
if ((fu && fu->kind == TY_SLICE) ||
|
||||
type_isstr(ft)) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_AX, (int)f->offset + 8),
|
||||
areg(D_BX));
|
||||
|
||||
Reference in New Issue
Block a user