cgen: merge byte-identical str+slice cgassign arms onto kind-gates -- Phase 2 C4.4
Post the str->24B lifts, cgassign had SEPARATE str and slice arms emitting byte-identical 3-word {ptr,len,cap} code. Collapse each identical pair into ONE kind-gated arm (rule 12, sea-of-stars; removes a drift hazard) -- the structural str==[]u8 unification, byte-id-NEUTRAL (each stage's emission unchanged for both str and slice inputs). Pairs: field store s.f=v + ident reassign name=v. cstage gates on the EXACT predicate union (raw kind==TY_STR OR'd with TY_SLICE -- NOT type_isstr, which would also match TY_UNTYPED_STR); ww on isstrtype||isslicetype and letvarisstr||letvarisslice (ww local field/reassign were already merged). Mirrors the in-tree deep-value-chain precedent (cstage 3274). str-only arms with no slice pair (arr[i].field=/chained, G1/G2) untouched.
Verified per-stage PRE==POST byte-identical (focused 5-path fixture + 4 large real combined.ww inputs, both stages); the 5 pairs were byte-identical pre-merge. main.combined.ww regenerated via the canonical make path (md5-stable). A pre-existing global-slice-field-store divergence (g.sl=b: cstage 3-word, wwstage 1-word) surfaced during review -- filed (#26/#10), NOT a C4.4 concern (PRE==POST).
This commit is contained in:
@@ -2587,42 +2587,18 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
int is_global = (boff == 0 && !via_ptr
|
int is_global = (boff == 0 && !via_ptr
|
||||||
&& let_islet(base->str));
|
&& let_islet(base->str));
|
||||||
int foff = (int)f->offset;
|
int foff = (int)f->offset;
|
||||||
/* str IS []u8: rhs cgexpr leaves (AX=ptr, BX=len,
|
|
||||||
* CX=cap); store all three at field+0/+8/+16,
|
|
||||||
* mirroring the slice-field arm below. Address
|
|
||||||
* scratch must dodge CX (holds cap), so via_ptr/
|
|
||||||
* is_global stage the struct base in DX (#1/Phase 3).
|
|
||||||
* Only plain `=` is wired; compound on a str field is
|
|
||||||
* not meaningful. */
|
|
||||||
Type *str_fu = (f->type && f->type->kind == TY_NAMED)
|
Type *str_fu = (f->type && f->type->kind == TY_NAMED)
|
||||||
? f->type->under : f->type;
|
? f->type->under : f->type;
|
||||||
if (n->op == TK_ASSIGN && str_fu && str_fu->kind == TY_STR) {
|
/* str/slice field: str IS []u8, so both store the full
|
||||||
cgexpr(c, n->rhs, locals);
|
* 3-word {ptr,len,cap} that rhs cgexpr leaves in
|
||||||
if (via_ptr) {
|
* (AX,BX,CX) at field+0/+8/+16. Address scratch must
|
||||||
ins2(c, A_MOVQ, amem(D_BP, boff), areg(D_DX));
|
* dodge CX (holds cap), so via_ptr/is_global stage the
|
||||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_DX, foff + 0));
|
* struct base in DX (#1/Phase 3). Without this the
|
||||||
ins2(c, A_MOVQ, areg(D_BX), amem(D_DX, foff + 8));
|
|
||||||
ins2(c, A_MOVQ, areg(D_CX), amem(D_DX, foff + 16));
|
|
||||||
} else if (is_global) {
|
|
||||||
ins2(c, A_LEAQ, masym(c, base->str), areg(D_DX));
|
|
||||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_DX, foff + 0));
|
|
||||||
ins2(c, A_MOVQ, areg(D_BX), amem(D_DX, foff + 8));
|
|
||||||
ins2(c, A_MOVQ, areg(D_CX), amem(D_DX, foff + 16));
|
|
||||||
} else {
|
|
||||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, boff + foff + 0));
|
|
||||||
ins2(c, A_MOVQ, areg(D_BX), amem(D_BP, boff + foff + 8));
|
|
||||||
ins2(c, A_MOVQ, areg(D_CX), amem(D_BP, boff + foff + 16));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* slice-typed field: rhs cgexpr leaves (AX=ptr,
|
|
||||||
* BX=len, CX=cap); store all three at
|
|
||||||
* field+0/+8/+16. Address scratch must dodge CX
|
|
||||||
* (holds cap), so via_ptr/is_global stage the
|
|
||||||
* struct base in DX. Without this branch the
|
|
||||||
* generic store_op below writes only AX, silently
|
* generic store_op below writes only AX, silently
|
||||||
* dropping .len and .cap. */
|
* dropping .len/.cap. Only plain `=` is wired; compound
|
||||||
if (n->op == TK_ASSIGN && str_fu && str_fu->kind == TY_SLICE) {
|
* on a str/slice field is not meaningful. */
|
||||||
|
if (n->op == TK_ASSIGN && str_fu
|
||||||
|
&& (str_fu->kind == TY_SLICE || str_fu->kind == TY_STR)) {
|
||||||
cgexpr(c, n->rhs, locals);
|
cgexpr(c, n->rhs, locals);
|
||||||
if (via_ptr) {
|
if (via_ptr) {
|
||||||
ins2(c, A_MOVQ, amem(D_BP, boff), areg(D_DX));
|
ins2(c, A_MOVQ, amem(D_BP, boff), areg(D_DX));
|
||||||
@@ -3850,41 +3826,18 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Plain `name = strexpr;` for a str-typed local. str IS []u8:
|
/* `name = expr;` reassignment of a str/slice/struct local or
|
||||||
* cgexpr leaves (AX=ptr, BX=len, CX=cap); store all three at
|
* top-level let. */
|
||||||
* off+0/+8/+16, identical to the slice arm below. Top-level
|
|
||||||
* str globals go through &name(SB) → DI scratch (CX holds cap)
|
|
||||||
* since the asm has no `name+8(SB)` operand form (#1/Phase 3). */
|
|
||||||
if (n->lhs && n->lhs->kind == N_IDENT && n->op == TK_ASSIGN
|
if (n->lhs && n->lhs->kind == N_IDENT && n->op == TK_ASSIGN
|
||||||
&& n->lhs->type) {
|
&& n->lhs->type) {
|
||||||
Type *lt = n->lhs->type;
|
Type *lt = n->lhs->type;
|
||||||
Type *lu = (lt && lt->kind == TY_NAMED) ? lt->under : lt;
|
Type *lu = (lt && lt->kind == TY_NAMED) ? lt->under : lt;
|
||||||
if (lu && lu->kind == TY_STR) {
|
/* str/slice local/let: str IS []u8, so both store the full
|
||||||
int off = localfind(locals, n->lhs->str);
|
* 3-word {ptr,len,cap} from (AX,BX,CX) at off+0/+8/+16
|
||||||
if (off != 0) {
|
* (local) or via &name(SB) → DI scratch (global — CX holds
|
||||||
cgexpr(c, n->rhs, locals);
|
* the cap, and the asm has no `name+8(SB)` operand form, so
|
||||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, off + 0));
|
* a different address register is needed) (#1/Phase 3). */
|
||||||
ins2(c, A_MOVQ, areg(D_BX), amem(D_BP, off + 8));
|
if (lu && (lu->kind == TY_SLICE || lu->kind == TY_STR)) {
|
||||||
ins2(c, A_MOVQ, areg(D_CX), amem(D_BP, off + 16));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (let_islet(n->lhs->str)) {
|
|
||||||
cgexpr(c, n->rhs, locals);
|
|
||||||
ins2(c, A_MOVQ, areg(D_CX), areg(D_DI));
|
|
||||||
ins2(c, A_LEAQ, masym(c, n->lhs->str),
|
|
||||||
areg(D_CX));
|
|
||||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_CX, 0));
|
|
||||||
ins2(c, A_MOVQ, areg(D_BX), amem(D_CX, 8));
|
|
||||||
ins2(c, A_MOVQ, areg(D_DI), amem(D_CX, 16));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Slice reassignment: cgexpr produces (AX=ptr, BX=len,
|
|
||||||
* CX=cap). Store all three at off+0/+8/+16 (local) or
|
|
||||||
* via &name(SB) → DI scratch (global — CX holds the
|
|
||||||
* cap, so we need a different address register). */
|
|
||||||
if (lu && lu->kind == TY_SLICE) {
|
|
||||||
int off = localfind(locals, n->lhs->str);
|
int off = localfind(locals, n->lhs->str);
|
||||||
if (off != 0) {
|
if (off != 0) {
|
||||||
cgexpr(c, n->rhs, locals);
|
cgexpr(c, n->rhs, locals);
|
||||||
|
|||||||
@@ -18213,33 +18213,12 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\tMOVQ\tBX, AX\n");
|
emitline("\tMOVQ\tBX, AX\n");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// str IS []u8: rhs left (AX=ptr,
|
|
||||||
// BX=len, CX=cap). CX holds cap, so
|
|
||||||
// stage the struct addr in DX and
|
|
||||||
// store all three words — identical
|
|
||||||
// to the slice arm below (#1/Phase 3).
|
|
||||||
if (n.op == tkind.TK_ASSIGN) {
|
if (n.op == tkind.TK_ASSIGN) {
|
||||||
if (isstrtype(c, fi.tnode)) {
|
// str/slice field via *struct: str IS []u8, so both
|
||||||
emitline("\tMOVQ\t");
|
// store the full 3-word {ptr,len,cap} from (AX,BX,CX).
|
||||||
emitoff(lc.off: i64);
|
// CX holds cap, so stage the struct addr in DX and
|
||||||
emitline("(BP), DX\n");
|
// store at foff/+8/+16 (#1/Phase 3).
|
||||||
emitline("\tMOVQ\tAX, ");
|
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||||
emitdispreg(fi.foff: i64, "DX");
|
|
||||||
emitline("\n");
|
|
||||||
emitline("\tMOVQ\tBX, ");
|
|
||||||
emitdispreg((fi.foff + 8): i64, "DX");
|
|
||||||
emitline("\n");
|
|
||||||
emitline("\tMOVQ\tCX, ");
|
|
||||||
emitdispreg((fi.foff + 16): i64, "DX");
|
|
||||||
emitline("\n");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
// slice field via *struct: rhs left
|
|
||||||
// (AX=ptr, BX=len, CX=cap). CX is
|
|
||||||
// taken, so stage the struct addr
|
|
||||||
// in DX. Store all three words at
|
|
||||||
// foff/+8/+16.
|
|
||||||
if (isslicetype(c, fi.tnode)) {
|
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
emitoff(lc.off: i64);
|
emitoff(lc.off: i64);
|
||||||
emitline("(BP), DX\n");
|
emitline("(BP), DX\n");
|
||||||
@@ -18421,29 +18400,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};};
|
};};
|
||||||
};
|
};
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
// str IS []u8: cgexpr left (AX=ptr,
|
// str/slice field direct: str IS []u8, so both store the
|
||||||
// BX=len, CX=cap); store all three at
|
// full 3-word {ptr,len,cap} from (AX,BX,CX) at +0/+8/+16.
|
||||||
// +0/+8/+16, identical to the slice
|
// BP base, no scratch reload needed; the generic fldstoreop
|
||||||
// arm below. BP base, no scratch
|
// below would write only AX, dropping .len/.cap (#1/Phase 3).
|
||||||
// reload needed (#1/Phase 3).
|
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||||
if (isstrtype(c, fi.tnode)) {
|
|
||||||
emitline("\tMOVQ\tAX, ");
|
|
||||||
emitoff((lc.off + fi.foff): i64);
|
|
||||||
emitline("(BP)\n");
|
|
||||||
emitline("\tMOVQ\tBX, ");
|
|
||||||
emitoff((lc.off + fi.foff + 8): i64);
|
|
||||||
emitline("(BP)\n");
|
|
||||||
emitline("\tMOVQ\tCX, ");
|
|
||||||
emitoff((lc.off + fi.foff + 16): i64);
|
|
||||||
emitline("(BP)\n");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
// slice field direct: cgexpr left
|
|
||||||
// (AX=ptr, BX=len, CX=cap); store all
|
|
||||||
// three at +0/+8/+16. The generic
|
|
||||||
// fldstoreop below would only write AX,
|
|
||||||
// dropping .len/.cap.
|
|
||||||
if (isslicetype(c, fi.tnode)) {
|
|
||||||
emitline("\tMOVQ\tAX, ");
|
emitline("\tMOVQ\tAX, ");
|
||||||
emitoff((lc.off + fi.foff): i64);
|
emitoff((lc.off + fi.foff): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
@@ -19466,21 +19427,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (n.op == tkind.TK_ASSIGN) {
|
if (n.op == tkind.TK_ASSIGN) {
|
||||||
if (letvarisstr(c, nm)) {
|
// str/slice top-level let: str IS []u8, so both store the
|
||||||
// str IS []u8: stash cap in DI before LEAQ
|
// full 3-word {ptr,len,cap}. Stash cap in DI before LEAQ
|
||||||
// overwrites CX, then store ptr/len/cap —
|
// overwrites CX, then store ptr/len/cap via &name(SB)
|
||||||
// identical to the slice arm below
|
// (#1/Phase 3).
|
||||||
// (#1/Phase 3).
|
if (letvarisstr(c, nm) || letvarisslice(c, nm)) {
|
||||||
emitline("\tMOVQ\tCX, DI\n");
|
|
||||||
emitline("\tLEAQ\t");
|
|
||||||
emitsymname(c, nm);
|
|
||||||
emitline("(SB), CX\n");
|
|
||||||
emitline("\tMOVQ\tAX, (CX)\n");
|
|
||||||
emitline("\tMOVQ\tBX, 8(CX)\n");
|
|
||||||
emitline("\tMOVQ\tDI, 16(CX)\n");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if (letvarisslice(c, nm)) {
|
|
||||||
emitline("\tMOVQ\tCX, DI\n");
|
emitline("\tMOVQ\tCX, DI\n");
|
||||||
emitline("\tLEAQ\t");
|
emitline("\tLEAQ\t");
|
||||||
emitsymname(c, nm);
|
emitsymname(c, nm);
|
||||||
|
|||||||
@@ -4380,33 +4380,12 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\tMOVQ\tBX, AX\n");
|
emitline("\tMOVQ\tBX, AX\n");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// str IS []u8: rhs left (AX=ptr,
|
|
||||||
// BX=len, CX=cap). CX holds cap, so
|
|
||||||
// stage the struct addr in DX and
|
|
||||||
// store all three words — identical
|
|
||||||
// to the slice arm below (#1/Phase 3).
|
|
||||||
if (n.op == tkind.TK_ASSIGN) {
|
if (n.op == tkind.TK_ASSIGN) {
|
||||||
if (isstrtype(c, fi.tnode)) {
|
// str/slice field via *struct: str IS []u8, so both
|
||||||
emitline("\tMOVQ\t");
|
// store the full 3-word {ptr,len,cap} from (AX,BX,CX).
|
||||||
emitoff(lc.off: i64);
|
// CX holds cap, so stage the struct addr in DX and
|
||||||
emitline("(BP), DX\n");
|
// store at foff/+8/+16 (#1/Phase 3).
|
||||||
emitline("\tMOVQ\tAX, ");
|
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||||
emitdispreg(fi.foff: i64, "DX");
|
|
||||||
emitline("\n");
|
|
||||||
emitline("\tMOVQ\tBX, ");
|
|
||||||
emitdispreg((fi.foff + 8): i64, "DX");
|
|
||||||
emitline("\n");
|
|
||||||
emitline("\tMOVQ\tCX, ");
|
|
||||||
emitdispreg((fi.foff + 16): i64, "DX");
|
|
||||||
emitline("\n");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
// slice field via *struct: rhs left
|
|
||||||
// (AX=ptr, BX=len, CX=cap). CX is
|
|
||||||
// taken, so stage the struct addr
|
|
||||||
// in DX. Store all three words at
|
|
||||||
// foff/+8/+16.
|
|
||||||
if (isslicetype(c, fi.tnode)) {
|
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
emitoff(lc.off: i64);
|
emitoff(lc.off: i64);
|
||||||
emitline("(BP), DX\n");
|
emitline("(BP), DX\n");
|
||||||
@@ -4588,29 +4567,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};};
|
};};
|
||||||
};
|
};
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
// str IS []u8: cgexpr left (AX=ptr,
|
// str/slice field direct: str IS []u8, so both store the
|
||||||
// BX=len, CX=cap); store all three at
|
// full 3-word {ptr,len,cap} from (AX,BX,CX) at +0/+8/+16.
|
||||||
// +0/+8/+16, identical to the slice
|
// BP base, no scratch reload needed; the generic fldstoreop
|
||||||
// arm below. BP base, no scratch
|
// below would write only AX, dropping .len/.cap (#1/Phase 3).
|
||||||
// reload needed (#1/Phase 3).
|
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||||
if (isstrtype(c, fi.tnode)) {
|
|
||||||
emitline("\tMOVQ\tAX, ");
|
|
||||||
emitoff((lc.off + fi.foff): i64);
|
|
||||||
emitline("(BP)\n");
|
|
||||||
emitline("\tMOVQ\tBX, ");
|
|
||||||
emitoff((lc.off + fi.foff + 8): i64);
|
|
||||||
emitline("(BP)\n");
|
|
||||||
emitline("\tMOVQ\tCX, ");
|
|
||||||
emitoff((lc.off + fi.foff + 16): i64);
|
|
||||||
emitline("(BP)\n");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
// slice field direct: cgexpr left
|
|
||||||
// (AX=ptr, BX=len, CX=cap); store all
|
|
||||||
// three at +0/+8/+16. The generic
|
|
||||||
// fldstoreop below would only write AX,
|
|
||||||
// dropping .len/.cap.
|
|
||||||
if (isslicetype(c, fi.tnode)) {
|
|
||||||
emitline("\tMOVQ\tAX, ");
|
emitline("\tMOVQ\tAX, ");
|
||||||
emitoff((lc.off + fi.foff): i64);
|
emitoff((lc.off + fi.foff): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
@@ -5633,21 +5594,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (n.op == tkind.TK_ASSIGN) {
|
if (n.op == tkind.TK_ASSIGN) {
|
||||||
if (letvarisstr(c, nm)) {
|
// str/slice top-level let: str IS []u8, so both store the
|
||||||
// str IS []u8: stash cap in DI before LEAQ
|
// full 3-word {ptr,len,cap}. Stash cap in DI before LEAQ
|
||||||
// overwrites CX, then store ptr/len/cap —
|
// overwrites CX, then store ptr/len/cap via &name(SB)
|
||||||
// identical to the slice arm below
|
// (#1/Phase 3).
|
||||||
// (#1/Phase 3).
|
if (letvarisstr(c, nm) || letvarisslice(c, nm)) {
|
||||||
emitline("\tMOVQ\tCX, DI\n");
|
|
||||||
emitline("\tLEAQ\t");
|
|
||||||
emitsymname(c, nm);
|
|
||||||
emitline("(SB), CX\n");
|
|
||||||
emitline("\tMOVQ\tAX, (CX)\n");
|
|
||||||
emitline("\tMOVQ\tBX, 8(CX)\n");
|
|
||||||
emitline("\tMOVQ\tDI, 16(CX)\n");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if (letvarisslice(c, nm)) {
|
|
||||||
emitline("\tMOVQ\tCX, DI\n");
|
emitline("\tMOVQ\tCX, DI\n");
|
||||||
emitline("\tLEAQ\t");
|
emitline("\tLEAQ\t");
|
||||||
emitsymname(c, nm);
|
emitsymname(c, nm);
|
||||||
|
|||||||
@@ -18213,33 +18213,12 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\tMOVQ\tBX, AX\n");
|
emitline("\tMOVQ\tBX, AX\n");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// str IS []u8: rhs left (AX=ptr,
|
|
||||||
// BX=len, CX=cap). CX holds cap, so
|
|
||||||
// stage the struct addr in DX and
|
|
||||||
// store all three words — identical
|
|
||||||
// to the slice arm below (#1/Phase 3).
|
|
||||||
if (n.op == tkind.TK_ASSIGN) {
|
if (n.op == tkind.TK_ASSIGN) {
|
||||||
if (isstrtype(c, fi.tnode)) {
|
// str/slice field via *struct: str IS []u8, so both
|
||||||
emitline("\tMOVQ\t");
|
// store the full 3-word {ptr,len,cap} from (AX,BX,CX).
|
||||||
emitoff(lc.off: i64);
|
// CX holds cap, so stage the struct addr in DX and
|
||||||
emitline("(BP), DX\n");
|
// store at foff/+8/+16 (#1/Phase 3).
|
||||||
emitline("\tMOVQ\tAX, ");
|
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||||
emitdispreg(fi.foff: i64, "DX");
|
|
||||||
emitline("\n");
|
|
||||||
emitline("\tMOVQ\tBX, ");
|
|
||||||
emitdispreg((fi.foff + 8): i64, "DX");
|
|
||||||
emitline("\n");
|
|
||||||
emitline("\tMOVQ\tCX, ");
|
|
||||||
emitdispreg((fi.foff + 16): i64, "DX");
|
|
||||||
emitline("\n");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
// slice field via *struct: rhs left
|
|
||||||
// (AX=ptr, BX=len, CX=cap). CX is
|
|
||||||
// taken, so stage the struct addr
|
|
||||||
// in DX. Store all three words at
|
|
||||||
// foff/+8/+16.
|
|
||||||
if (isslicetype(c, fi.tnode)) {
|
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
emitoff(lc.off: i64);
|
emitoff(lc.off: i64);
|
||||||
emitline("(BP), DX\n");
|
emitline("(BP), DX\n");
|
||||||
@@ -18421,29 +18400,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};};
|
};};
|
||||||
};
|
};
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
// str IS []u8: cgexpr left (AX=ptr,
|
// str/slice field direct: str IS []u8, so both store the
|
||||||
// BX=len, CX=cap); store all three at
|
// full 3-word {ptr,len,cap} from (AX,BX,CX) at +0/+8/+16.
|
||||||
// +0/+8/+16, identical to the slice
|
// BP base, no scratch reload needed; the generic fldstoreop
|
||||||
// arm below. BP base, no scratch
|
// below would write only AX, dropping .len/.cap (#1/Phase 3).
|
||||||
// reload needed (#1/Phase 3).
|
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||||
if (isstrtype(c, fi.tnode)) {
|
|
||||||
emitline("\tMOVQ\tAX, ");
|
|
||||||
emitoff((lc.off + fi.foff): i64);
|
|
||||||
emitline("(BP)\n");
|
|
||||||
emitline("\tMOVQ\tBX, ");
|
|
||||||
emitoff((lc.off + fi.foff + 8): i64);
|
|
||||||
emitline("(BP)\n");
|
|
||||||
emitline("\tMOVQ\tCX, ");
|
|
||||||
emitoff((lc.off + fi.foff + 16): i64);
|
|
||||||
emitline("(BP)\n");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
// slice field direct: cgexpr left
|
|
||||||
// (AX=ptr, BX=len, CX=cap); store all
|
|
||||||
// three at +0/+8/+16. The generic
|
|
||||||
// fldstoreop below would only write AX,
|
|
||||||
// dropping .len/.cap.
|
|
||||||
if (isslicetype(c, fi.tnode)) {
|
|
||||||
emitline("\tMOVQ\tAX, ");
|
emitline("\tMOVQ\tAX, ");
|
||||||
emitoff((lc.off + fi.foff): i64);
|
emitoff((lc.off + fi.foff): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
@@ -19466,21 +19427,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (n.op == tkind.TK_ASSIGN) {
|
if (n.op == tkind.TK_ASSIGN) {
|
||||||
if (letvarisstr(c, nm)) {
|
// str/slice top-level let: str IS []u8, so both store the
|
||||||
// str IS []u8: stash cap in DI before LEAQ
|
// full 3-word {ptr,len,cap}. Stash cap in DI before LEAQ
|
||||||
// overwrites CX, then store ptr/len/cap —
|
// overwrites CX, then store ptr/len/cap via &name(SB)
|
||||||
// identical to the slice arm below
|
// (#1/Phase 3).
|
||||||
// (#1/Phase 3).
|
if (letvarisstr(c, nm) || letvarisslice(c, nm)) {
|
||||||
emitline("\tMOVQ\tCX, DI\n");
|
|
||||||
emitline("\tLEAQ\t");
|
|
||||||
emitsymname(c, nm);
|
|
||||||
emitline("(SB), CX\n");
|
|
||||||
emitline("\tMOVQ\tAX, (CX)\n");
|
|
||||||
emitline("\tMOVQ\tBX, 8(CX)\n");
|
|
||||||
emitline("\tMOVQ\tDI, 16(CX)\n");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if (letvarisslice(c, nm)) {
|
|
||||||
emitline("\tMOVQ\tCX, DI\n");
|
emitline("\tMOVQ\tCX, DI\n");
|
||||||
emitline("\tLEAQ\t");
|
emitline("\tLEAQ\t");
|
||||||
emitsymname(c, nm);
|
emitsymname(c, nm);
|
||||||
|
|||||||
Reference in New Issue
Block a user