ww: cgen trap batch (def-str field, chained-ptr write, scalar+str tuple ABI)
This commit is contained in:
@@ -419,6 +419,49 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
};
|
||||
// Hare-style tuple positional access: `t.0`, `t.1`.
|
||||
// Walk the tuple element type list summing slotsize
|
||||
// (matches the (scalar, str) init layout which puts
|
||||
// the scalar in an 8B slot and the str in 16B). For
|
||||
// a str element, load both halves into (AX, BX) so
|
||||
// chains like `t.1.len` propagate correctly.
|
||||
if (lkind == N_TTUPLE) {
|
||||
let idx: i32 = fldnumidx(fld);
|
||||
if (idx >= 0) {
|
||||
let tp: *node = tn.list;
|
||||
let foff: i32 = 0;
|
||||
let i: i32 = 0;
|
||||
for (i < idx) {
|
||||
if (tp == nil) { i = idx; }
|
||||
else {
|
||||
foff += slotsize(c, tp);
|
||||
tp = tp.next;
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
if (tp != nil) {
|
||||
if (isstrtyperaw(tp)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((lc.off + foff + 0): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((lc.off + foff + 8): i64);
|
||||
emitline("(BP), BX\n");
|
||||
return;
|
||||
};
|
||||
let sz: i32 = slotsize(c, tp);
|
||||
let op: str = "MOVQ";
|
||||
if (sz == 1) { op = "MOVZBQ"; }
|
||||
else { if (sz == 4) { op = "MOVL"; }; };
|
||||
emitline("\t");
|
||||
emitline(op);
|
||||
emitline("\t");
|
||||
emitoff((lc.off + foff): i64);
|
||||
emitline("(BP), AX\n");
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
// str/slice pseudo-fields .ptr/.len/.cap on a
|
||||
// direct local: load at slot+delta.
|
||||
let delta: i32 = -1;
|
||||
@@ -1049,6 +1092,71 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// Chained `<expr>.field = v` where `<expr>` itself is a chain
|
||||
// of dots resolving to a *struct. Mirrors the C cgen branch
|
||||
// added to close trap 1 (cmd/w6c/cgen.c). Without this, only
|
||||
// `local.field = v` and `local.fieldptr.field = v` get wired
|
||||
// (the latter through the IDENT-base branch above) — chains
|
||||
// like `s.last.snext = sy` (lib/ww/sym.ww) silently emit no
|
||||
// store. Only plain `=` is wired here; chained compound on a
|
||||
// pointer-field hasn't surfaced.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_DOT) {
|
||||
let base: *node = lhs.lhs;
|
||||
let fld: str = lhs.str;
|
||||
if (base != nil) {
|
||||
if (base.kind == N_DOT) {
|
||||
let innert: *node = dotinnerstructptr(c, base);
|
||||
if (innert != nil) {
|
||||
let sname: str = innert.str;
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld)) {
|
||||
if (n.op == TK_ASSIGN) {
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
// str rhs: AX=ptr, BX=len.
|
||||
// Stash both, then load
|
||||
// the struct ptr into CX
|
||||
// and write both halves.
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, base);
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "CX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((fi.foff + 8): i64, "CX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, base);
|
||||
emitline("\tMOVQ\tAX, BX\n");
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
let sop: str = fieldstoreop(fi);
|
||||
emitline("\t");
|
||||
emitline(sop);
|
||||
emitline("\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "BX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
// Local-ident target — plain `=` and the simple compound
|
||||
// forms (+= -= *= /=); other compounds fall back to
|
||||
// "evaluate rhs, replace". Mirrors C cgen's IDENT-assign path.
|
||||
|
||||
Reference in New Issue
Block a user