w6c+selfhost: cgen *T-rooted chained N_DOT (closes #22)
Spine walker now accepts *T root at the last hop (cur->lhs->kind == N_IDENT, pu->kind == TY_PTR), substitutes pointee struct, emits MOVQ off(BP), CX before offset arithmetic. Symmetric in N_DOT and N_ASSIGN. Distinct gate from existing mid-chain *T-field branch (cgen.c:4615) — no shadow. Unblocks task #18 (bufio writer first-field embed). Pre-existing *T-field mid-chain path unchanged.
This commit is contained in:
114
cmd/w6c/cgen.c
114
cmd/w6c/cgen.c
@@ -2400,6 +2400,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
&& n->lhs->lhs->kind == N_DOT && n->op == TK_ASSIGN) {
|
||||
struct { Type *pu; const char *name; } steps[16];
|
||||
int nsteps = 0;
|
||||
int ptr_root = 0;
|
||||
Node *cur = n->lhs;
|
||||
int abort = 0;
|
||||
while (cur && cur->kind == N_DOT && cur->lhs) {
|
||||
@@ -2410,7 +2411,23 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (cur == n->lhs && (pu->kind == TY_SLICE
|
||||
|| pu->kind == TY_STR)) {
|
||||
/* leaf pseudo-field on slice/str header */
|
||||
} else if (pu->kind != TY_STRUCT) {
|
||||
} else if (pu->kind == TY_STRUCT) {
|
||||
/* value-struct hop */
|
||||
} else if (pu->kind == TY_PTR && pu->sub
|
||||
&& cur->lhs->kind == N_IDENT) {
|
||||
/* `*T` root: dereference at emit time;
|
||||
* walk through pointee struct fields.
|
||||
* Last-hop only (root is a bare ident). */
|
||||
Type *sub = (pu->sub->kind == TY_NAMED)
|
||||
? pu->sub->under : pu->sub;
|
||||
if (sub && sub->kind == TY_STRUCT) {
|
||||
pu = sub;
|
||||
ptr_root = 1;
|
||||
} else {
|
||||
abort = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
abort = 1;
|
||||
break;
|
||||
}
|
||||
@@ -2449,7 +2466,6 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
if (ok) {
|
||||
int root_off = localfind(locals, cur->str);
|
||||
int base_reg = D_BP;
|
||||
int base_disp = root_off;
|
||||
int is_global = 0;
|
||||
int root_resolved = (root_off != 0);
|
||||
@@ -2458,16 +2474,26 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
is_global = 1;
|
||||
}
|
||||
if (root_resolved) {
|
||||
/* `*T` root and global both store via CX as
|
||||
* the base register; only the loader differs
|
||||
* (LEAQ name(SB) vs MOVQ off(BP)). Compute it
|
||||
* AFTER cgexpr(rhs) so AX/BX/X0 stay intact. */
|
||||
int via_cx = is_global || ptr_root;
|
||||
if (slice_delta >= 0) {
|
||||
/* slice/str pseudo-field store. .ptr writes
|
||||
* 8 bytes; .len / .cap write 8 bytes each
|
||||
* (matches the existing N_IDENT pseudo-
|
||||
* field branch). */
|
||||
cgexpr(c, n->rhs, locals);
|
||||
if (is_global) {
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, cur->str),
|
||||
areg(D_CX));
|
||||
if (via_cx) {
|
||||
if (ptr_root)
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, base_disp),
|
||||
areg(D_CX));
|
||||
else
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, cur->str),
|
||||
areg(D_CX));
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_CX, total_off + slice_delta));
|
||||
} else {
|
||||
@@ -2484,10 +2510,15 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
int store_op = fldstoreop(leaf_type, fsz);
|
||||
if (fu && fu->kind == TY_STR) {
|
||||
cgexpr(c, n->rhs, locals);
|
||||
if (is_global) {
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, cur->str),
|
||||
areg(D_CX));
|
||||
if (via_cx) {
|
||||
if (ptr_root)
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, base_disp),
|
||||
areg(D_CX));
|
||||
else
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, cur->str),
|
||||
areg(D_CX));
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_CX, total_off + 0));
|
||||
ins2(c, A_MOVQ, areg(D_BX),
|
||||
@@ -2504,10 +2535,15 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (fld_isfloat(leaf_type, &sf32)) {
|
||||
int mov = sf32 ? A_MOVSS : A_MOVSD;
|
||||
cgexpr(c, n->rhs, locals);
|
||||
if (is_global) {
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, cur->str),
|
||||
areg(D_CX));
|
||||
if (via_cx) {
|
||||
if (ptr_root)
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, base_disp),
|
||||
areg(D_CX));
|
||||
else
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, cur->str),
|
||||
areg(D_CX));
|
||||
ins2(c, mov, areg(D_X0),
|
||||
amem(D_CX, total_off));
|
||||
} else {
|
||||
@@ -2517,10 +2553,15 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
break;
|
||||
}
|
||||
cgexpr(c, n->rhs, locals);
|
||||
if (is_global) {
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, cur->str),
|
||||
areg(D_CX));
|
||||
if (via_cx) {
|
||||
if (ptr_root)
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, base_disp),
|
||||
areg(D_CX));
|
||||
else
|
||||
ins2(c, A_LEAQ,
|
||||
masym(c, cur->str),
|
||||
areg(D_CX));
|
||||
ins2(c, store_op, areg(D_AX),
|
||||
amem(D_CX, total_off));
|
||||
} else {
|
||||
@@ -4193,6 +4234,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (leaf_is_pseudo || leaf_in_struct) {
|
||||
struct { Type *pu; const char *name; } steps[16];
|
||||
int nsteps = 0;
|
||||
int ptr_root = 0;
|
||||
Node *cur = n;
|
||||
int abort = 0;
|
||||
while (cur && cur->kind == N_DOT && cur->lhs) {
|
||||
@@ -4203,7 +4245,26 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (cur == n && (pu->kind == TY_SLICE
|
||||
|| pu->kind == TY_STR)) {
|
||||
/* leaf pseudo on slice/str header */
|
||||
} else if (pu->kind != TY_STRUCT) {
|
||||
} else if (pu->kind == TY_STRUCT) {
|
||||
/* value-struct hop */
|
||||
} else if (pu->kind == TY_PTR && pu->sub
|
||||
&& cur->lhs->kind == N_IDENT) {
|
||||
/* `*T` root: dereference once at emit
|
||||
* time, then walk offsets through the
|
||||
* pointee. Only at the last hop (root
|
||||
* is a bare ident) — `*T`-field mid-
|
||||
* chain keeps its cgexpr-based pointer-
|
||||
* field branch further down. */
|
||||
Type *sub = (pu->sub->kind == TY_NAMED)
|
||||
? pu->sub->under : pu->sub;
|
||||
if (sub && sub->kind == TY_STRUCT) {
|
||||
pu = sub;
|
||||
ptr_root = 1;
|
||||
} else {
|
||||
abort = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
abort = 1;
|
||||
break;
|
||||
}
|
||||
@@ -4252,6 +4313,21 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
base_disp = 0;
|
||||
root_resolved = 1;
|
||||
}
|
||||
if (root_resolved && ptr_root) {
|
||||
/* `*T` root: load the pointer value
|
||||
* once; field accesses then index at
|
||||
* total_off off the pointer. */
|
||||
if (base_reg == D_BP) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, base_disp),
|
||||
areg(D_CX));
|
||||
} else {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_CX, 0), areg(D_CX));
|
||||
}
|
||||
base_reg = D_CX;
|
||||
base_disp = 0;
|
||||
}
|
||||
if (root_resolved) {
|
||||
if (slice_delta >= 0) {
|
||||
ins2(c, A_MOVQ,
|
||||
|
||||
Reference in New Issue
Block a user