Continue fold-2: migrate the #73 whole-struct field-copy ragged-tail test from a bespoke build+run C twin to test/lang @test, retiring the twin in the same commit. Runtime coverage MOVES from $(TESTS) to test-lang (T1 runs+asserts via `ww test`) + test-lang-byteid (T2 keeps cs==ww .s byte-id); coverage is preserved, the $(TESTS) headline drops 1 (422->421). All four rows are pure value-rows (no reject rows): each poisons `mark` at the inner struct's natural offset, copies, then asserts every field back with primitive int comparisons, so an 8-byte MOVQ that over-writes the ragged-tail successor FAILS. 989_structcopytail_run.c -> structcopytail_test.ww (tail2/tail6/tail7 ragged-tail copy preserves mark; ctl8 8-aligned control) This is the only Family-3 file with no build-must-fail rows; the three compound-OP= twins (948_idx_compound, 949_dotfield_compound, 949_idxfield_compound) carry loud //ww:error reject rows a runtime @test cannot replicate and are DEFERRED to a fold-3 value-split + reject-carrier pass (they stay fully in $(TESTS), no coverage lost). Bump LANGBYTEID_EXPECTED_MIN 34->35 to ratchet the new corpus floor.
77 lines
2.7 KiB
Plaintext
77 lines
2.7 KiB
Plaintext
// structcopytail_test — whole-struct field-copy ragged tail (#73, #263 both
|
|
// stages), migrated from test/wcc/989_structcopytail_run.c. 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. Pre-#73
|
|
// both stages' inline tail handled only {4,1}; a natural size %8 in {2,3,5,6,7}
|
|
// fell to a single MOVQ writing [0,8) and clobbering the `mark` field placed at
|
|
// the inner struct's natural offset. The fix routes both stages' field copy
|
|
// through the canonical greedy emitter. Each row poisons `mark` first, copies,
|
|
// then reads every field back; the .c returned the 1-based index of the first
|
|
// mismatch (0 = all-correct), here each field is asserted directly. T2
|
|
// (test-lang-byteid) keeps the cs==ww net the .c twin's dual-driver run gave.
|
|
|
|
package structcopytail_test;
|
|
|
|
type inner2 = struct { a: u8, b: u8 };
|
|
type outer2 = struct { i: inner2, mark: i32 };
|
|
|
|
type inner6 = struct { a: u16, b: u16, c: u16 };
|
|
type outer6 = struct { i: inner6, mark: u8 };
|
|
|
|
type inner7 = struct { a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8 };
|
|
type outer7 = struct { i: inner7, mark: u8 };
|
|
|
|
type inner8 = struct { a: i64 };
|
|
type outer8 = struct { i: inner8, mark: i64 };
|
|
|
|
@test fn tail2() void = {
|
|
// 2-byte inner; mark (nat offset 4) must survive the MOVW tail.
|
|
let o: inner2 = inner2 { a = 0x11, b = 0x22 };
|
|
let x: outer2;
|
|
x.mark = 0x7f7f7f7f;
|
|
x.i = o;
|
|
assert(x.i.a: int == 0x11);
|
|
assert(x.i.b: int == 0x22);
|
|
assert(x.mark == 0x7f7f7f7f);
|
|
};
|
|
|
|
@test fn tail6() void = {
|
|
// 6-byte inner; mark:u8 (nat offset 6) must survive the MOVL+MOVW tail.
|
|
let o: inner6 = inner6 { a = 0x1111, b = 0x2222, c = 0x3333 };
|
|
let x: outer6;
|
|
x.mark = 0x5a;
|
|
x.i = o;
|
|
assert(x.i.a: int == 0x1111);
|
|
assert(x.i.b: int == 0x2222);
|
|
assert(x.i.c: int == 0x3333);
|
|
assert(x.mark: int == 0x5a);
|
|
};
|
|
|
|
@test fn tail7() void = {
|
|
// 7-byte inner; the full MOVL+MOVW+MOVB ladder; mark:u8 at nat offset 7.
|
|
let o: inner7 = inner7 { a = 0x11, b = 0x22, c = 0x33, d = 0x44,
|
|
e = 0x55, f = 0x66, g = 0x77 };
|
|
let x: outer7;
|
|
x.mark = 0x5a;
|
|
x.i = o;
|
|
assert(x.i.a: int == 0x11);
|
|
assert(x.i.b: int == 0x22);
|
|
assert(x.i.c: int == 0x33);
|
|
assert(x.i.d: int == 0x44);
|
|
assert(x.i.e: int == 0x55);
|
|
assert(x.i.f: int == 0x66);
|
|
assert(x.i.g: int == 0x77);
|
|
assert(x.mark: int == 0x5a);
|
|
};
|
|
|
|
@test fn ctl8() void = {
|
|
// 8-aligned inner; the MOVQ loop alone, zero tail iterations (unchanged).
|
|
let o: inner8 = inner8 { a = 0x1234567 };
|
|
let x: outer8;
|
|
x.mark = 0x76543210;
|
|
x.i = o;
|
|
assert(x.i.a == 0x1234567);
|
|
assert(x.mark == 0x76543210);
|
|
};
|