wwstage: load-combine-store local-field compound assign (#227)
A compound assign (`-=`/`+=`) on a local field silently dropped the operator in wwstage, storing the bare rhs. Two same-class sites in cgenexpr.ww lacked the `n.op != TK_ASSIGN` load-combine-store guard that the pointer-to-struct path already had: the local str/slice pseudo-field fall-through (`view.len -= 1` stored 1) and the direct struct-local scalar field (`p.x -= 4` stored 4). Both now load the field, push, eval rhs, pop, combine (ADDQ/SUBQ), and store — mirroring cstage cmd/w6c/cgen.c:3235-3264 and :3477-3502. cstage was already correct; this aligns wwstage up. PLUSEQ/MINUSEQ only, matching cstage's switch. This is the missing-SUBQ half of fmt's cs/ww divergence (fmt's view.len-=1). The remaining match-label-counter offset is separate, so 777/780/781 stay STAGE_CS until that lands. test/wcc/data/attest_pass.ww: @test check_local_field_compound covers both sites (str pseudo-field + struct scalar), run by 910_at_test (cstage) and 997_at_test_ww (wwstage); pre-fix the dropped op aborts via the 1/0 idiom.
This commit is contained in:
@@ -24299,7 +24299,30 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};};
|
||||
};
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
// Compound on direct struct-local
|
||||
// scalar field: load current → push
|
||||
// → eval rhs → combine → store
|
||||
// (mirror cgen.c:3477 local arm).
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
emitoff((lc.off + fi.foff): i64);
|
||||
emitline("(BP), BX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
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");
|
||||
};
|
||||
};
|
||||
// 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
|
||||
@@ -24392,6 +24415,26 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
};
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
// Compound on local `str|slice` pseudo-field:
|
||||
// load current → push → eval rhs → combine →
|
||||
// store (mirror cgen.c:3235 local arm).
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP), BX\n");
|
||||
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");
|
||||
};
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP)\n");
|
||||
return;
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + delta): i64);
|
||||
|
||||
@@ -5658,7 +5658,30 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};};
|
||||
};
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
// Compound on direct struct-local
|
||||
// scalar field: load current → push
|
||||
// → eval rhs → combine → store
|
||||
// (mirror cgen.c:3477 local arm).
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
emitoff((lc.off + fi.foff): i64);
|
||||
emitline("(BP), BX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
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");
|
||||
};
|
||||
};
|
||||
// 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
|
||||
@@ -5751,6 +5774,26 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
};
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
// Compound on local `str|slice` pseudo-field:
|
||||
// load current → push → eval rhs → combine →
|
||||
// store (mirror cgen.c:3235 local arm).
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP), BX\n");
|
||||
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");
|
||||
};
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP)\n");
|
||||
return;
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + delta): i64);
|
||||
|
||||
@@ -24299,7 +24299,30 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};};
|
||||
};
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
// Compound on direct struct-local
|
||||
// scalar field: load current → push
|
||||
// → eval rhs → combine → store
|
||||
// (mirror cgen.c:3477 local arm).
|
||||
let lop: str = fieldloadop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(lop);
|
||||
emitline("\t");
|
||||
emitoff((lc.off + fi.foff): i64);
|
||||
emitline("(BP), BX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
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");
|
||||
};
|
||||
};
|
||||
// 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
|
||||
@@ -24392,6 +24415,26 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
};
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
// Compound on local `str|slice` pseudo-field:
|
||||
// load current → push → eval rhs → combine →
|
||||
// store (mirror cgen.c:3235 local arm).
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP), BX\n");
|
||||
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");
|
||||
};
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + delta): i64);
|
||||
emitline("(BP)\n");
|
||||
return;
|
||||
};
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((lc.off + delta): i64);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
package data;
|
||||
|
||||
type point = struct { x: i32, y: i32 };
|
||||
|
||||
@test fn check_add() void = {
|
||||
let a: i32 = 2;
|
||||
let b: i32 = 3;
|
||||
@@ -21,3 +23,24 @@ package data;
|
||||
let _: i32 = 1 / 0;
|
||||
};
|
||||
};
|
||||
|
||||
// #227: compound assign (`-=`/`+=`) on a local field must
|
||||
// load-combine-store, not drop the op. Pre-fix wwstage stored the bare
|
||||
// rhs (p.x->4, p.y->5, view.len->1), so each mismatch aborts via 1/0.
|
||||
@test fn check_local_field_compound() void = {
|
||||
let p: point = point { x = 10i32, y = 3i32 };
|
||||
p.x -= 4i32;
|
||||
p.y += 5i32;
|
||||
if (p.x != 6) {
|
||||
let _: i32 = 1 / 0;
|
||||
};
|
||||
if (p.y != 8) {
|
||||
let _: i32 = 1 / 0;
|
||||
};
|
||||
let view: str = "hello";
|
||||
view.len -= 1;
|
||||
let n: i32 = view.len: i32;
|
||||
if (n != 4) {
|
||||
let _: i32 = 1 / 0;
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user