w6c: chained-DOT struct field-copy tail uses 4/2/1 ladder, not over-MOVQ (#9)
The depth->=2 chained `t.m.l = s` struct-ident field copy selected its tail with (tail==4)?MOVL:(tail==1?MOVB:MOVQ), so every tail in {2,3,5,6,7} fell to an 8-byte MOVQ that over-wrote past the destination field — clobbering a @packed neighbour (t.m.l=s wrote s's slop over t.m.z: cstage exit 0 vs wwstage's correct 222) and diverging cs!=ww gate-blind. Replace with a descending 4/2/1 MOVL/MOVW/MOVB ladder comparing to ssz (the field's natural type-table size), aligning cstage UP to wwstage's sized ladder + cg_aggcopy. New table-driven gate 949_chained_dot_struct_copy_run (7 sizes x runtime-exit oracle on both drivers + cs==ww byte-id; negative-control proven).
This commit is contained in:
@@ -6365,19 +6365,57 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
amem(D_BP, base_disp + total_off + k));
|
||||
k += 8;
|
||||
}
|
||||
if (k < ssz) {
|
||||
int tail = ssz - k;
|
||||
int lop = (tail == 4) ? A_MOVL
|
||||
: (tail == 1 ? A_MOVB : A_MOVQ);
|
||||
ins2(c, lop,
|
||||
/* Descending 4/2/1 sized tail, not a
|
||||
* 4/1-then-MOVQ: ssz is the field's
|
||||
* natural (non-slot-padded) struct size,
|
||||
* so a tail of {2,3,5,6,7} packs at its
|
||||
* own stride (struct{u16,[8]u8}=10 has
|
||||
* tail 2). The old `tail==1?MOVB:MOVQ`
|
||||
* fell every other tail to an 8B MOVQ that
|
||||
* over-writes past the destination FIELD —
|
||||
* a @packed neighbour gets clobbered (the
|
||||
* depth-≥2 chained `t.m.l = s` wrote s's
|
||||
* slop over t.m.z, exit 0 not 222) and
|
||||
* cstage diverged from wwstage's sized
|
||||
* MOVW (gate-blind cs≠ww). Aligns cstage
|
||||
* UP to the wwstage 8/4/2/1 ladder
|
||||
* (cgenexpr.ww:10083) and cg_aggcopy.
|
||||
* #107 class. */
|
||||
if (k + 4 <= ssz) {
|
||||
ins2(c, A_MOVL,
|
||||
amem(D_BP, soff + k),
|
||||
areg(D_AX));
|
||||
if (via_cx)
|
||||
ins2(c, lop, areg(D_AX),
|
||||
ins2(c, A_MOVL, areg(D_AX),
|
||||
amem(D_CX, total_off + k));
|
||||
else
|
||||
ins2(c, lop, areg(D_AX),
|
||||
ins2(c, A_MOVL, areg(D_AX),
|
||||
amem(D_BP, base_disp + total_off + k));
|
||||
k += 4;
|
||||
}
|
||||
if (k + 2 <= ssz) {
|
||||
ins2(c, A_MOVW,
|
||||
amem(D_BP, soff + k),
|
||||
areg(D_AX));
|
||||
if (via_cx)
|
||||
ins2(c, A_MOVW, areg(D_AX),
|
||||
amem(D_CX, total_off + k));
|
||||
else
|
||||
ins2(c, A_MOVW, areg(D_AX),
|
||||
amem(D_BP, base_disp + total_off + k));
|
||||
k += 2;
|
||||
}
|
||||
if (k + 1 <= ssz) {
|
||||
ins2(c, A_MOVB,
|
||||
amem(D_BP, soff + k),
|
||||
areg(D_AX));
|
||||
if (via_cx)
|
||||
ins2(c, A_MOVB, areg(D_AX),
|
||||
amem(D_CX, total_off + k));
|
||||
else
|
||||
ins2(c, A_MOVB, areg(D_AX),
|
||||
amem(D_BP, base_disp + total_off + k));
|
||||
k += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user