w6c: lower append() to rt_ensure + inline store (hare model)

This commit is contained in:
2026-05-11 17:02:32 +09:00
parent 5408160d49
commit 9e383b7ba0
4 changed files with 100 additions and 65 deletions

View File

@@ -1304,23 +1304,36 @@ cgexpr(Cg *c, Node *n, Local *locals)
if (n->lhs && n->lhs->kind == N_IDENT && n->lhs->str &&
strcmp(n->lhs->str, "append") == 0 && n->list &&
n->list->next) {
/* append(s, v1, v2, ...) — one CALL per item.
* append(s, items...) — runtime loop over items. */
/* append(s, v) lowering — Hare's rt::ensure model.
* ; AX = value
* ; PUSHQ AX ; save
* ; ADDQ $1, sn_off+8(BP) ; s.len += 1
* ; LEAQ sn_off(BP), DI ; arg1 = &s
* ; MOVQ esz, SI ; arg2 = membsz
* ; CALL rt_ensure(SB) ; may realloc s.ptr
* ; MOVQ sn_off+8(BP), CX ; CX = new len
* ; SUBQ $1, CX ; slot index
* ; [IMULQ esz, CX] ; byte offset (esz>1)
* ; MOVQ sn_off(BP), BX ; reread s.ptr
* ; ADDQ CX, BX ; BX = target
* ; POPQ AX ; v
* ; MOV* AX, (BX) ; store (MOVB / MOVQ)
*
* Spread form `append(s, items...)` runs this same body
* in a counted loop over items. */
Node *sn = n->list;
Type *st = sn->type;
Type *su = (st && st->kind == TY_NAMED) ? st->under : st;
int esz = (su && su->sub) ? (int)su->sub->size : 1;
const char *fn = (esz == 1) ? "appendu8" : "appendi64";
int sn_off = (sn->kind == N_IDENT)
? localfind(locals, sn->str) : 0;
int store_op = (esz == 1) ? A_MOVB : A_MOVQ;
for (Node *vn = sn->next; vn; vn = vn->next) {
if (vn->kind == N_SPREAD &&
vn->lhs && vn->lhs->kind == N_IDENT) {
/* iterate items; items_off is the
* spread-source slice's BP offset. */
int it_off = localfind(locals, vn->lhs->str);
int load_op = (esz == 1) ? A_MOVZBQ : A_MOVQ;
/* push counter on stack */
/* push counter (i) on stack */
ins2(c, A_SUBQ, aimm(8), areg(D_SP));
ins2(c, A_MOVQ, aimm(0), amem(D_SP, 0));
char *ll = mklabel(c, "spr_l");
@@ -1330,6 +1343,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
ins2(c, A_MOVQ, amem(D_BP, it_off + 8), areg(D_DX));
ins2(c, A_CMPQ, areg(D_DX), areg(D_CX));
ins1(c, A_JGE, abranch(le));
/* AX = items.ptr[i] */
ins2(c, A_MOVQ, amem(D_BP, it_off), areg(D_BX));
if (esz > 1) {
ins2(c, A_MOVQ, aimm(esz), areg(D_AX));
@@ -1337,11 +1351,23 @@ cgexpr(Cg *c, Node *n, Local *locals)
}
ins2(c, A_ADDQ, areg(D_CX), areg(D_BX));
ins2(c, load_op, amem(D_BX, 0), areg(D_AX));
/* ensure + store one element */
ins1(c, A_PUSHQ, areg(D_AX));
ins2(c, A_LEAQ, amem(D_BP, sn_off), areg(D_AX));
ins1(c, A_POPQ, areg(D_SI));
ins2(c, A_MOVQ, areg(D_AX), areg(D_DI));
ins1(c, A_CALL, masym(c, fn));
ins2(c, A_ADDQ, aimm(1), amem(D_BP, sn_off + 8));
ins2(c, A_LEAQ, amem(D_BP, sn_off), areg(D_DI));
ins2(c, A_MOVQ, aimm(esz), areg(D_SI));
ins1(c, A_CALL, masym(c, "rt_ensure"));
ins2(c, A_MOVQ, amem(D_BP, sn_off + 8), areg(D_CX));
ins2(c, A_SUBQ, aimm(1), areg(D_CX));
if (esz > 1) {
ins2(c, A_MOVQ, aimm(esz), areg(D_AX));
ins2(c, A_IMULQ, areg(D_AX), areg(D_CX));
}
ins2(c, A_MOVQ, amem(D_BP, sn_off), areg(D_BX));
ins2(c, A_ADDQ, areg(D_CX), areg(D_BX));
ins1(c, A_POPQ, areg(D_AX));
ins2(c, store_op, areg(D_AX), amem(D_BX, 0));
/* loop tail */
ins2(c, A_ADDQ, aimm(1), amem(D_SP, 0));
ins1(c, A_JMP, abranch(ll));
label(c, le);
@@ -1350,11 +1376,20 @@ cgexpr(Cg *c, Node *n, Local *locals)
}
cgexpr(c, vn, locals); /* val → AX */
ins1(c, A_PUSHQ, areg(D_AX));
if (sn->kind == N_IDENT)
ins2(c, A_LEAQ, amem(D_BP, sn_off), areg(D_AX));
ins1(c, A_POPQ, areg(D_SI));
ins2(c, A_MOVQ, areg(D_AX), areg(D_DI));
ins1(c, A_CALL, masym(c, fn));
ins2(c, A_ADDQ, aimm(1), amem(D_BP, sn_off + 8));
ins2(c, A_LEAQ, amem(D_BP, sn_off), areg(D_DI));
ins2(c, A_MOVQ, aimm(esz), areg(D_SI));
ins1(c, A_CALL, masym(c, "rt_ensure"));
ins2(c, A_MOVQ, amem(D_BP, sn_off + 8), areg(D_CX));
ins2(c, A_SUBQ, aimm(1), areg(D_CX));
if (esz > 1) {
ins2(c, A_MOVQ, aimm(esz), areg(D_AX));
ins2(c, A_IMULQ, areg(D_AX), areg(D_CX));
}
ins2(c, A_MOVQ, amem(D_BP, sn_off), areg(D_BX));
ins2(c, A_ADDQ, areg(D_CX), areg(D_BX));
ins1(c, A_POPQ, areg(D_AX));
ins2(c, store_op, areg(D_AX), amem(D_BX, 0));
}
break;
}