w6c: lower append() to rt_ensure + inline store (hare model)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user