wcc: indexed-field compound assignment wires all ten ops, both stages
arr[i].field /= %= <<= >>= silently dropped the op (load-combine-store
emitted plain assignment) in BOTH stages — gate-blind, the #133 class.
Route every compound op through the combine dispatch at the indexed-
field arm and hard-error the unhandled operand kinds (float/str/slice/
tagged), per the #133 template (3986818). The runtime-correct target is
the op's own algebra (a OP= b == a = a OP b). Review item #33.
Both stages move in one commit: the fix is a single emission contract —
splitting cstage cgen.c from selfhost cgenexpr.ww would leave the
byte-id gates red between the halves.
This commit is contained in:
@@ -5555,6 +5555,19 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* pop addr→BX, rhs→CX; combine;
|
||||
* store. Float/str compound
|
||||
* not wired. */
|
||||
Type *fchk33 = type_chase_named(ft);
|
||||
if (fchk33 && fchk33->kind == TY_TAGGED)
|
||||
fatal("arr[i].field compound on "
|
||||
"tagged field not wired (#33/rule-7)");
|
||||
if (fchk33 && fchk33->kind == TY_STR)
|
||||
fatal("arr[i].field compound on "
|
||||
"str field not wired (#33/rule-7)");
|
||||
if (fchk33 && fchk33->kind == TY_SLICE)
|
||||
fatal("arr[i].field compound on "
|
||||
"slice field not wired (#33/rule-7)");
|
||||
if (ft && type_isfloat(ft))
|
||||
fatal("arr[i].field compound on "
|
||||
"float field not wired (#33/rule-7)");
|
||||
cgexpr(c, n->rhs, locals);
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
cgexpr(c, idx, locals);
|
||||
@@ -5587,6 +5600,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
areg(D_AX));
|
||||
ins1(c, A_POPQ, areg(D_BX));
|
||||
ins1(c, A_POPQ, areg(D_CX));
|
||||
int unsignd33 = type_isunsigned(ft);
|
||||
switch (n->op) {
|
||||
case TK_PLUSEQ:
|
||||
ins2(c, A_ADDQ,
|
||||
@@ -5618,7 +5632,39 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
areg(D_CX),
|
||||
areg(D_AX));
|
||||
break;
|
||||
default: break;
|
||||
case TK_SLASHEQ:
|
||||
if (unsignd33)
|
||||
ins2(c, A_MOVQ, aimm(0),
|
||||
areg(D_DX));
|
||||
else
|
||||
ins0(c, A_CQO);
|
||||
ins1(c, unsignd33 ? A_DIVQ : A_IDIVQ,
|
||||
areg(D_CX));
|
||||
break;
|
||||
case TK_PERCENTEQ:
|
||||
if (unsignd33)
|
||||
ins2(c, A_MOVQ, aimm(0),
|
||||
areg(D_DX));
|
||||
else
|
||||
ins0(c, A_CQO);
|
||||
ins1(c, unsignd33 ? A_DIVQ : A_IDIVQ,
|
||||
areg(D_CX));
|
||||
ins2(c, A_MOVQ, areg(D_DX),
|
||||
areg(D_AX));
|
||||
break;
|
||||
case TK_LSHIFTEQ:
|
||||
ins2(c, A_SHLQ, areg(D_CX),
|
||||
areg(D_AX));
|
||||
break;
|
||||
case TK_RSHIFTEQ:
|
||||
ins2(c, unsignd33 ? A_SHRQ : A_SARQ,
|
||||
areg(D_CX),
|
||||
areg(D_AX));
|
||||
break;
|
||||
default:
|
||||
fatal("arr[i].field compound: "
|
||||
"unknown op tk=%d (#33/rule-7)",
|
||||
n->op);
|
||||
}
|
||||
ins2(c, store_op, areg(D_AX),
|
||||
amem(D_BX, foff));
|
||||
|
||||
Reference in New Issue
Block a user