wcc: whole-struct field-copy completes the ragged tail greedily, both stages
A `x.f = o` copy of a whole struct field emits a MOVQ run for the
8-byte chunks plus a tail. Both stages inlined a tail that handled only
{4,1}: a 4-byte remainder went MOVL, a 1-byte MOVB, but {2,3,5,6,7} fell
through to an 8-byte MOVQ that OVER-READS the source and OVER-WRITES the
field's natural-offset successor. With #44 packing a successor at its
natural offset, that is a live clobber: outer2{i:inner2{u8,u8}, mark:i32}
copies i with `MOVQ -8(BP),AX; MOVQ AX,-16(BP)` and wipes mark@-12; the
correct move is a single MOVW. Same defect in cstage (cgen.c) and the
four wwstage field-copy sites (cgenexpr.ww: via-ptr, direct-BP-local,
global, and the multi-hop dot-chain CX variant).
Fix: replace each inline {4,1} tail with the descending greedy 4/2/1
(MOVL/MOVW/MOVB) the canonical aggregate-copy emitters already use, so
the tail is complete on every natural size. This is path (alpha) of the
#73 brief — a corpus-neutral, no-workaround completion of the inline
tail. Routing field copies through the shared aggcopy/cg_aggcopy choke-
point (beta) is the balloon: those emitters hardcode (SI)->(BX) at offset
k with zero base displacement, but the four field-copy dsts are
heterogeneous (foff(BX), boff+foff(BP) with no base reg, totaloff(CX)),
so routing forces per-site-per-stage LEAQ src->SI + LEAQ dst->BX rewrites
with no mechanical cross-stage mirror at the CX site = a gate-blind
cs!=ww risk. The emitter extraction is filed as a later addressing-
unification arc (#12). The ragged tail is corpus-absent (every corpus
field copy is tail in {0,4}, where greedy 4/2/1 emits exactly what the
old {4,1} tail did), so this is CLASS-N: zero corpus move on both stages,
byte-id holds by construction.
The cstage <=24 N_CALL receive site (cgen.c:5234) is a different copy
family (sret result read from AX/DX/CX, not a mem-to-mem field copy) and
already handles 4/2/1; left untouched. The str/slice/tagged/tuple 4/1
sites (#76) are likewise a separate family, filed not folded.
989_structcopytail_run pins it on both driver twins: tail2 (MOVW), tail6
(MOVL+MOVW), tail7 (the full MOVL+MOVW+MOVB ladder, the MOVB-path row),
plus an 8-aligned ctl8 (tail-0 control). Pre-fix cstage clobbers mark and
exits non-zero -> cs!=ww; post-fix 4/4 ok cs==ww.
This commit is contained in:
17
Makefile
17
Makefile
@@ -258,6 +258,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
|
|||||||
$(BIN)/test_tagtupfieldsize_run \
|
$(BIN)/test_tagtupfieldsize_run \
|
||||||
$(BIN)/test_nestfield_run \
|
$(BIN)/test_nestfield_run \
|
||||||
$(BIN)/test_structlocal_frame \
|
$(BIN)/test_structlocal_frame \
|
||||||
|
$(BIN)/test_structcopytail_run \
|
||||||
$(BIN)/test_arrlit_tail_zero_run \
|
$(BIN)/test_arrlit_tail_zero_run \
|
||||||
$(BIN)/test_defdim_slice_run \
|
$(BIN)/test_defdim_slice_run \
|
||||||
$(BIN)/test_trystr_run \
|
$(BIN)/test_trystr_run \
|
||||||
@@ -789,6 +790,22 @@ $(BIN)/test_structlocal_frame: test/wcc/989_structlocal_frame.c \
|
|||||||
$(BIN)/w6c $(BIN)/w6c_ww | $(BIN)
|
$(BIN)/w6c $(BIN)/w6c_ww | $(BIN)
|
||||||
$(CC) $(CFLAGS) -o $@ $<
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
# 989_structcopytail_run (#73): a whole-struct field-copy `x.i = o` whose
|
||||||
|
# source natural size %8 lands in {2,3,5,6,7} must move exactly that many
|
||||||
|
# bytes via a descending greedy 8->4->2->1 tail (MOVL/MOVW/MOVB), not round
|
||||||
|
# the ragged remainder up to an 8-byte MOVQ that over-writes the field's
|
||||||
|
# natural-offset successor. BOTH stages inlined a tail handling only {4,1};
|
||||||
|
# tail-2 (inner2{u8,u8} in outer2{i,mark:i32}) and tail-6 (inner6{u16,u16,
|
||||||
|
# u16} in outer6{i,mark:u8}) over-wrote MARK with an 8B MOVQ. Builds+runs on
|
||||||
|
# BOTH driver twins (rule-10), pinning the absolute 0; ctl8 (8-aligned, zero
|
||||||
|
# tail) pins the unchanged path.
|
||||||
|
$(BIN)/test_structcopytail_run: test/wcc/989_structcopytail_run.c \
|
||||||
|
$(BIN)/ww $(BIN)/ww_ww \
|
||||||
|
$(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
|
||||||
|
$(BIN)/w6c_ww $(BIN)/w6a_ww $(BIN)/w6l_ww \
|
||||||
|
$(LIB)/libwwrt.a | $(BIN)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
# 989_arrlit_tail_zero_run (#13): an under-length array literal zero-fills the
|
# 989_arrlit_tail_zero_run (#13): an under-length array literal zero-fills the
|
||||||
# unspecified tail, not the last value. Builds+runs on BOTH driver twins
|
# unspecified tail, not the last value. Builds+runs on BOTH driver twins
|
||||||
# (rule-10), pinning the absolute value (pre-fix ww tail = last value).
|
# (rule-10), pinning the absolute value (pre-fix ww tail = last value).
|
||||||
|
|||||||
@@ -5313,15 +5313,29 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, boff + foff + k));
|
ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, boff + foff + k));
|
||||||
k += 8;
|
k += 8;
|
||||||
}
|
}
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
int tail = ssz - k;
|
ins2(c, A_MOVL, amem(D_BP, soff + k), areg(D_AX));
|
||||||
int lop = (tail == 4) ? A_MOVL
|
|
||||||
: (tail == 1 ? A_MOVB : A_MOVQ);
|
|
||||||
ins2(c, lop, amem(D_BP, soff + k), areg(D_AX));
|
|
||||||
if (via_ptr || is_global)
|
if (via_ptr || is_global)
|
||||||
ins2(c, lop, areg(D_AX), amem(D_BX, foff + k));
|
ins2(c, A_MOVL, areg(D_AX), amem(D_BX, foff + k));
|
||||||
else
|
else
|
||||||
ins2(c, lop, areg(D_AX), amem(D_BP, boff + foff + k));
|
ins2(c, A_MOVL, areg(D_AX), amem(D_BP, boff + foff + k));
|
||||||
|
k += 4;
|
||||||
|
}
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
ins2(c, A_MOVW, amem(D_BP, soff + k), areg(D_AX));
|
||||||
|
if (via_ptr || is_global)
|
||||||
|
ins2(c, A_MOVW, areg(D_AX), amem(D_BX, foff + k));
|
||||||
|
else
|
||||||
|
ins2(c, A_MOVW, areg(D_AX), amem(D_BP, boff + foff + k));
|
||||||
|
k += 2;
|
||||||
|
}
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
ins2(c, A_MOVB, amem(D_BP, soff + k), areg(D_AX));
|
||||||
|
if (via_ptr || is_global)
|
||||||
|
ins2(c, A_MOVB, areg(D_AX), amem(D_BX, foff + k));
|
||||||
|
else
|
||||||
|
ins2(c, A_MOVB, areg(D_AX), amem(D_BP, boff + foff + k));
|
||||||
|
k += 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33325,21 +33325,32 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\n");
|
emitline("\n");
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitdispreg((fi.foff + k): i64, "BX");
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
emitline("\n");
|
emitline("\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
@@ -33551,21 +33562,32 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitoff((lc.off + fi.foff + k): i64);
|
emitoff((lc.off + fi.foff + k): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitoff((lc.off + fi.foff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitoff((lc.off + fi.foff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
@@ -33838,21 +33860,32 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\n");
|
emitline("\n");
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitdispreg((fi.foff + k): i64, "BX");
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
emitline("\n");
|
emitline("\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
@@ -34487,29 +34520,50 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitdispreg((totaloff + k): i64, "CX");
|
emitdispreg((totaloff + k): i64, "CX");
|
||||||
emitline("\n");
|
emitline("\n");
|
||||||
} else {
|
} else {
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitoff((rootoff + totaloff + k): i64);
|
emitoff((rootoff + totaloff + k): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
};
|
};
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
if (viacx) {
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitdispreg((totaloff + k): i64, "CX");
|
||||||
|
emitline("\n");
|
||||||
|
} else {
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitoff((rootoff + totaloff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
if (viacx) {
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitdispreg((totaloff + k): i64, "CX");
|
||||||
|
emitline("\n");
|
||||||
|
} else {
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitoff((rootoff + totaloff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
|
|||||||
@@ -9979,21 +9979,32 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\n");
|
emitline("\n");
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitdispreg((fi.foff + k): i64, "BX");
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
emitline("\n");
|
emitline("\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
@@ -10205,21 +10216,32 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitoff((lc.off + fi.foff + k): i64);
|
emitoff((lc.off + fi.foff + k): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitoff((lc.off + fi.foff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitoff((lc.off + fi.foff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
@@ -10492,21 +10514,32 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\n");
|
emitline("\n");
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitdispreg((fi.foff + k): i64, "BX");
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
emitline("\n");
|
emitline("\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
@@ -11141,29 +11174,50 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitdispreg((totaloff + k): i64, "CX");
|
emitdispreg((totaloff + k): i64, "CX");
|
||||||
emitline("\n");
|
emitline("\n");
|
||||||
} else {
|
} else {
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitoff((rootoff + totaloff + k): i64);
|
emitoff((rootoff + totaloff + k): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
};
|
};
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
if (viacx) {
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitdispreg((totaloff + k): i64, "CX");
|
||||||
|
emitline("\n");
|
||||||
|
} else {
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitoff((rootoff + totaloff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
if (viacx) {
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitdispreg((totaloff + k): i64, "CX");
|
||||||
|
emitline("\n");
|
||||||
|
} else {
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitoff((rootoff + totaloff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
|
|||||||
@@ -33325,21 +33325,32 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\n");
|
emitline("\n");
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitdispreg((fi.foff + k): i64, "BX");
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
emitline("\n");
|
emitline("\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
@@ -33551,21 +33562,32 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitoff((lc.off + fi.foff + k): i64);
|
emitoff((lc.off + fi.foff + k): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitoff((lc.off + fi.foff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitoff((lc.off + fi.foff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
@@ -33838,21 +33860,32 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\n");
|
emitline("\n");
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitdispreg((fi.foff + k): i64, "BX");
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
emitline("\n");
|
emitline("\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitdispreg((fi.foff + k): i64, "BX");
|
||||||
|
emitline("\n");
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
@@ -34487,29 +34520,50 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
k += 8;
|
k += 8;
|
||||||
};
|
};
|
||||||
if (k < ssz) {
|
if (k + 4 <= ssz) {
|
||||||
let tail: i32 = ssz - k;
|
emitline("\tMOVL\t");
|
||||||
let lop: str = "MOVQ";
|
|
||||||
if (tail == 4) { lop = "MOVL"; }
|
|
||||||
else { if (tail == 1) { lop = "MOVB"; }; };
|
|
||||||
emitline("\t");
|
|
||||||
emitline(lop);
|
|
||||||
emitline("\t");
|
|
||||||
emitoff((srhs.off + k): i64);
|
emitoff((srhs.off + k): i64);
|
||||||
emitline("(BP), AX\n");
|
emitline("(BP), AX\n");
|
||||||
if (viacx) {
|
if (viacx) {
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitdispreg((totaloff + k): i64, "CX");
|
emitdispreg((totaloff + k): i64, "CX");
|
||||||
emitline("\n");
|
emitline("\n");
|
||||||
} else {
|
} else {
|
||||||
emitline("\t");
|
emitline("\tMOVL\tAX, ");
|
||||||
emitline(lop);
|
|
||||||
emitline("\tAX, ");
|
|
||||||
emitoff((rootoff + totaloff + k): i64);
|
emitoff((rootoff + totaloff + k): i64);
|
||||||
emitline("(BP)\n");
|
emitline("(BP)\n");
|
||||||
};
|
};
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
if (k + 2 <= ssz) {
|
||||||
|
emitline("\tMOVW\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
if (viacx) {
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitdispreg((totaloff + k): i64, "CX");
|
||||||
|
emitline("\n");
|
||||||
|
} else {
|
||||||
|
emitline("\tMOVW\tAX, ");
|
||||||
|
emitoff((rootoff + totaloff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
k += 2;
|
||||||
|
};
|
||||||
|
if (k + 1 <= ssz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((srhs.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
if (viacx) {
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitdispreg((totaloff + k): i64, "CX");
|
||||||
|
emitline("\n");
|
||||||
|
} else {
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitoff((rootoff + totaloff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
k += 1;
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
};};
|
};};
|
||||||
|
|||||||
235
test/wcc/989_structcopytail_run.c
Normal file
235
test/wcc/989_structcopytail_run.c
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
* 989_structcopytail_run — #73 teeth (recorded by impl-55, 2026-06-13).
|
||||||
|
*
|
||||||
|
* Whole-struct field-copy ragged tail. A `x.i = o` copy of a struct whose
|
||||||
|
* NATURAL size is not 8-aligned must move exactly that many bytes via a
|
||||||
|
* descending-greedy 8->4->2->1 tail (MOVL/MOVW/MOVB), NOT round up to an
|
||||||
|
* 8-byte MOVQ that bleeds into the field's natural-offset successor.
|
||||||
|
*
|
||||||
|
* THIS TEST IS cs!=ww-RED UNTIL #73. As impl-55 proved (2026-06-13), BOTH
|
||||||
|
* stages inline a tail handling only {4,1}; a natural size %8 in
|
||||||
|
* {2,3,5,6,7} falls through to an 8-byte MOVQ over-write:
|
||||||
|
* - wwstage: cgenexpr.ww 4 field-copy sites (now length-correct via #71,
|
||||||
|
* tail still 4/1).
|
||||||
|
* - cstage: cmd/w6c/cgen.c:5302/5318 (+ siblings 2970/3332/5268/6255/
|
||||||
|
* 6314/7259) — str_fu->size length is already natural, tail is 4/1.
|
||||||
|
* ASM PROOF (tail2, x.i = o): cstage emits `MOVQ -8(BP),AX; MOVQ AX,-16(BP)`
|
||||||
|
* (8B over-write -> clobbers mark@-12). #73 routes both stages' field copy
|
||||||
|
* through the canonical greedy emitter (cstage cg_aggcopy@2241 / ww
|
||||||
|
* aggcopy@1662), completing the tail on both -> this test goes green
|
||||||
|
* cs==ww. Do NOT wire it before #73 lands.
|
||||||
|
*
|
||||||
|
* Shapes:
|
||||||
|
* tail2: inner2{a:u8,b:u8} (size 2) in outer2{i:inner2, mark:i32}; #44
|
||||||
|
* packs mark at natural offset 4. A MOVQ copy of i writes [0,8)
|
||||||
|
* and clobbers mark@4; the MOVW tail writes [0,2).
|
||||||
|
* tail6: inner6{a:u16,b:u16,c:u16} (size 6) in outer6{i:inner6, mark:u8};
|
||||||
|
* mark at natural offset 6. A MOVQ copy writes [0,8) and clobbers
|
||||||
|
* mark@6; the MOVL+MOVW tail writes [0,6).
|
||||||
|
* ctl8: inner8{a:i64} (size 8, 8-aligned) — the MOVQ loop alone, no
|
||||||
|
* tail; proves the 8-aligned path is unchanged.
|
||||||
|
* Each program reads every field back and returns the 1-based index of the
|
||||||
|
* first mismatch, 0 on all-correct. Both stages build+run (rule-10), pin 0.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
runwait(const char *cmd)
|
||||||
|
{
|
||||||
|
int rc = system(cmd);
|
||||||
|
if (rc == -1) return -1;
|
||||||
|
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct row {
|
||||||
|
const char *label;
|
||||||
|
const char *src;
|
||||||
|
int want_exit; /* >= 0: pin the absolute value; -1: cs==ww only */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct row rows[] = {
|
||||||
|
/* tail2 — whole-copy of a 2-byte struct; mark (nat offset 4) must
|
||||||
|
* survive. Pre-tail-fix MOVQ writes [0,8) -> mark clobbered. */
|
||||||
|
{ "tail2",
|
||||||
|
"package main;\n"
|
||||||
|
"type inner2 = struct { a: u8, b: u8 };\n"
|
||||||
|
"type outer2 = struct { i: inner2, mark: i32 };\n"
|
||||||
|
"export fn main() int = {\n"
|
||||||
|
" let o: inner2 = inner2 { a = 0x11, b = 0x22 };\n"
|
||||||
|
" let x: outer2;\n"
|
||||||
|
" x.mark = 0x7f7f7f7f;\n"
|
||||||
|
" x.i = o;\n"
|
||||||
|
" if (x.i.a: int != 0x11) { return 1; };\n"
|
||||||
|
" if (x.i.b: int != 0x22) { return 2; };\n"
|
||||||
|
" if (x.mark != 0x7f7f7f7f) { return 3; };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n",
|
||||||
|
0 },
|
||||||
|
|
||||||
|
/* tail6 — whole-copy of a 6-byte struct; mark:u8 (nat offset 6) must
|
||||||
|
* survive. Pre-tail-fix MOVQ writes [0,8) -> mark clobbered; the
|
||||||
|
* MOVL+MOVW tail writes exactly [0,6). */
|
||||||
|
{ "tail6",
|
||||||
|
"package main;\n"
|
||||||
|
"type inner6 = struct { a: u16, b: u16, c: u16 };\n"
|
||||||
|
"type outer6 = struct { i: inner6, mark: u8 };\n"
|
||||||
|
"export fn main() int = {\n"
|
||||||
|
" let o: inner6 = inner6 { a = 0x1111, b = 0x2222, c = 0x3333 };\n"
|
||||||
|
" let x: outer6;\n"
|
||||||
|
" x.mark = 0x5a;\n"
|
||||||
|
" x.i = o;\n"
|
||||||
|
" if (x.i.a: int != 0x1111) { return 1; };\n"
|
||||||
|
" if (x.i.b: int != 0x2222) { return 2; };\n"
|
||||||
|
" if (x.i.c: int != 0x3333) { return 3; };\n"
|
||||||
|
" if (x.mark: int != 0x5a) { return 4; };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n",
|
||||||
|
0 },
|
||||||
|
|
||||||
|
/* tail7 — whole-copy of a 7-byte struct (seven u8, align 1); mark:u8
|
||||||
|
* at natural offset 7 must survive. Exercises the FULL descending tail
|
||||||
|
* ladder in one shape: MOVL[0,4) + MOVW[4,6) + MOVB[6,7). Pre-fix the
|
||||||
|
* 4/1-only tail defaulted size-7 to a single 8-byte MOVQ writing [0,8)
|
||||||
|
* -> clobbers mark@7; this is the only row hitting the MOVB tail. */
|
||||||
|
{ "tail7",
|
||||||
|
"package main;\n"
|
||||||
|
"type inner7 = struct { a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8 };\n"
|
||||||
|
"type outer7 = struct { i: inner7, mark: u8 };\n"
|
||||||
|
"export fn main() int = {\n"
|
||||||
|
" let o: inner7 = inner7 { a = 0x11, b = 0x22, c = 0x33, d = 0x44, e = 0x55, f = 0x66, g = 0x77 };\n"
|
||||||
|
" let x: outer7;\n"
|
||||||
|
" x.mark = 0x5a;\n"
|
||||||
|
" x.i = o;\n"
|
||||||
|
" if (x.i.a: int != 0x11) { return 1; };\n"
|
||||||
|
" if (x.i.b: int != 0x22) { return 2; };\n"
|
||||||
|
" if (x.i.c: int != 0x33) { return 3; };\n"
|
||||||
|
" if (x.i.d: int != 0x44) { return 4; };\n"
|
||||||
|
" if (x.i.e: int != 0x55) { return 5; };\n"
|
||||||
|
" if (x.i.f: int != 0x66) { return 6; };\n"
|
||||||
|
" if (x.i.g: int != 0x77) { return 7; };\n"
|
||||||
|
" if (x.mark: int != 0x5a) { return 8; };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n",
|
||||||
|
0 },
|
||||||
|
|
||||||
|
/* ctl8 — 8-aligned struct: the MOVQ loop alone, zero tail iterations.
|
||||||
|
* Proves the 8-aligned emission path stays correct (byte-id caveat). */
|
||||||
|
{ "ctl8",
|
||||||
|
"package main;\n"
|
||||||
|
"type inner8 = struct { a: i64 };\n"
|
||||||
|
"type outer8 = struct { i: inner8, mark: i64 };\n"
|
||||||
|
"export fn main() int = {\n"
|
||||||
|
" let o: inner8 = inner8 { a = 0x1234567 };\n"
|
||||||
|
" let x: outer8;\n"
|
||||||
|
" x.mark = 0x76543210;\n"
|
||||||
|
" x.i = o;\n"
|
||||||
|
" if (x.i.a != 0x1234567) { return 1; };\n"
|
||||||
|
" if (x.mark != 0x76543210) { return 2; };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n",
|
||||||
|
0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* run_build — build+run `src` via `driver`; returns the binary's exit
|
||||||
|
* code, or -1 on a build failure. */
|
||||||
|
static int
|
||||||
|
run_build(const char *driver, const struct row *r, int i)
|
||||||
|
{
|
||||||
|
char src[64], tmpdir[64], cmd[1024];
|
||||||
|
snprintf(src, sizeof src, "/tmp/sctail_%d_%d.ww", getpid(), i);
|
||||||
|
snprintf(tmpdir, sizeof tmpdir, "/tmp/sctail_%d_d_%d", getpid(), i);
|
||||||
|
|
||||||
|
FILE *f = fopen(src, "wb");
|
||||||
|
if (!f) return -2;
|
||||||
|
fputs(r->src, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
mkdir(tmpdir, 0755);
|
||||||
|
snprintf(cmd, sizeof cmd, "cd %s && %s build %s 2>/dev/null",
|
||||||
|
tmpdir, driver, src);
|
||||||
|
int brc = runwait(cmd);
|
||||||
|
|
||||||
|
const char *base = strrchr(src, '/');
|
||||||
|
base = base ? base + 1 : src;
|
||||||
|
char outbin[128];
|
||||||
|
snprintf(outbin, sizeof outbin, "%s/%s", tmpdir, base);
|
||||||
|
char *dot = strrchr(outbin, '.');
|
||||||
|
if (dot && strcmp(dot, ".ww") == 0) *dot = '\0';
|
||||||
|
|
||||||
|
int got = -1;
|
||||||
|
if (brc == 0) got = runwait(outbin);
|
||||||
|
|
||||||
|
unlink(src); unlink(outbin); rmdir(tmpdir);
|
||||||
|
return brc == 0 ? got : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
const char *bin = getenv("BIN");
|
||||||
|
if (!bin) bin = "out/bin";
|
||||||
|
char absbin[1024];
|
||||||
|
if (bin[0] != '/') {
|
||||||
|
char cwd[1024];
|
||||||
|
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
|
||||||
|
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
|
||||||
|
bin = absbin;
|
||||||
|
}
|
||||||
|
|
||||||
|
char cdrv[1024], wdrv[1024];
|
||||||
|
snprintf(cdrv, sizeof cdrv, "%s/ww", bin);
|
||||||
|
snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin);
|
||||||
|
int have_ww = (access(wdrv, X_OK) == 0);
|
||||||
|
|
||||||
|
int n = (int)(sizeof rows / sizeof rows[0]);
|
||||||
|
int total = 0, fail = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
total++;
|
||||||
|
int gc = run_build(cdrv, &rows[i], i);
|
||||||
|
if (gc < 0) {
|
||||||
|
fprintf(stderr, "structcopytail_run[cstage][%s]: build/run "
|
||||||
|
"failed (got %d)\n", rows[i].label, gc);
|
||||||
|
fail++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rows[i].want_exit >= 0 && gc != rows[i].want_exit) {
|
||||||
|
fprintf(stderr, "structcopytail_run[cstage][%s]: exit=%d "
|
||||||
|
"want=%d (field/clobber mismatch)\n",
|
||||||
|
rows[i].label, gc, rows[i].want_exit);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
if (!have_ww) {
|
||||||
|
fprintf(stderr, "structcopytail_run: skip wwstage (no %s)\n",
|
||||||
|
wdrv);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int gw = run_build(wdrv, &rows[i], i);
|
||||||
|
if (gw != gc) {
|
||||||
|
fprintf(stderr, "structcopytail_run[%s]: cs=%d != ww=%d "
|
||||||
|
"(copy-tail divergence — #71)\n",
|
||||||
|
rows[i].label, gc, gw);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
if (rows[i].want_exit >= 0 && gw != rows[i].want_exit) {
|
||||||
|
fprintf(stderr, "structcopytail_run[wwstage][%s]: exit=%d "
|
||||||
|
"want=%d (field/clobber mismatch)\n",
|
||||||
|
rows[i].label, gw, rows[i].want_exit);
|
||||||
|
fail++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail) {
|
||||||
|
fprintf(stderr, "structcopytail_run: %d/%d checks failed\n",
|
||||||
|
fail, total);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("structcopytail_run: %d/%d ok\n", total, total);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user