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:
@@ -15928,21 +15928,14 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
if (streq(tf.name, fld)) {
|
||||
let ft: *tinfo = tf.type_;
|
||||
cgexpr(c, lhs); // AX = ptr to inner struct
|
||||
// str field: load both halves.
|
||||
if (typeisstr(ft)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((tf.offset + 8u64): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(tf.offset: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
// slice field: load (ptr, len, cap)
|
||||
// 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 (typeisslice(ft)) {
|
||||
// AX) LAST. str folds onto the slice
|
||||
// arm (#1/Phase 3 collapse; cite cstage
|
||||
// cgen.c N_DOT chained *struct caseB).
|
||||
if (typeisstr(ft) || typeisslice(ft)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((tf.offset + 8u64): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
|
||||
@@ -2100,21 +2100,14 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
if (streq(tf.name, fld)) {
|
||||
let ft: *tinfo = tf.type_;
|
||||
cgexpr(c, lhs); // AX = ptr to inner struct
|
||||
// str field: load both halves.
|
||||
if (typeisstr(ft)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((tf.offset + 8u64): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(tf.offset: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
// slice field: load (ptr, len, cap)
|
||||
// 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 (typeisslice(ft)) {
|
||||
// AX) LAST. str folds onto the slice
|
||||
// arm (#1/Phase 3 collapse; cite cstage
|
||||
// cgen.c N_DOT chained *struct caseB).
|
||||
if (typeisstr(ft) || typeisslice(ft)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((tf.offset + 8u64): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
|
||||
@@ -15928,21 +15928,14 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
if (streq(tf.name, fld)) {
|
||||
let ft: *tinfo = tf.type_;
|
||||
cgexpr(c, lhs); // AX = ptr to inner struct
|
||||
// str field: load both halves.
|
||||
if (typeisstr(ft)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((tf.offset + 8u64): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(tf.offset: i64, "AX");
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
// slice field: load (ptr, len, cap)
|
||||
// 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 (typeisslice(ft)) {
|
||||
// AX) LAST. str folds onto the slice
|
||||
// arm (#1/Phase 3 collapse; cite cstage
|
||||
// cgen.c N_DOT chained *struct caseB).
|
||||
if (typeisstr(ft) || typeisslice(ft)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg((tf.offset + 8u64): i64, "AX");
|
||||
emitline(", BX\n");
|
||||
|
||||
Reference in New Issue
Block a user