Files
ww/test/lang/arr_struct_subtail_frame_test.ww

66 lines
3.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// arr_struct_subtail_frame_test — #9: a local `[N]S` where S is a struct with
// a sub-8-tail field over-sized its stack FRAME (cs≠ww, gate-visible). The
// wwstage cgen frame reader (slotsize, cgenutil.ww TY_ARRAY arm) summed the
// element's slot-PADDED width (outer.slotsize 24) × N instead of the array's
// NATURAL size (outer.size 16) × N rounded to 8 — so `[2]outer` reserved $48
// where cstage reserves natural $32, and every later local stacked at a shifted
// BP offset. ROOT was the SAME dual-SSoT slotsize leak #75 fixed for the
// TY_STRUCT arm, never carried to its TY_ARRAY sibling; #9 applies the identical
// round8(ti.size) transform. ti.size == ti.slotsize for every array of prims /
// arrays / 8-multiple tagged elements, so the fix MOVES only this nested-sub-8-
// struct case (#48 [N]Alias and 1D/2D prim arrays are unchanged).
//
// The LOAD-BEARING tooth is the test-lang-byteid .s comparison: reverting the
// cgenutil.ww slotsize arm reddens this file (ww frame $48 vs cstage $32). The
// value asserts are a SECONDARY net — standalone ww is internally consistent at
// the inflated stride (it reserves AND addresses at the same over-sized frame),
// so a pure value run can pass while broken; they guard a future stride/offset
// regression, not the frame size. element_layout pins the natural per-element
// stride (16) and field offsets (a@0, p.x@1, p.y@2, z@8); cross_element pins
// that element 0 and element 1 don't alias after the fix shrinks the frame.
//
// Inline @test fns, not a row-table: the cases vary in the WRITE/READ place
// shape over a fixed struct layout, not in data over one operation, so a
// row-array `[](in,exp){}` can't express them (and that form is blocked by cgen
// #111). Mirrors dotbase_arr_test's #135 pins.
package arr_struct_subtail_frame_test;
type inner = struct { x: u8, y: u8 }; // natural 2, align 1
type outer = struct { a: u8, p: inner, z: i64 }; // natural 16, align 8 (sub-8 tail at p)
@test fn element_layout() void = {
let arr: [2]outer = [
outer { a = 1u8, p = inner { x = 2u8, y = 3u8 }, z = 100i64 },
outer { a = 4u8, p = inner { x = 5u8, y = 6u8 }, z = 200i64 }];
assert(arr[0].a: i32 == 1);
assert(arr[0].p.x: i32 == 2);
assert(arr[0].p.y: i32 == 3);
assert(arr[0].z == 100i64);
assert(arr[1].a: i32 == 4);
assert(arr[1].p.x: i32 == 5);
assert(arr[1].p.y: i32 == 6);
assert(arr[1].z == 200i64);
};
@test fn write_tail() void = { // write the sub-8 tail field then read back
let arr: [2]outer = [
outer { a = 1u8, p = inner { x = 2u8, y = 3u8 }, z = 100i64 },
outer { a = 4u8, p = inner { x = 5u8, y = 6u8 }, z = 200i64 }];
arr[1].z = 999i64;
arr[0].a = 7u8;
assert(arr[1].z == 999i64);
assert(arr[0].a: i32 == 7);
assert(arr[0].z == 100i64); // neighbour untouched
};
@test fn cross_element() void = { // element 0 and 1 are 16 apart, no alias
let arr: [2]outer = [
outer { a = 1u8, p = inner { x = 2u8, y = 3u8 }, z = 100i64 },
outer { a = 4u8, p = inner { x = 5u8, y = 6u8 }, z = 200i64 }];
arr[0].p.y = 77u8;
assert(arr[0].p.y: i32 == 77);
assert(arr[1].p.x: i32 == 5); // not clobbered by the elem-0 write
assert(arr[1].p.y: i32 == 6);
};