wcc+w6c+w6c_ww: delete() builtin — single-element slice removal (part of #35)
Hare's delete(xs[i]) (ref/harec/src/check.c:1981-2027): checker accepts an N_INDEX over a slice-typed base, stamps void; loud-rejects the range form delete(xs[i..j]) (stays filed on #35 — regex fold-2b's consumers are all single-element), non-index operands, array bases, wrong arity. Lowering (both stages, converged byte-identical by construction): ascending word-copy loop shifts [i+1..len) down one esz stride, then hdr.len -= 1; cap unchanged. The move is a same-type whole-stride byte copy — src and dst are elements of the SAME slice, so no boxing exists for any element kind; one loop serves scalar/narrow/str/struct/tagged. esz off the STAMPED base type (#34/#48 discipline). Base shapes: local slice ident (LEAQ) and deref-of-local ptr-to-slice (MOVQ — the fold-2b delete_thread shape); others rule-7 loud-stop. test/804: 38 fixtures — first/middle/last/to-empty, esz 1/4/8/24/56 (MOVB/MOVL tails + 7-qword tagged), cap-unchanged, (*threads)[i], 4 checker reject rows; every accept row cs==ww asm byte-id.
This commit is contained in:
113
cmd/w6c/cgen.c
113
cmd/w6c/cgen.c
@@ -6252,6 +6252,119 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
cgexpr(c, n->list, locals);
|
||||
break;
|
||||
}
|
||||
if (n->lhs && n->lhs->kind == N_IDENT && n->lhs->str &&
|
||||
strcmp(n->lhs->str, "delete") == 0 && n->list &&
|
||||
n->list->next == NULL) {
|
||||
/* delete(xs[i]) — single-element slice removal, the
|
||||
* delete-half of #35. Shift [i+1..len) down one
|
||||
* stride, len -= 1, cap unchanged. The move is a
|
||||
* same-type whole-stride byte copy: src and dst are
|
||||
* elements of the SAME slice, so no boxing/coercion
|
||||
* exists for any element kind (str/slice 24B header,
|
||||
* tagged box, struct body) — one word-copy loop
|
||||
* serves all kinds, unlike append's value-store
|
||||
* dispatch (#34) which boxes from a foreign source.
|
||||
* Ascending j keeps src (j+1) ahead of dst (j), the
|
||||
* safe memmove-down direction. Bounds are implicit
|
||||
* (no index check, matching the rest of cgen).
|
||||
*
|
||||
* ; AX = i (cgexpr)
|
||||
* ; PUSHQ AX ; 8(SP) = j counter
|
||||
* ; LEAQ/MOVQ off(BP), AX ; &hdr (ident / *p base)
|
||||
* ; PUSHQ AX ; (SP) = &hdr
|
||||
* ; del_l:
|
||||
* ; MOVQ (SP), DX ; MOVQ 8(SP), CX
|
||||
* ; MOVQ 8(DX), BX ; SUBQ $1, BX
|
||||
* ; CMPQ BX, CX ; JGE del_e ; j >= len-1
|
||||
* ; [IMULQ esz, CX]
|
||||
* ; MOVQ (DX), BX ; ADDQ CX, BX ; BX = dst
|
||||
* ; word-copy esz bytes esz(BX) -> (BX)
|
||||
* ; ADDQ $1, 8(SP) ; JMP del_l
|
||||
* ; del_e:
|
||||
* ; MOVQ (SP), DX ; SUBQ $1, 8(DX)
|
||||
* ; ADDQ $16, SP */
|
||||
Node *d = n->list; /* N_INDEX, checker-validated */
|
||||
Node *base = d->lhs;
|
||||
Type *su = type_chase_named(base->type);
|
||||
Type *esub = (su && su->sub)
|
||||
? type_chase_named(su->sub) : NULL;
|
||||
int esz = esub ? (int)esub->size : 0;
|
||||
if (esz <= 0)
|
||||
fatal("#35: delete() element size unresolved "
|
||||
"(rule-7)");
|
||||
int hdr_lea = 0;
|
||||
int hdr_off = 0;
|
||||
int hdr_ok = 0;
|
||||
if (base->kind == N_IDENT &&
|
||||
localfind(locals, base->str) != 0) {
|
||||
hdr_lea = 1;
|
||||
hdr_off = localfind(locals, base->str);
|
||||
hdr_ok = 1;
|
||||
}
|
||||
/* (*p)[i]: the header lives behind a local
|
||||
* ptr-to-slice — the regex fold-2b delete_thread
|
||||
* shape (threads: *[]thread). */
|
||||
if (!hdr_ok && base->kind == N_UN &&
|
||||
base->op == TK_STAR && base->lhs &&
|
||||
base->lhs->kind == N_IDENT &&
|
||||
localfind(locals, base->lhs->str) != 0) {
|
||||
hdr_off = localfind(locals, base->lhs->str);
|
||||
hdr_ok = 1;
|
||||
}
|
||||
if (!hdr_ok)
|
||||
fatal("#35: delete() base shape unsupported "
|
||||
"(rule-7: local slice ident or "
|
||||
"deref-of-local only)");
|
||||
cgexpr(c, d->rhs, locals); /* AX = i */
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
if (hdr_lea)
|
||||
ins2(c, A_LEAQ, amem(D_BP, hdr_off), areg(D_AX));
|
||||
else
|
||||
ins2(c, A_MOVQ, amem(D_BP, hdr_off), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
char *dll = mklabel(c, "del_l");
|
||||
char *dle = mklabel(c, "del_e");
|
||||
label(c, dll);
|
||||
ins2(c, A_MOVQ, amem(D_SP, 0), areg(D_DX));
|
||||
ins2(c, A_MOVQ, amem(D_SP, 8), areg(D_CX));
|
||||
ins2(c, A_MOVQ, amem(D_DX, 8), areg(D_BX));
|
||||
ins2(c, A_SUBQ, aimm(1), areg(D_BX));
|
||||
ins2(c, A_CMPQ, areg(D_BX), areg(D_CX));
|
||||
ins1(c, A_JGE, abranch(dle));
|
||||
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_DX, 0), areg(D_BX));
|
||||
ins2(c, A_ADDQ, areg(D_CX), areg(D_BX));
|
||||
int dk = 0;
|
||||
for (; dk + 8 <= esz; dk += 8) {
|
||||
ins2(c, A_MOVQ, amem(D_BX, esz + dk), areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_BX, dk));
|
||||
}
|
||||
if (dk + 4 <= esz) {
|
||||
ins2(c, A_MOVL, amem(D_BX, esz + dk), areg(D_AX));
|
||||
ins2(c, A_MOVL, areg(D_AX), amem(D_BX, dk));
|
||||
dk += 4;
|
||||
}
|
||||
if (dk + 2 <= esz) {
|
||||
ins2(c, A_MOVW, amem(D_BX, esz + dk), areg(D_AX));
|
||||
ins2(c, A_MOVW, areg(D_AX), amem(D_BX, dk));
|
||||
dk += 2;
|
||||
}
|
||||
if (dk + 1 <= esz) {
|
||||
ins2(c, A_MOVB, amem(D_BX, esz + dk), areg(D_AX));
|
||||
ins2(c, A_MOVB, areg(D_AX), amem(D_BX, dk));
|
||||
dk += 1;
|
||||
}
|
||||
ins2(c, A_ADDQ, aimm(1), amem(D_SP, 8));
|
||||
ins1(c, A_JMP, abranch(dll));
|
||||
label(c, dle);
|
||||
ins2(c, A_MOVQ, amem(D_SP, 0), areg(D_DX));
|
||||
ins2(c, A_SUBQ, aimm(1), amem(D_DX, 8));
|
||||
ins2(c, A_ADDQ, aimm(16), areg(D_SP));
|
||||
break;
|
||||
}
|
||||
if (n->lhs && n->lhs->kind == N_IDENT &&
|
||||
n->lhs->type == ty_err &&
|
||||
n->lhs->str && strcmp(n->lhs->str, "alloc") == 0 &&
|
||||
|
||||
@@ -1435,6 +1435,37 @@ cexpr(Checker *c, Node *n)
|
||||
n->lhs->type = ty_err;
|
||||
return n->type;
|
||||
}
|
||||
/* delete(xs[i]) — single-element slice removal, the
|
||||
* delete-half of #35 (insert() stays deferred). harec
|
||||
* ref/harec/src/check.c:1981-2027 also accepts the range
|
||||
* form delete(xs[i..j]) (EXPR_SLICE) — out of scope here
|
||||
* (regex fold-2b's consumers are all single-element);
|
||||
* loud-rejected below, the range form stays filed on #35. */
|
||||
if (n->lhs && n->lhs->kind == N_IDENT &&
|
||||
n->lhs->str && strcmp(n->lhs->str, "delete") == 0) {
|
||||
Node *d = n->list;
|
||||
if (d == NULL || d->next != NULL)
|
||||
err(c, n->pos, "delete: takes exactly one argument");
|
||||
if (d != NULL) {
|
||||
(void)cexpr(c, d);
|
||||
if (d->kind == N_SLICE)
|
||||
err(c, n->pos, "delete: range form delete(xs[i..j]) unimplemented (task #35)");
|
||||
else if (d->kind != N_INDEX)
|
||||
err(c, n->pos, "delete: operand must be an indexing expression xs[i]");
|
||||
else {
|
||||
Type *bt = d->lhs ? d->lhs->type : NULL;
|
||||
while (bt && bt->kind == TY_NAMED)
|
||||
bt = bt->under;
|
||||
/* harec check.c:2024 wording; a
|
||||
* fixed-size [N]T base lands here. */
|
||||
if (bt == NULL || bt->kind != TY_SLICE)
|
||||
err(c, n->pos, "delete must operate on a slice");
|
||||
}
|
||||
}
|
||||
n->type = ty_void;
|
||||
n->lhs->type = ty_err;
|
||||
return n->type;
|
||||
}
|
||||
/* assert(cond[, msg]) / abort([msg]) — runtime checks that
|
||||
* call into rt_abort. msg must be a str when present.
|
||||
* Only treated as builtins when no user symbol shadows the
|
||||
|
||||
Reference in New Issue
Block a user