wcc: single-dot field compound assignment routes through one combine helper
s.f *= v silently became s.f = v (and the other non-+=/-= ops dropped likewise) in BOTH stages across five lvalue sub-arms: via-ptr field, direct local field, str/slice pseudo-field, and the two global-field forms. Funnel all five through a shared combine dispatch (cgdotfieldcombine / cg_dotfield_combine) emitting the load-OP-store sequence at field width, hard-erroring the unhandled kinds — close-by- construction so no arm stays on the old PLUSEQ-only path (the #133 BUS-routing lesson; #227 sites A/B are the closed siblings). The refactor routes the corpus's existing +=/-= sites through the same helper output-identically (byte-id held). Review item #34. Both stages move in one commit: one emission contract; splitting the halves would leave the byte-id gates red in between.
This commit is contained in:
@@ -23409,6 +23409,85 @@ fn cgtrytaggedshift(c: *cgen, n: *node) bool = {
|
||||
// INDEX/DOT) from the box address cgexpr leaves in AX. Both were
|
||||
// silent word0 unwraps pre-#35. >32B non-call stays loud (the cursor
|
||||
// cannot carry it; #40 family). Mirrors cstage N_TRYPROP/N_TRYUNW.
|
||||
// cgdotfieldcombine — single-dot field compound combine. The old
|
||||
// field value is in BX, the rhs in AX; the result is left in AX.
|
||||
// PLUSEQ/MINUSEQ preserve the pre-#34 emission (byte-id); the other 8
|
||||
// ops were silently DROPPED (the arm fell through to a plain store of
|
||||
// the rhs → `s.f = rhs`, #34/#263). SLASHEQ/PERCENTEQ/LSHIFTEQ/RSHIFTEQ
|
||||
// need the lhs in AX and the divisor/count in CX, so swap (rhs AX→CX,
|
||||
// old BX→AX) first. Signed RSHIFTEQ uses SARQ, unsigned SHRQ (#136).
|
||||
// Mirrors cstage cg_dotfield_combine — both stages emit identical asm.
|
||||
fn cgdotfieldcombine(c: *cgen, op: tkind, unsignd: bool) void = {
|
||||
if (op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_STAREQ) { emitline("\tIMULQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_AMPEQ) { emitline("\tANDQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_PIPEEQ) { emitline("\tORQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_CARETEQ) { emitline("\tXORQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_SLASHEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
if (unsignd) { emitline("\tMOVQ\t$0, DX\n"); emitline("\tDIVQ\tCX\n"); }
|
||||
else { emitline("\tCQO\n"); emitline("\tIDIVQ\tCX\n"); };
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_PERCENTEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
if (unsignd) { emitline("\tMOVQ\t$0, DX\n"); emitline("\tDIVQ\tCX\n"); }
|
||||
else { emitline("\tCQO\n"); emitline("\tIDIVQ\tCX\n"); };
|
||||
emitline("\tMOVQ\tDX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_LSHIFTEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
emitline("\tSHLQ\tCX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_RSHIFTEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
if (unsignd) { emitline("\tSHRQ\tCX, AX\n"); }
|
||||
else { emitline("\tSARQ\tCX, AX\n"); };
|
||||
return;
|
||||
};
|
||||
let m: str = "single-dot field compound: unknown op (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
|
||||
// cgdotfieldhardstop — loud-stop a single-dot field compound on a
|
||||
// non-integer field (float/str/slice/tagged): the combine arm only
|
||||
// speaks integer ABI; pre-#34 these silently became `s.f = rhs`.
|
||||
// Mirrors the cstage cg_dotfield_hardstop gate. (#34/rule-7)
|
||||
fn cgdotfieldhardstop(c: *cgen, ftn: *node) void = {
|
||||
if (istaggedtype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on tagged field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (isstrtype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on str field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (isslicetype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on slice field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (isfloattype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on float field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
|
||||
fn cgtryunwcursor(c: *cgen, n: *node, opname: str) void = {
|
||||
let u: *tinfo = nil;
|
||||
if (n.lhs != nil) { u = n.lhs.type_: *tinfo; };
|
||||
@@ -33041,11 +33120,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// PLUSEQ is commutative; MINUSEQ
|
||||
// needs lhs - rhs (BX is old lhs,
|
||||
// AX is rhs).
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldhardstop(c, fi.tnode);
|
||||
let uns34: bool = false;
|
||||
if (fi.tnode != nil) { if (fi.tnode.type_ != nil) { uns34 = typeisunsigned(fi.tnode.type_: *tinfo); }; };
|
||||
cgdotfieldcombine(c, n.op, uns34);
|
||||
};
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
// str/slice field via *struct: str IS []u8, so both
|
||||
@@ -33267,11 +33345,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
// PLUSEQ commutes; MINUSEQ needs
|
||||
// lhs-rhs (BX old lhs, AX rhs).
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldhardstop(c, fi.tnode);
|
||||
let uns34: bool = false;
|
||||
if (fi.tnode != nil) { if (fi.tnode.type_ != nil) { uns34 = typeisunsigned(fi.tnode.type_: *tinfo); }; };
|
||||
cgdotfieldcombine(c, n.op, uns34);
|
||||
};
|
||||
// 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.
|
||||
@@ -33342,11 +33419,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
// PLUSEQ is commutative; MINUSEQ
|
||||
// needs lhs - rhs.
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldcombine(c, n.op, false);
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
@@ -33375,11 +33448,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldcombine(c, n.op, false);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP)\n");
|
||||
@@ -33630,11 +33699,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldhardstop(c, fi.tnode);
|
||||
let uns34: bool = false;
|
||||
if (fi.tnode != nil) { if (fi.tnode.type_ != nil) { uns34 = typeisunsigned(fi.tnode.type_: *tinfo); }; };
|
||||
cgdotfieldcombine(c, n.op, uns34);
|
||||
let sop: str = fieldstoreop(c, fi);
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, bn);
|
||||
|
||||
@@ -258,6 +258,85 @@ fn cgtrytaggedshift(c: *cgen, n: *node) bool = {
|
||||
// INDEX/DOT) from the box address cgexpr leaves in AX. Both were
|
||||
// silent word0 unwraps pre-#35. >32B non-call stays loud (the cursor
|
||||
// cannot carry it; #40 family). Mirrors cstage N_TRYPROP/N_TRYUNW.
|
||||
// cgdotfieldcombine — single-dot field compound combine. The old
|
||||
// field value is in BX, the rhs in AX; the result is left in AX.
|
||||
// PLUSEQ/MINUSEQ preserve the pre-#34 emission (byte-id); the other 8
|
||||
// ops were silently DROPPED (the arm fell through to a plain store of
|
||||
// the rhs → `s.f = rhs`, #34/#263). SLASHEQ/PERCENTEQ/LSHIFTEQ/RSHIFTEQ
|
||||
// need the lhs in AX and the divisor/count in CX, so swap (rhs AX→CX,
|
||||
// old BX→AX) first. Signed RSHIFTEQ uses SARQ, unsigned SHRQ (#136).
|
||||
// Mirrors cstage cg_dotfield_combine — both stages emit identical asm.
|
||||
fn cgdotfieldcombine(c: *cgen, op: tkind, unsignd: bool) void = {
|
||||
if (op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_STAREQ) { emitline("\tIMULQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_AMPEQ) { emitline("\tANDQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_PIPEEQ) { emitline("\tORQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_CARETEQ) { emitline("\tXORQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_SLASHEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
if (unsignd) { emitline("\tMOVQ\t$0, DX\n"); emitline("\tDIVQ\tCX\n"); }
|
||||
else { emitline("\tCQO\n"); emitline("\tIDIVQ\tCX\n"); };
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_PERCENTEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
if (unsignd) { emitline("\tMOVQ\t$0, DX\n"); emitline("\tDIVQ\tCX\n"); }
|
||||
else { emitline("\tCQO\n"); emitline("\tIDIVQ\tCX\n"); };
|
||||
emitline("\tMOVQ\tDX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_LSHIFTEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
emitline("\tSHLQ\tCX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_RSHIFTEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
if (unsignd) { emitline("\tSHRQ\tCX, AX\n"); }
|
||||
else { emitline("\tSARQ\tCX, AX\n"); };
|
||||
return;
|
||||
};
|
||||
let m: str = "single-dot field compound: unknown op (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
|
||||
// cgdotfieldhardstop — loud-stop a single-dot field compound on a
|
||||
// non-integer field (float/str/slice/tagged): the combine arm only
|
||||
// speaks integer ABI; pre-#34 these silently became `s.f = rhs`.
|
||||
// Mirrors the cstage cg_dotfield_hardstop gate. (#34/rule-7)
|
||||
fn cgdotfieldhardstop(c: *cgen, ftn: *node) void = {
|
||||
if (istaggedtype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on tagged field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (isstrtype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on str field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (isslicetype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on slice field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (isfloattype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on float field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
|
||||
fn cgtryunwcursor(c: *cgen, n: *node, opname: str) void = {
|
||||
let u: *tinfo = nil;
|
||||
if (n.lhs != nil) { u = n.lhs.type_: *tinfo; };
|
||||
@@ -9890,11 +9969,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// PLUSEQ is commutative; MINUSEQ
|
||||
// needs lhs - rhs (BX is old lhs,
|
||||
// AX is rhs).
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldhardstop(c, fi.tnode);
|
||||
let uns34: bool = false;
|
||||
if (fi.tnode != nil) { if (fi.tnode.type_ != nil) { uns34 = typeisunsigned(fi.tnode.type_: *tinfo); }; };
|
||||
cgdotfieldcombine(c, n.op, uns34);
|
||||
};
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
// str/slice field via *struct: str IS []u8, so both
|
||||
@@ -10116,11 +10194,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
// PLUSEQ commutes; MINUSEQ needs
|
||||
// lhs-rhs (BX old lhs, AX rhs).
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldhardstop(c, fi.tnode);
|
||||
let uns34: bool = false;
|
||||
if (fi.tnode != nil) { if (fi.tnode.type_ != nil) { uns34 = typeisunsigned(fi.tnode.type_: *tinfo); }; };
|
||||
cgdotfieldcombine(c, n.op, uns34);
|
||||
};
|
||||
// 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.
|
||||
@@ -10191,11 +10268,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
// PLUSEQ is commutative; MINUSEQ
|
||||
// needs lhs - rhs.
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldcombine(c, n.op, false);
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
@@ -10224,11 +10297,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldcombine(c, n.op, false);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP)\n");
|
||||
@@ -10479,11 +10548,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldhardstop(c, fi.tnode);
|
||||
let uns34: bool = false;
|
||||
if (fi.tnode != nil) { if (fi.tnode.type_ != nil) { uns34 = typeisunsigned(fi.tnode.type_: *tinfo); }; };
|
||||
cgdotfieldcombine(c, n.op, uns34);
|
||||
let sop: str = fieldstoreop(c, fi);
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, bn);
|
||||
|
||||
@@ -23409,6 +23409,85 @@ fn cgtrytaggedshift(c: *cgen, n: *node) bool = {
|
||||
// INDEX/DOT) from the box address cgexpr leaves in AX. Both were
|
||||
// silent word0 unwraps pre-#35. >32B non-call stays loud (the cursor
|
||||
// cannot carry it; #40 family). Mirrors cstage N_TRYPROP/N_TRYUNW.
|
||||
// cgdotfieldcombine — single-dot field compound combine. The old
|
||||
// field value is in BX, the rhs in AX; the result is left in AX.
|
||||
// PLUSEQ/MINUSEQ preserve the pre-#34 emission (byte-id); the other 8
|
||||
// ops were silently DROPPED (the arm fell through to a plain store of
|
||||
// the rhs → `s.f = rhs`, #34/#263). SLASHEQ/PERCENTEQ/LSHIFTEQ/RSHIFTEQ
|
||||
// need the lhs in AX and the divisor/count in CX, so swap (rhs AX→CX,
|
||||
// old BX→AX) first. Signed RSHIFTEQ uses SARQ, unsigned SHRQ (#136).
|
||||
// Mirrors cstage cg_dotfield_combine — both stages emit identical asm.
|
||||
fn cgdotfieldcombine(c: *cgen, op: tkind, unsignd: bool) void = {
|
||||
if (op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_STAREQ) { emitline("\tIMULQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_AMPEQ) { emitline("\tANDQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_PIPEEQ) { emitline("\tORQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_CARETEQ) { emitline("\tXORQ\tBX, AX\n"); return; };
|
||||
if (op == tkind.TK_SLASHEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
if (unsignd) { emitline("\tMOVQ\t$0, DX\n"); emitline("\tDIVQ\tCX\n"); }
|
||||
else { emitline("\tCQO\n"); emitline("\tIDIVQ\tCX\n"); };
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_PERCENTEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
if (unsignd) { emitline("\tMOVQ\t$0, DX\n"); emitline("\tDIVQ\tCX\n"); }
|
||||
else { emitline("\tCQO\n"); emitline("\tIDIVQ\tCX\n"); };
|
||||
emitline("\tMOVQ\tDX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_LSHIFTEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
emitline("\tSHLQ\tCX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (op == tkind.TK_RSHIFTEQ) {
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
if (unsignd) { emitline("\tSHRQ\tCX, AX\n"); }
|
||||
else { emitline("\tSARQ\tCX, AX\n"); };
|
||||
return;
|
||||
};
|
||||
let m: str = "single-dot field compound: unknown op (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
|
||||
// cgdotfieldhardstop — loud-stop a single-dot field compound on a
|
||||
// non-integer field (float/str/slice/tagged): the combine arm only
|
||||
// speaks integer ABI; pre-#34 these silently became `s.f = rhs`.
|
||||
// Mirrors the cstage cg_dotfield_hardstop gate. (#34/rule-7)
|
||||
fn cgdotfieldhardstop(c: *cgen, ftn: *node) void = {
|
||||
if (istaggedtype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on tagged field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (isstrtype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on str field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (isslicetype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on slice field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (isfloattype(c, ftn)) {
|
||||
let m: str = "single-dot field compound on float field not wired (#34/rule-7)\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
|
||||
fn cgtryunwcursor(c: *cgen, n: *node, opname: str) void = {
|
||||
let u: *tinfo = nil;
|
||||
if (n.lhs != nil) { u = n.lhs.type_: *tinfo; };
|
||||
@@ -33041,11 +33120,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// PLUSEQ is commutative; MINUSEQ
|
||||
// needs lhs - rhs (BX is old lhs,
|
||||
// AX is rhs).
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldhardstop(c, fi.tnode);
|
||||
let uns34: bool = false;
|
||||
if (fi.tnode != nil) { if (fi.tnode.type_ != nil) { uns34 = typeisunsigned(fi.tnode.type_: *tinfo); }; };
|
||||
cgdotfieldcombine(c, n.op, uns34);
|
||||
};
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
// str/slice field via *struct: str IS []u8, so both
|
||||
@@ -33267,11 +33345,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
// PLUSEQ commutes; MINUSEQ needs
|
||||
// lhs-rhs (BX old lhs, AX rhs).
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldhardstop(c, fi.tnode);
|
||||
let uns34: bool = false;
|
||||
if (fi.tnode != nil) { if (fi.tnode.type_ != nil) { uns34 = typeisunsigned(fi.tnode.type_: *tinfo); }; };
|
||||
cgdotfieldcombine(c, n.op, uns34);
|
||||
};
|
||||
// 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.
|
||||
@@ -33342,11 +33419,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
// PLUSEQ is commutative; MINUSEQ
|
||||
// needs lhs - rhs.
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldcombine(c, n.op, false);
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
@@ -33375,11 +33448,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldcombine(c, n.op, false);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP)\n");
|
||||
@@ -33630,11 +33699,10 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
if (n.op == tkind.TK_PLUSEQ) { emitline("\tADDQ\tBX, AX\n"); };
|
||||
if (n.op == tkind.TK_MINUSEQ) {
|
||||
emitline("\tSUBQ\tAX, BX\n");
|
||||
emitline("\tMOVQ\tBX, AX\n");
|
||||
};
|
||||
cgdotfieldhardstop(c, fi.tnode);
|
||||
let uns34: bool = false;
|
||||
if (fi.tnode != nil) { if (fi.tnode.type_ != nil) { uns34 = typeisunsigned(fi.tnode.type_: *tinfo); }; };
|
||||
cgdotfieldcombine(c, n.op, uns34);
|
||||
let sop: str = fieldstoreop(c, fi);
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, bn);
|
||||
|
||||
Reference in New Issue
Block a user