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:
@@ -18213,33 +18213,12 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
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 (isstrtype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), DX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
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)) {
|
||||
// str/slice field via *struct: str IS []u8, so both
|
||||
// store the full 3-word {ptr,len,cap} from (AX,BX,CX).
|
||||
// CX holds cap, so stage the struct addr in DX and
|
||||
// store at foff/+8/+16 (#1/Phase 3).
|
||||
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), DX\n");
|
||||
@@ -18421,29 +18400,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};};
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
// str IS []u8: cgexpr left (AX=ptr,
|
||||
// BX=len, CX=cap); store all three at
|
||||
// +0/+8/+16, identical to the slice
|
||||
// arm below. BP base, no scratch
|
||||
// reload needed (#1/Phase 3).
|
||||
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)) {
|
||||
// str/slice field direct: str IS []u8, so both store the
|
||||
// full 3-word {ptr,len,cap} from (AX,BX,CX) at +0/+8/+16.
|
||||
// BP base, no scratch reload needed; the generic fldstoreop
|
||||
// below would write only AX, dropping .len/.cap (#1/Phase 3).
|
||||
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + fi.foff): i64);
|
||||
emitline("(BP)\n");
|
||||
@@ -19466,21 +19427,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
if (letvarisstr(c, nm)) {
|
||||
// str IS []u8: stash cap in DI before LEAQ
|
||||
// overwrites CX, then store ptr/len/cap —
|
||||
// identical to the slice arm below
|
||||
// (#1/Phase 3).
|
||||
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)) {
|
||||
// str/slice top-level let: str IS []u8, so both store the
|
||||
// full 3-word {ptr,len,cap}. Stash cap in DI before LEAQ
|
||||
// overwrites CX, then store ptr/len/cap via &name(SB)
|
||||
// (#1/Phase 3).
|
||||
if (letvarisstr(c, nm) || letvarisslice(c, nm)) {
|
||||
emitline("\tMOVQ\tCX, DI\n");
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, nm);
|
||||
|
||||
@@ -4380,33 +4380,12 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
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 (isstrtype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), DX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
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)) {
|
||||
// str/slice field via *struct: str IS []u8, so both
|
||||
// store the full 3-word {ptr,len,cap} from (AX,BX,CX).
|
||||
// CX holds cap, so stage the struct addr in DX and
|
||||
// store at foff/+8/+16 (#1/Phase 3).
|
||||
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), DX\n");
|
||||
@@ -4588,29 +4567,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};};
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
// str IS []u8: cgexpr left (AX=ptr,
|
||||
// BX=len, CX=cap); store all three at
|
||||
// +0/+8/+16, identical to the slice
|
||||
// arm below. BP base, no scratch
|
||||
// reload needed (#1/Phase 3).
|
||||
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)) {
|
||||
// str/slice field direct: str IS []u8, so both store the
|
||||
// full 3-word {ptr,len,cap} from (AX,BX,CX) at +0/+8/+16.
|
||||
// BP base, no scratch reload needed; the generic fldstoreop
|
||||
// below would write only AX, dropping .len/.cap (#1/Phase 3).
|
||||
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + fi.foff): i64);
|
||||
emitline("(BP)\n");
|
||||
@@ -5633,21 +5594,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
if (letvarisstr(c, nm)) {
|
||||
// str IS []u8: stash cap in DI before LEAQ
|
||||
// overwrites CX, then store ptr/len/cap —
|
||||
// identical to the slice arm below
|
||||
// (#1/Phase 3).
|
||||
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)) {
|
||||
// str/slice top-level let: str IS []u8, so both store the
|
||||
// full 3-word {ptr,len,cap}. Stash cap in DI before LEAQ
|
||||
// overwrites CX, then store ptr/len/cap via &name(SB)
|
||||
// (#1/Phase 3).
|
||||
if (letvarisstr(c, nm) || letvarisslice(c, nm)) {
|
||||
emitline("\tMOVQ\tCX, DI\n");
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, nm);
|
||||
|
||||
@@ -18213,33 +18213,12 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
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 (isstrtype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), DX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
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)) {
|
||||
// str/slice field via *struct: str IS []u8, so both
|
||||
// store the full 3-word {ptr,len,cap} from (AX,BX,CX).
|
||||
// CX holds cap, so stage the struct addr in DX and
|
||||
// store at foff/+8/+16 (#1/Phase 3).
|
||||
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), DX\n");
|
||||
@@ -18421,29 +18400,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};};
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
// str IS []u8: cgexpr left (AX=ptr,
|
||||
// BX=len, CX=cap); store all three at
|
||||
// +0/+8/+16, identical to the slice
|
||||
// arm below. BP base, no scratch
|
||||
// reload needed (#1/Phase 3).
|
||||
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)) {
|
||||
// str/slice field direct: str IS []u8, so both store the
|
||||
// full 3-word {ptr,len,cap} from (AX,BX,CX) at +0/+8/+16.
|
||||
// BP base, no scratch reload needed; the generic fldstoreop
|
||||
// below would write only AX, dropping .len/.cap (#1/Phase 3).
|
||||
if (isstrtype(c, fi.tnode) || isslicetype(c, fi.tnode)) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + fi.foff): i64);
|
||||
emitline("(BP)\n");
|
||||
@@ -19466,21 +19427,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
if (letvarisstr(c, nm)) {
|
||||
// str IS []u8: stash cap in DI before LEAQ
|
||||
// overwrites CX, then store ptr/len/cap —
|
||||
// identical to the slice arm below
|
||||
// (#1/Phase 3).
|
||||
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)) {
|
||||
// str/slice top-level let: str IS []u8, so both store the
|
||||
// full 3-word {ptr,len,cap}. Stash cap in DI before LEAQ
|
||||
// overwrites CX, then store ptr/len/cap via &name(SB)
|
||||
// (#1/Phase 3).
|
||||
if (letvarisstr(c, nm) || letvarisslice(c, nm)) {
|
||||
emitline("\tMOVQ\tCX, DI\n");
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, nm);
|
||||
|
||||
Reference in New Issue
Block a user