cgen: store all eightbytes of a global/chained dot-field unwrap success (#16)
This commit is contained in:
@@ -8353,6 +8353,86 @@ fn cgcall(c: *cgen, n: *syntax.node) void = {
|
||||
|
||||
fn cgassign(c: *cgen, n: *syntax.node) void = {
|
||||
let lhs: *syntax.node = n.lhs;
|
||||
// #16: a single-dot aggregate-field unwrap store whose base is a
|
||||
// module-GLOBAL value-struct (`g.f = mk()!`) or a CHAINED struct
|
||||
// field (`o.m.f = mk()!`). The #12 single-dot arm covered only a
|
||||
// LOCAL / via-ptr base (its enclosing block requires localfindnode
|
||||
// != nil), so the global case fell to the generic single-word store
|
||||
// (DROPPED w1/w2) and the chained case never reached any field arm
|
||||
// (SILENT both-stage, byte-id blind). Route the dest ADDRESS through
|
||||
// cgplaceaddr (global LEAQ root + chained deref+offset spine) and
|
||||
// feed the SAME {AX,DX,CX} producer-shift materialise. cgplaceaddr
|
||||
// clobbers AX/CX, so it runs BEFORE cgexpr(rhs) and the address is
|
||||
// saved across the call. In-cap struct field only (#12 scope);
|
||||
// float/over-cap loud-stop at the producer. Local/via-ptr single-dot
|
||||
// stays on the #12 arm. Mirrors cstage cgen.c N_ASSIGN #16 arm.
|
||||
if (lhs != nil) { if (lhs.kind == syntax.nkind.N_DOT
|
||||
&& lhs.lhs != nil && n.op == syntax.tkind.TK_ASSIGN
|
||||
&& n.rhs != nil
|
||||
&& (n.rhs.kind == syntax.nkind.N_TRYUNW
|
||||
|| n.rhs.kind == syntax.nkind.N_TRYPROP)) {
|
||||
let db: *syntax.node = lhs.lhs;
|
||||
let chained: bool = db.kind == syntax.nkind.N_DOT;
|
||||
let globalbase: bool = false;
|
||||
if (db.kind == syntax.nkind.N_IDENT) {
|
||||
if (localfindnode(c, db.str) == nil) {
|
||||
if (isletvar(c, db.str)) {
|
||||
let dbu: *syntax.tinfo = tichase(db.type_: *syntax.tinfo);
|
||||
if (dbu != nil) { if (dbu.kind == syntax.tykind.TY_STRUCT) {
|
||||
globalbase = true;
|
||||
}; };
|
||||
};
|
||||
};
|
||||
};
|
||||
if (chained || globalbase) {
|
||||
let fu: *syntax.tinfo = tichase(lhs.type_: *syntax.tinfo);
|
||||
if (fu != nil) { if (fu.kind == syntax.tykind.TY_STRUCT) {
|
||||
let ssz: i32 = fu.size: i32;
|
||||
if (ssz <= 24) {
|
||||
let tlm: i32 = ssz - (ssz / 8) * 8;
|
||||
if (tlm == 0 || tlm == 1 || tlm == 2 || tlm == 4) {
|
||||
if (!cgplaceaddr(c, lhs, "BX")) {
|
||||
let m16: str = "#16: global/chained aggregate unwrap field dest unresolved (cgplaceaddr)\n";
|
||||
os.write(2, m16.ptr, m16.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
let full: i32 = ssz / 8;
|
||||
let i: i32 = 0;
|
||||
for (i < full) {
|
||||
let reg: str = "AX";
|
||||
if (i == 1) { reg = "DX"; };
|
||||
if (i == 2) { reg = "CX"; };
|
||||
emitline("\tMOVQ\t");
|
||||
emitline(reg);
|
||||
emitline(", ");
|
||||
emitdispreg((i * 8): i64, "BX");
|
||||
emitline("\n");
|
||||
i += 1;
|
||||
};
|
||||
if (tlm > 0) {
|
||||
let top: str = "MOVB";
|
||||
if (tlm == 4) { top = "MOVL"; };
|
||||
if (tlm == 2) { top = "MOVW"; };
|
||||
let treg: str = "AX";
|
||||
if (full == 1) { treg = "DX"; };
|
||||
if (full == 2) { treg = "CX"; };
|
||||
emitline("\t");
|
||||
emitline(top);
|
||||
emitline("\t");
|
||||
emitline(treg);
|
||||
emitline(", ");
|
||||
emitdispreg((full * 8): i64, "BX");
|
||||
emitline("\n");
|
||||
};
|
||||
return;
|
||||
};
|
||||
};
|
||||
}; };
|
||||
};
|
||||
}; };
|
||||
// #145 (c1.5a): bulk slice-copy-assign `s.arr[lo:hi] = bs` (LHS is
|
||||
// N_SLICE). No legacy cgassign arm catches N_SLICE — the statement
|
||||
// silently emitted nothing (both stages, byte-id-green, #263-class).
|
||||
|
||||
Reference in New Issue
Block a user