cgen: str N_DOT field read -> 3-word {ptr,len,cap} -- Phase 2 C4.6 (both stages)
Reading a str-typed struct field loaded only 2 words (ptr,len), dropping the cap word. Fold the str-field read onto the adjacent proven slice-field arm by widening its kind-gate to include str (type_isstr/isstrtype, never size==24). Sites: S1 direct struct field (local BP + global CX base) and S2 field through a *struct local (pst.f). cstage==wwstage byte-identical; the slice-field arms stay unchanged for slices.
C4.6 bundles the S1 local-field fold with a FORCED global-field lift -- the rule-11 reason they cannot split: cstage reads a field with ONE unified base_reg arm, so folding str covers local AND global together. For byte-id, ww's global field path must then lift in the SAME commit -- but ww splits local/global and its global arm has no slice sibling, so it is authored as ww's own local slice-field arm retargeted to the CX base (cap->CX last, base survives). The underlying cstage-unifies / ww-splits field-arm divergence is a separate filed structural follow-up, not resolved here.
test/wcc/933: table-driven runtime .cap-survives over local/global/*struct field reads, both drivers; verified fail-before/pass-after. The local-field row interposes a CX-clobbering call so a 2-word read cannot coincidentally pass on stale CX (the field store otherwise leaves the cap word lingering in CX).
main.combined.ww regenerated via the canonical make path (md5-stable), per the 1140a59 precedent.
This commit is contained in:
@@ -5891,24 +5891,16 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
(void)is_global;
|
||||
break;
|
||||
}
|
||||
/* str field: load (ptr, len) into (AX, BX) so the
|
||||
* value flows through the str-rhs convention. */
|
||||
Type *str_fu = (f->type && f->type->kind == TY_NAMED)
|
||||
? f->type->under : f->type;
|
||||
if (str_fu && str_fu->kind == TY_STR) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(base_reg, base_disp + (int)f->offset + 0),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ,
|
||||
amem(base_reg, base_disp + (int)f->offset + 8),
|
||||
areg(D_BX));
|
||||
break;
|
||||
}
|
||||
/* slice field: load (ptr, len, cap) into (AX, BX, CX)
|
||||
* so the value flows through the slice-rhs convention.
|
||||
/* str IS []u8 — same 3-word {ptr,len,cap} as a slice
|
||||
* field: load (ptr, len, cap) into (AX, BX, CX) so the
|
||||
* value flows through the slice-rhs convention. str
|
||||
* folds onto the slice arm (#1/Phase 3 collapse).
|
||||
* base_reg may be CX for globals; load .cap LAST so
|
||||
* the base survives the earlier reads. */
|
||||
if (str_fu && str_fu->kind == TY_SLICE) {
|
||||
Type *str_fu = (f->type && f->type->kind == TY_NAMED)
|
||||
? f->type->under : f->type;
|
||||
if ((str_fu && str_fu->kind == TY_SLICE) ||
|
||||
type_isstr(f->type)) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(base_reg, base_disp + (int)f->offset + 0),
|
||||
areg(D_AX));
|
||||
@@ -6008,27 +6000,16 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
areg(D_R8));
|
||||
break;
|
||||
}
|
||||
/* str field through *struct: read len into a
|
||||
* scratch first (it's at +8) so loading ptr
|
||||
* into AX last leaves (AX=ptr, BX=len). We
|
||||
* use CX as the scratch, then move CX→BX. */
|
||||
Type *str_fu = (f->type && f->type->kind == TY_NAMED)
|
||||
? f->type->under : f->type;
|
||||
if (str_fu && str_fu->kind == TY_STR) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BX, (int)f->offset + 8),
|
||||
areg(D_CX));
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BX, (int)f->offset + 0),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_CX), areg(D_BX));
|
||||
break;
|
||||
}
|
||||
/* slice field through *struct: load (ptr, len,
|
||||
/* str IS []u8 — same 3-word {ptr,len,cap} as a
|
||||
* slice field through *struct: load (ptr, len,
|
||||
* cap) into (AX, BX, CX). BX holds the *struct
|
||||
* pointer, so load .len LAST — the earlier loads
|
||||
* still index off the original base. */
|
||||
if (str_fu && str_fu->kind == TY_SLICE) {
|
||||
* still index off the original base. str folds
|
||||
* onto the slice arm (#1/Phase 3 collapse). */
|
||||
Type *str_fu = (f->type && f->type->kind == TY_NAMED)
|
||||
? f->type->under : f->type;
|
||||
if ((str_fu && str_fu->kind == TY_SLICE) ||
|
||||
type_isstr(f->type)) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BX, (int)f->offset + 0),
|
||||
areg(D_AX));
|
||||
|
||||
Reference in New Issue
Block a user