w6c+selfhost: cgen N_DOT N_INDEX-lhs branch (closes #8)

cstage cmd/w6c/cgen.c gained the missing N_DOT N_INDEX-lhs branch.
Covers both [N]*Struct and [N]Struct via fldloadop. wwstage already
handled [N]*Struct since 7c75dd2; refactored to mirror cstage exactly
and added [N]Struct. The spill workaround in dotchainresolve stays
(Pike rule); task #14 retires it as a follow-up.

Wwstage cgassign N_DOT(N_INDEX,...) silent store-drop discovered in
scope, filed as task #16.
This commit is contained in:
2026-05-13 23:45:35 +09:00
parent d053560b80
commit 9ef9bef340
7 changed files with 592 additions and 148 deletions

View File

@@ -4253,6 +4253,98 @@ cgexpr(Cg *c, Node *n, Local *locals)
}
}
}
/* `arr[i].field` — element-then-field through a `[N]*S` /
* `[N]S` (and slice/`*[N]S`) base. One branch covers both
* shapes: compute `&arr[i]` into BX, then either deref
* (`*Struct` element) or move-to-AX (value `Struct` element),
* so the leaf load is `(field.offset)(AX)` either way.
* Bypasses cgindex deliberately — cgindex's final MOVQ
* would truncate a value-struct element to 8 bytes. Mirrors
* selfhost/cmd/wcc/cgenexpr.ww's cgdot N_INDEX-lhs branch. */
if (n->lhs && n->lhs->kind == N_INDEX && n->lhs->lhs
&& n->lhs->lhs->kind == N_IDENT) {
Node *idxbase = n->lhs->lhs;
Type *elemt = n->lhs->type;
Type *elemu = (elemt && elemt->kind == TY_NAMED)
? elemt->under : elemt;
Type *struct_t = NULL;
int viaptr = 0;
if (elemu && elemu->kind == TY_PTR) {
Type *inner = elemu->sub;
if (inner && inner->kind == TY_NAMED)
inner = inner->under;
if (inner && inner->kind == TY_STRUCT) {
struct_t = inner;
viaptr = 1;
}
} else if (elemu && elemu->kind == TY_STRUCT) {
struct_t = elemu;
}
if (struct_t) {
Tfield *f = NULL;
for (Tfield *fl = struct_t->fields; fl; fl = fl->next)
if (strcmp(fl->name, n->str) == 0)
{ f = fl; break; }
Type *bt = idxbase->type;
Type *bu = (bt && bt->kind == TY_NAMED)
? bt->under : bt;
int is_arr = bu && bu->kind == TY_ARRAY;
int is_sl = bu && bu->kind == TY_SLICE;
int is_ptr = bu && bu->kind == TY_PTR;
int off = localfind(locals, idxbase->str);
if (f != NULL && (is_arr || is_sl || is_ptr)
&& off != 0) {
int esz = (int)elemt->size;
cgexpr(c, n->lhs->rhs, locals);
if (esz > 1) {
ins2(c, A_MOVQ, aimm(esz),
areg(D_CX));
ins2(c, A_IMULQ, areg(D_CX),
areg(D_AX));
}
if (is_arr)
ins2(c, A_LEAQ,
amem(D_BP, off), areg(D_BX));
else
ins2(c, A_MOVQ,
amem(D_BP, off), areg(D_BX));
ins2(c, A_ADDQ, areg(D_AX), areg(D_BX));
if (viaptr)
ins2(c, A_MOVQ,
amem(D_BX, 0), areg(D_AX));
else
ins2(c, A_MOVQ, areg(D_BX),
areg(D_AX));
int foff = (int)f->offset;
Type *ft = f->type;
Type *fu = (ft && ft->kind == TY_NAMED)
? ft->under : ft;
if (fu && fu->kind == TY_STR) {
ins2(c, A_MOVQ,
amem(D_AX, foff + 8),
areg(D_BX));
ins2(c, A_MOVQ,
amem(D_AX, foff + 0),
areg(D_AX));
goto dot_done;
}
int g_isf32 = 0;
if (fld_isfloat(ft, &g_isf32)) {
int mov = g_isf32
? A_MOVSS : A_MOVSD;
ins2(c, mov,
amem(D_AX, foff),
areg(D_X0));
goto dot_done;
}
int fsz = (int)(ft ? ft->size : 8);
int op = fldloadop(ft, fsz);
ins2(c, op, amem(D_AX, foff),
areg(D_AX));
goto dot_done;
}
}
}
/* Nested module-qualified field where the chain didn't fold to
* a known shape (typical when w6c runs on a single file with
* `use mod;` but no driver concatenation — the body's enum /