wcc/cgen: #145 slice-copy-assign LHS s.arr[lo:hi]=bs — N_SLICE-LHS arm, runtime byte-copy loop, esz via type table (both stages)
Probe-first find for the path c2 appendlit (buf.buf[lo..hi]=bs): a slice-copy-assign into a struct-field array sub-range emitted ZERO code — silent NO-OP, both stages, both-wrong-identical (#263), so runtime is the only net. N_ASSIGN gains an N_SLICE-LHS arm (cgen.c + cgenexpr.ww slicebaseesz twin) reusing the N_SLICE-read base/esz cascade and copying (hi-lo)*esz bytes from rhs.ptr via a runtime loop (len is runtime; no REP/MOVSB). esz routed through the type table (rule 13; [N]u8->1). Hare len(bs)==hi-lo assert deferred to #149.
This commit is contained in:
@@ -4771,6 +4771,57 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
break;
|
||||
}
|
||||
case N_ASSIGN: {
|
||||
/* #145 (c1.5a): bulk slice-copy-assign into a range place
|
||||
* `s.arr[lo:hi] = bs` (LHS is N_SLICE). No legacy N_ASSIGN arm
|
||||
* catches N_SLICE (they gate INDEX/STAR/DOT/ident), so the
|
||||
* statement fell through to the scalar tail and emitted NOTHING
|
||||
* — a silent no-op, both stages, byte-id-green (#263-class).
|
||||
* Reuse the N_SLICE READ lowering: cgexpr(lhs) leaves AX = dst
|
||||
* ptr (base+lo*esz), BX = hi-lo (element count), CX = cap. The
|
||||
* element width is the SAME read-path esz (rule-13: chased base
|
||||
* element tinfo, [N]u8 -> 1); multiply BX by it for the byte
|
||||
* count, then a runtime-counted byte-granular copy from bs.ptr.
|
||||
* Byte loop because the length is RUNTIME — the #265/#268 memcpy
|
||||
* emitters are compile-time-sz unrolled and w6a has no REP/MOVSB.
|
||||
* Only plain `=`; a compound op on a range place is meaningless.
|
||||
*
|
||||
* Hare asserts len(bs)==hi-lo (ref/hare/path/stack.ha:72,
|
||||
* appendlit). We copy exactly hi-lo elems and do NOT runtime-
|
||||
* check len(bs). The length-equality assert is task #149
|
||||
* (rule-7: documented, not a c2 blocker — appendlit's lengths
|
||||
* are equal by construction). */
|
||||
if (n->op == TK_ASSIGN && n->lhs && n->lhs->kind == N_SLICE) {
|
||||
Node *sl = n->lhs;
|
||||
Node *sbase = sl->lhs;
|
||||
Type *sbu = type_chase_named(sbase ? sbase->type : NULL);
|
||||
int esz = (sbase && (sbase->kind == N_IDENT
|
||||
|| sbase->kind == N_DOT || sbase->kind == N_ARRLIT)
|
||||
&& sbu && sbu->sub) ? (int)sbu->sub->size : 1;
|
||||
cgexpr(c, sl, locals); /* AX=dst ptr, BX=hi-lo */
|
||||
if (esz > 1) {
|
||||
ins2(c, A_MOVQ, aimm(esz), areg(D_DX));
|
||||
ins2(c, A_IMULQ, areg(D_DX), areg(D_BX));
|
||||
}
|
||||
ins1(c, A_PUSHQ, areg(D_AX)); /* dst ptr */
|
||||
ins1(c, A_PUSHQ, areg(D_BX)); /* byte count */
|
||||
cgexpr(c, n->rhs, locals); /* AX=src ptr */
|
||||
ins2(c, A_MOVQ, areg(D_AX), areg(D_SI));
|
||||
ins1(c, A_POPQ, areg(D_CX)); /* byte count */
|
||||
ins1(c, A_POPQ, areg(D_DI)); /* dst ptr */
|
||||
char *top = mklabel(c, "scpy");
|
||||
char *end = mklabel(c, "scpe");
|
||||
label(c, top);
|
||||
ins2(c, A_CMPQ, aimm(0), areg(D_CX));
|
||||
ins1(c, A_JLE, abranch(end));
|
||||
ins2(c, A_MOVB, amem(D_SI, 0), areg(D_AX));
|
||||
ins2(c, A_MOVB, areg(D_AX), amem(D_DI, 0));
|
||||
ins2(c, A_ADDQ, aimm(1), areg(D_SI));
|
||||
ins2(c, A_ADDQ, aimm(1), areg(D_DI));
|
||||
ins2(c, A_SUBQ, aimm(1), areg(D_CX));
|
||||
ins1(c, A_JMP, abranch(top));
|
||||
label(c, end);
|
||||
break;
|
||||
}
|
||||
/* Discard lvalue `_ = expr;` — evaluate rhs for side effects,
|
||||
* write nothing. */
|
||||
if (n->lhs && n->lhs->kind == N_IDENT &&
|
||||
|
||||
Reference in New Issue
Block a user