cgen: store all eightbytes of a global/chained dot-field unwrap success (#16)
This commit is contained in:
@@ -5209,6 +5209,64 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
fatal("array-literal store at assignment "
|
||||
"unwired (task #32)");
|
||||
}
|
||||
/* #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: it gated !is_global
|
||||
* and its enclosing N_DOT arm requires an N_IDENT local base,
|
||||
* 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 destination
|
||||
* ADDRESS through cgplaceaddr (which resolves a global LEAQ root
|
||||
* and a chained deref+offset spine uniformly) 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 (size<=24, #12
|
||||
* scope); a float-bearing / over-cap success variant loud-stops
|
||||
* at the producer. Local/via-ptr single-dot stays on #12. */
|
||||
if (n->op == TK_ASSIGN && n->lhs && n->lhs->kind == N_DOT
|
||||
&& n->lhs->lhs
|
||||
&& n->rhs && (n->rhs->kind == N_TRYUNW
|
||||
|| n->rhs->kind == N_TRYPROP)) {
|
||||
Node *db = n->lhs->lhs;
|
||||
int chained = (db->kind == N_DOT);
|
||||
int globalbase = 0;
|
||||
if (db->kind == N_IDENT
|
||||
&& localfind(locals, db->str) == 0
|
||||
&& let_islet(db->str)) {
|
||||
Type *dbu = type_chase_named(db->type);
|
||||
if (dbu && dbu->kind == TY_STRUCT)
|
||||
globalbase = 1;
|
||||
}
|
||||
Type *fu = type_chase_named(n->lhs->type);
|
||||
if ((chained || globalbase) && fu
|
||||
&& fu->kind == TY_STRUCT
|
||||
&& (int)fu->size <= 24
|
||||
&& (fu->size % 8 == 0 || fu->size % 8 == 1
|
||||
|| fu->size % 8 == 2 || fu->size % 8 == 4)) {
|
||||
int ssz = (int)fu->size;
|
||||
if (!cgplaceaddr(c, n->lhs, D_BX, locals))
|
||||
fatal("#16: global/chained aggregate "
|
||||
"unwrap field dest unresolved "
|
||||
"(cgplaceaddr)");
|
||||
ins1(c, A_PUSHQ, areg(D_BX));
|
||||
cgexpr(c, n->rhs, locals);
|
||||
ins1(c, A_POPQ, areg(D_BX));
|
||||
int regs[3] = { D_AX, D_DX, D_CX };
|
||||
int full = ssz / 8;
|
||||
int tail = ssz % 8;
|
||||
for (int i = 0; i < full; i++)
|
||||
ins2(c, A_MOVQ, areg(regs[i]),
|
||||
amem(D_BX, i * 8));
|
||||
if (tail > 0) {
|
||||
int op = (tail == 4) ? A_MOVL
|
||||
: (tail == 2) ? A_MOVW : A_MOVB;
|
||||
ins2(c, op, areg(regs[full]),
|
||||
amem(D_BX, full * 8));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* p.x = v or p.x += v where p.x is a struct field
|
||||
* (direct or via *struct). For compound ops we read-modify-
|
||||
* write the field; for plain `=` we just write. The base
|
||||
|
||||
Reference in New Issue
Block a user