w6c+wwstage: addr-of/slice struct array-field via dotbaseaddr (#252)
Taking &x.o[i] (address-of) or slicing x.o[lo:hi] / x.o[lo:] of a struct's [N]T-typed FIELD computed the field's VALUE as the base address (MOVL off(BP),AX) instead of its ADDRESS (LEAQ off(BP),AX) -> garbage pointer -> segfault. The index read/write path was fixed in #135; this is the unwired addr-of + slice sibling — both base-address paths fell to the generic cgexpr(base) auto-deref. Wire the #135 cg_dotbase_addr / dotbaseaddr helper into the addr-of N_INDEX complex-base arm and the N_SLICE base arm, symmetric on both stages (guarded if(!dotbase) cgexpr(base)). Extend the slice element stride (esz) and default-hi length to an N_DOT array-field base too, read from the field's element tinfo / array length via the type table (rule-13) — so non-u8 element slices scale correctly and s.obuf[lo:] gets the array's element count. cstage already derived default-hi via base->type (alen); only wwstage needed the N_DOT default-hi arm. cs==ww byte-identical on every shape. test/949_dotbase_addr_slice_run: 7 dual-stage rows (addr-of local + *struct param, explicit + default-hi u8 slice, non-u8 [4]i32 stride, bare-local control), run + cs==ww byte-id. Regen w6c/wwdump combined.ww.
This commit is contained in:
@@ -20727,15 +20727,29 @@ fn cgslice(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #252: an N_DOT `[N]T`-field base (`s.obuf[lo:hi]`) carries no
|
||||
// tnode — resolve esz / default-hi / base-address from the checker-
|
||||
// stamped element tinfo on base.type_ instead. Cstage twin reads
|
||||
// base->type (cgen.c N_SLICE esz + bu->kind==TY_ARRAY default-hi).
|
||||
let dotbu: *tinfo = nil;
|
||||
if (base != nil) { if (base.kind == nkind.N_DOT) {
|
||||
dotbu = base.type_: *tinfo;
|
||||
for (dotbu != nil && dotbu.kind == tykind.TY_NAMED) {
|
||||
dotbu = dotbu.under;
|
||||
};
|
||||
};};
|
||||
// esz from the type table for an N_IDENT base (#76; mirrors the
|
||||
// cgindex idiom). Non-ident base stays esz=1 -> ptr unscaled,
|
||||
// matching cstage's base->kind==N_IDENT gate.
|
||||
// cgindex idiom) or an N_DOT array/slice-field base (#252: scale by
|
||||
// the field's element width, not esz=1 — silently wrong for non-u8).
|
||||
// Other non-ident bases stay esz=1 -> ptr unscaled.
|
||||
let esz: i32 = 1;
|
||||
if (baselocal != nil) {
|
||||
esz = elemsizeofc(c, baselocal.tnode);
|
||||
} else { if (globaltn != nil) {
|
||||
esz = elemsizeofc(c, globaltn);
|
||||
};};
|
||||
} else { if (dotbu != nil && dotbu.sub != nil) {
|
||||
esz = dotbu.sub.size: i32;
|
||||
};};};
|
||||
// base address
|
||||
if (baselocal != nil) {
|
||||
let tn: *node = baselocal.tnode;
|
||||
@@ -20766,7 +20780,12 @@ fn cgslice(c: *cgen, n: *node) void = {
|
||||
emitline("(SB), AX\n");
|
||||
};
|
||||
} else { if (base != nil) {
|
||||
cgexpr(c, base);
|
||||
// #252: N_DOT `[N]T`-field base → field ADDRESS via
|
||||
// dotbaseaddr (LEAQ), not the auto-deref VALUE load cgexpr
|
||||
// emits. Sibling of the #135 read-side.
|
||||
if (!dotbaseaddr(c, base, "AX")) {
|
||||
cgexpr(c, base);
|
||||
};
|
||||
};};};
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
// lo (default 0)
|
||||
@@ -20825,9 +20844,16 @@ fn cgslice(c: *cgen, n: *node) void = {
|
||||
handled = true;
|
||||
};};
|
||||
if (!handled) { emitline("\tMOVQ\t$0, AX\n"); };
|
||||
} else { if (dotbu != nil && dotbu.kind == tykind.TY_ARRAY) {
|
||||
// #252: default-hi `s.obuf[lo:]` on a struct array-field →
|
||||
// element count from the field's array tinfo. Cstage twin
|
||||
// cgexpr_int(bu->alen) (cgen.c N_SLICE default-hi).
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(dotbu.alen: i64);
|
||||
emitline(", AX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
};};};
|
||||
};};};};
|
||||
emitline("\tMOVQ\tAX, BX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
@@ -22538,8 +22564,14 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
// + POPQ AX scratch shuffle was rule-10
|
||||
// verbose-defensive on the wwstage side
|
||||
// with no semantic asymmetry (task #21).
|
||||
// #252: an N_DOT `[N]T`-field base needs the
|
||||
// field ADDRESS (dotbaseaddr LEAQ), not the
|
||||
// auto-deref VALUE load cgexpr emits. Sibling
|
||||
// of the #135 read-side wiring.
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, base);
|
||||
if (!dotbaseaddr(c, base, "AX")) {
|
||||
cgexpr(c, base);
|
||||
};
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
};};};
|
||||
emitline("\tADDQ\tBX, AX\n");
|
||||
|
||||
@@ -1429,15 +1429,29 @@ fn cgslice(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #252: an N_DOT `[N]T`-field base (`s.obuf[lo:hi]`) carries no
|
||||
// tnode — resolve esz / default-hi / base-address from the checker-
|
||||
// stamped element tinfo on base.type_ instead. Cstage twin reads
|
||||
// base->type (cgen.c N_SLICE esz + bu->kind==TY_ARRAY default-hi).
|
||||
let dotbu: *tinfo = nil;
|
||||
if (base != nil) { if (base.kind == nkind.N_DOT) {
|
||||
dotbu = base.type_: *tinfo;
|
||||
for (dotbu != nil && dotbu.kind == tykind.TY_NAMED) {
|
||||
dotbu = dotbu.under;
|
||||
};
|
||||
};};
|
||||
// esz from the type table for an N_IDENT base (#76; mirrors the
|
||||
// cgindex idiom). Non-ident base stays esz=1 -> ptr unscaled,
|
||||
// matching cstage's base->kind==N_IDENT gate.
|
||||
// cgindex idiom) or an N_DOT array/slice-field base (#252: scale by
|
||||
// the field's element width, not esz=1 — silently wrong for non-u8).
|
||||
// Other non-ident bases stay esz=1 -> ptr unscaled.
|
||||
let esz: i32 = 1;
|
||||
if (baselocal != nil) {
|
||||
esz = elemsizeofc(c, baselocal.tnode);
|
||||
} else { if (globaltn != nil) {
|
||||
esz = elemsizeofc(c, globaltn);
|
||||
};};
|
||||
} else { if (dotbu != nil && dotbu.sub != nil) {
|
||||
esz = dotbu.sub.size: i32;
|
||||
};};};
|
||||
// base address
|
||||
if (baselocal != nil) {
|
||||
let tn: *node = baselocal.tnode;
|
||||
@@ -1468,7 +1482,12 @@ fn cgslice(c: *cgen, n: *node) void = {
|
||||
emitline("(SB), AX\n");
|
||||
};
|
||||
} else { if (base != nil) {
|
||||
cgexpr(c, base);
|
||||
// #252: N_DOT `[N]T`-field base → field ADDRESS via
|
||||
// dotbaseaddr (LEAQ), not the auto-deref VALUE load cgexpr
|
||||
// emits. Sibling of the #135 read-side.
|
||||
if (!dotbaseaddr(c, base, "AX")) {
|
||||
cgexpr(c, base);
|
||||
};
|
||||
};};};
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
// lo (default 0)
|
||||
@@ -1527,9 +1546,16 @@ fn cgslice(c: *cgen, n: *node) void = {
|
||||
handled = true;
|
||||
};};
|
||||
if (!handled) { emitline("\tMOVQ\t$0, AX\n"); };
|
||||
} else { if (dotbu != nil && dotbu.kind == tykind.TY_ARRAY) {
|
||||
// #252: default-hi `s.obuf[lo:]` on a struct array-field →
|
||||
// element count from the field's array tinfo. Cstage twin
|
||||
// cgexpr_int(bu->alen) (cgen.c N_SLICE default-hi).
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(dotbu.alen: i64);
|
||||
emitline(", AX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
};};};
|
||||
};};};};
|
||||
emitline("\tMOVQ\tAX, BX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
@@ -3240,8 +3266,14 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
// + POPQ AX scratch shuffle was rule-10
|
||||
// verbose-defensive on the wwstage side
|
||||
// with no semantic asymmetry (task #21).
|
||||
// #252: an N_DOT `[N]T`-field base needs the
|
||||
// field ADDRESS (dotbaseaddr LEAQ), not the
|
||||
// auto-deref VALUE load cgexpr emits. Sibling
|
||||
// of the #135 read-side wiring.
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, base);
|
||||
if (!dotbaseaddr(c, base, "AX")) {
|
||||
cgexpr(c, base);
|
||||
};
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
};};};
|
||||
emitline("\tADDQ\tBX, AX\n");
|
||||
|
||||
@@ -20727,15 +20727,29 @@ fn cgslice(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #252: an N_DOT `[N]T`-field base (`s.obuf[lo:hi]`) carries no
|
||||
// tnode — resolve esz / default-hi / base-address from the checker-
|
||||
// stamped element tinfo on base.type_ instead. Cstage twin reads
|
||||
// base->type (cgen.c N_SLICE esz + bu->kind==TY_ARRAY default-hi).
|
||||
let dotbu: *tinfo = nil;
|
||||
if (base != nil) { if (base.kind == nkind.N_DOT) {
|
||||
dotbu = base.type_: *tinfo;
|
||||
for (dotbu != nil && dotbu.kind == tykind.TY_NAMED) {
|
||||
dotbu = dotbu.under;
|
||||
};
|
||||
};};
|
||||
// esz from the type table for an N_IDENT base (#76; mirrors the
|
||||
// cgindex idiom). Non-ident base stays esz=1 -> ptr unscaled,
|
||||
// matching cstage's base->kind==N_IDENT gate.
|
||||
// cgindex idiom) or an N_DOT array/slice-field base (#252: scale by
|
||||
// the field's element width, not esz=1 — silently wrong for non-u8).
|
||||
// Other non-ident bases stay esz=1 -> ptr unscaled.
|
||||
let esz: i32 = 1;
|
||||
if (baselocal != nil) {
|
||||
esz = elemsizeofc(c, baselocal.tnode);
|
||||
} else { if (globaltn != nil) {
|
||||
esz = elemsizeofc(c, globaltn);
|
||||
};};
|
||||
} else { if (dotbu != nil && dotbu.sub != nil) {
|
||||
esz = dotbu.sub.size: i32;
|
||||
};};};
|
||||
// base address
|
||||
if (baselocal != nil) {
|
||||
let tn: *node = baselocal.tnode;
|
||||
@@ -20766,7 +20780,12 @@ fn cgslice(c: *cgen, n: *node) void = {
|
||||
emitline("(SB), AX\n");
|
||||
};
|
||||
} else { if (base != nil) {
|
||||
cgexpr(c, base);
|
||||
// #252: N_DOT `[N]T`-field base → field ADDRESS via
|
||||
// dotbaseaddr (LEAQ), not the auto-deref VALUE load cgexpr
|
||||
// emits. Sibling of the #135 read-side.
|
||||
if (!dotbaseaddr(c, base, "AX")) {
|
||||
cgexpr(c, base);
|
||||
};
|
||||
};};};
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
// lo (default 0)
|
||||
@@ -20825,9 +20844,16 @@ fn cgslice(c: *cgen, n: *node) void = {
|
||||
handled = true;
|
||||
};};
|
||||
if (!handled) { emitline("\tMOVQ\t$0, AX\n"); };
|
||||
} else { if (dotbu != nil && dotbu.kind == tykind.TY_ARRAY) {
|
||||
// #252: default-hi `s.obuf[lo:]` on a struct array-field →
|
||||
// element count from the field's array tinfo. Cstage twin
|
||||
// cgexpr_int(bu->alen) (cgen.c N_SLICE default-hi).
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(dotbu.alen: i64);
|
||||
emitline(", AX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
};};};
|
||||
};};};};
|
||||
emitline("\tMOVQ\tAX, BX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
@@ -22538,8 +22564,14 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
// + POPQ AX scratch shuffle was rule-10
|
||||
// verbose-defensive on the wwstage side
|
||||
// with no semantic asymmetry (task #21).
|
||||
// #252: an N_DOT `[N]T`-field base needs the
|
||||
// field ADDRESS (dotbaseaddr LEAQ), not the
|
||||
// auto-deref VALUE load cgexpr emits. Sibling
|
||||
// of the #135 read-side wiring.
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, base);
|
||||
if (!dotbaseaddr(c, base, "AX")) {
|
||||
cgexpr(c, base);
|
||||
};
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
};};};
|
||||
emitline("\tADDQ\tBX, AX\n");
|
||||
|
||||
Reference in New Issue
Block a user