w6c: resolve ptr-to-array and slice-element aggregate sources (task #6 residue)
The two loud siblings filed in d3822d77: (a) an auto-deref *[N]T
indexed base (hs[k].result) failed cgplaceaddr's N_INDEX arm, which
knew only TY_SLICE/TY_ARRAY bases — add the one-pointer hop (the
(*hs)[k] form made implicit; load shape is the slice .ptr word's);
(b) a bare slice-element aggregate source (use(sl[k])) fell off
aggarg_srcaddr's ident-array-only N_INDEX arm into the #271 loud
stop — route the miss through the same cgplaceaddr fallback the
N_DOT arm uses. Both stages, byte-identical (probe matrix: let-copy,
field-assign, call-arg, return, indexed-store all IDENT).
After this, every ADDRESSABLE aggregate source resolves: ident
(local/module-let), deref, dot-chain, and index over array/slice/
ptr-array spines recurse through cgplaceaddr; the remaining loud
paths are rvalue sources (#40 family) and the #274 const-def arg,
both documented divergences. 8 rows added to idxdot_aggcopy_test.
This commit is contained in:
@@ -2313,7 +2313,10 @@ aggarg_srcaddr(Cg *c, Node *src, int dst, Local *locals)
|
||||
ins2(c, A_MOVQ, areg(D_AX), areg(dst));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
/* task #6 sibling: slice-element / non-ident-array base
|
||||
* (use(sl[k])) — the same C4/#40 place-resolver fallback
|
||||
* as the N_DOT arm; the missed walk is emission-free. */
|
||||
return cgplaceaddr(c, src, dst, locals);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2451,7 +2454,16 @@ cgplaceaddr(Cg *c, Node *n, int dst_reg, Local *locals)
|
||||
* dispatch first), so their asm is untouched. */
|
||||
Type *bu = type_chase_named(base->type);
|
||||
if (bu == NULL) return 0;
|
||||
if (bu->kind != TY_SLICE && bu->kind != TY_ARRAY)
|
||||
/* Auto-deref: a *[N]T indexed base takes one pointer hop —
|
||||
* the (*hs)[k] form made implicit (checker already stamps
|
||||
* the element type). Load shape is the slice .ptr word's. */
|
||||
int viaptr = 0;
|
||||
if (bu->kind == TY_PTR) {
|
||||
Type *p = type_chase_named(bu->sub);
|
||||
if (p && p->kind == TY_ARRAY)
|
||||
viaptr = 1;
|
||||
}
|
||||
if (!viaptr && bu->kind != TY_SLICE && bu->kind != TY_ARRAY)
|
||||
return 0;
|
||||
Type *et = type_chase_named(n->type);
|
||||
if (et == NULL) return 0;
|
||||
@@ -2465,8 +2477,8 @@ cgplaceaddr(Cg *c, Node *n, int dst_reg, Local *locals)
|
||||
if (!cgplaceaddr(c, base, dst_reg, locals)) return 0;
|
||||
/* A slice place holds the {ptr,len,cap} header — the
|
||||
* element base is its .ptr word; an array place IS the
|
||||
* element storage. */
|
||||
if (bu->kind == TY_SLICE)
|
||||
* element storage; a *[N]T place holds the array address. */
|
||||
if (bu->kind == TY_SLICE || viaptr)
|
||||
ins2(c, A_MOVQ, amem(dst_reg, 0), areg(dst_reg));
|
||||
ins1(c, A_POPQ, areg(D_AX));
|
||||
ins2(c, A_ADDQ, areg(D_AX), areg(dst_reg));
|
||||
|
||||
@@ -1704,14 +1704,17 @@ fn aggargsrcaddr(c: *cgen, src: *syntax.node, dst: str) bool = {
|
||||
return cgplaceaddr(c, src, dst);
|
||||
};
|
||||
if (src.kind == syntax.nkind.N_INDEX) {
|
||||
// task #6 sibling: slice-element / non-ident-array base
|
||||
// (use(sl[k])) — the same C4/#40 place-resolver fallback
|
||||
// as the N_DOT arm; the missed walk is emission-free.
|
||||
let base: *syntax.node = src.lhs;
|
||||
let idx: *syntax.node = src.rhs;
|
||||
if (base == nil) { return false; };
|
||||
if (base.kind != syntax.nkind.N_IDENT) { return false; };
|
||||
if (base == nil) { return cgplaceaddr(c, src, dst); };
|
||||
if (base.kind != syntax.nkind.N_IDENT) { return cgplaceaddr(c, src, dst); };
|
||||
let bu: *syntax.tinfo = base.type_: *syntax.tinfo;
|
||||
bu = tichase(bu);
|
||||
if (bu == nil) { return false; };
|
||||
if (bu.kind != syntax.tykind.TY_ARRAY) { return false; };
|
||||
if (bu == nil) { return cgplaceaddr(c, src, dst); };
|
||||
if (bu.kind != syntax.tykind.TY_ARRAY) { return cgplaceaddr(c, src, dst); };
|
||||
let esz: i32 = 1;
|
||||
if (bu.sub != nil) { esz = bu.sub.size: i32; };
|
||||
cgexpr(c, idx);
|
||||
@@ -1966,7 +1969,18 @@ fn cgplaceaddr(c: *cgen, n: *syntax.node, dstreg: str) bool = {
|
||||
let bu: *syntax.tinfo = base.type_: *syntax.tinfo;
|
||||
bu = tichase(bu);
|
||||
if (bu == nil) { return false; };
|
||||
if (bu.kind != syntax.tykind.TY_SLICE && bu.kind != syntax.tykind.TY_ARRAY) {
|
||||
// Auto-deref: a *[N]T indexed base takes one pointer hop —
|
||||
// the (*hs)[k] form made implicit (checker already stamps
|
||||
// the element type). Load shape is the slice .ptr word's.
|
||||
let viaptr: bool = false;
|
||||
if (bu.kind == syntax.tykind.TY_PTR) {
|
||||
let p: *syntax.tinfo = bu.sub;
|
||||
p = tichase(p);
|
||||
if (p != nil) { if (p.kind == syntax.tykind.TY_ARRAY) {
|
||||
viaptr = true;
|
||||
}; };
|
||||
};
|
||||
if (!viaptr && bu.kind != syntax.tykind.TY_SLICE && bu.kind != syntax.tykind.TY_ARRAY) {
|
||||
return false;
|
||||
};
|
||||
let et: *syntax.tinfo = n.type_: *syntax.tinfo;
|
||||
@@ -1984,8 +1998,8 @@ fn cgplaceaddr(c: *cgen, n: *syntax.node, dstreg: str) bool = {
|
||||
if (!cgplaceaddr(c, base, dstreg)) { return false; };
|
||||
// A slice place holds the {ptr,len,cap} header — the
|
||||
// element base is its .ptr word; an array place IS the
|
||||
// element storage.
|
||||
if (bu.kind == syntax.tykind.TY_SLICE) {
|
||||
// element storage; a *[N]T place holds the array address.
|
||||
if (bu.kind == syntax.tykind.TY_SLICE || viaptr) {
|
||||
emitline("\tMOVQ\t(");
|
||||
emitline(dstreg);
|
||||
emitline("), ");
|
||||
|
||||
@@ -131,3 +131,86 @@ fn pickresult(hs: *[4]handle, k: i64) inner = {
|
||||
assert(hs[0].result.a == 40);
|
||||
assert(hs[0].result.b == 41);
|
||||
};
|
||||
|
||||
// task #6 siblings (the d3822d77 loud residue): a *[N]T indexed base
|
||||
// auto-derefs through cgplaceaddr's pointer hop, and a bare slice
|
||||
// element rides aggarg_srcaddr's place-resolver fallback.
|
||||
@test fn ptrbaseletcopy() void = {
|
||||
let hs: [4]handle = mk();
|
||||
let hp: *[4]handle = &hs;
|
||||
let k: i64 = 2;
|
||||
let r: inner = hp[k].result;
|
||||
assert(r.a == 11);
|
||||
assert(r.b == 31);
|
||||
};
|
||||
|
||||
@test fn ptrbasecallarg() void = {
|
||||
let hs: [4]handle = mk();
|
||||
let hp: *[4]handle = &hs;
|
||||
let k: i64 = 2;
|
||||
assert(use(hp[k].result) == 42);
|
||||
};
|
||||
|
||||
fn pickptr(hp: *[4]handle, k: i64) inner = {
|
||||
return hp[k].result;
|
||||
};
|
||||
|
||||
@test fn ptrbasereturn() void = {
|
||||
let hs: [4]handle = mk();
|
||||
let r: inner = pickptr(&hs, 2);
|
||||
assert(r.a == 11);
|
||||
assert(r.b == 31);
|
||||
};
|
||||
|
||||
@test fn ptrbasefieldassign() void = {
|
||||
let hs: [4]handle = mk();
|
||||
let hp: *[4]handle = &hs;
|
||||
let k: i64 = 2;
|
||||
let g: bag;
|
||||
g.n = 0;
|
||||
g.res = hp[k].result;
|
||||
assert(g.res.a == 11);
|
||||
assert(g.res.b == 31);
|
||||
};
|
||||
|
||||
@test fn sliceelemletcopy() void = {
|
||||
let hs: [4]handle = mk();
|
||||
let sl: []handle = hs[0:4];
|
||||
let k: i64 = 2;
|
||||
let e: handle = sl[k];
|
||||
assert(e.id == 9);
|
||||
assert(e.result.a == 11);
|
||||
};
|
||||
|
||||
@test fn sliceelemcallarg() void = {
|
||||
let hs: [4]handle = mk();
|
||||
let sl: []handle = hs[0:4];
|
||||
let k: i64 = 2;
|
||||
assert(usehandle(sl[k]) == 51);
|
||||
};
|
||||
|
||||
fn usehandle(h: handle) i64 = {
|
||||
return h.id + h.result.a + h.result.b;
|
||||
};
|
||||
|
||||
fn pickelem(sl: []handle, k: i64) handle = {
|
||||
return sl[k];
|
||||
};
|
||||
|
||||
@test fn sliceelemreturn() void = {
|
||||
let hs: [4]handle = mk();
|
||||
let sl: []handle = hs[0:4];
|
||||
let e: handle = pickelem(sl, 2);
|
||||
assert(e.id == 9);
|
||||
assert(e.result.b == 31);
|
||||
};
|
||||
|
||||
@test fn sliceelemindexedstore() void = {
|
||||
let hs: [4]handle = mk();
|
||||
let sl: []handle = hs[0:4];
|
||||
let out: [2]inner;
|
||||
let j: i64 = 0;
|
||||
out[j] = sl[2].result;
|
||||
assert(out[0].a == 11);
|
||||
assert(out[0].b == 31);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user