Files
ww/test/lang/idx_dot_aggret_recv_runonly_test.ww
Hojun-Cho a0e330b283 cgen: store all eightbytes when an in-cap aggregate call returns into a field of an indexed element (#11)
The arr[i].f=mk() assign arm had no aggregate-field sub-arm, so a by-value aggregate field receive fell to the scalar default (one MOVQ, dropping DX/CX) — silent on BOTH stages (byte-id blind). Add a dual-site symmetric in-cap N_CALL arm mirroring C2c (c83a340): scratch-first materialise AX/DX/CX, then word-copy to (fi.foff+k*8) within &arr[i], sizing from the natural field size fi.fsz (not slotsize). Rule-7 LOUD-STOP for the three cases the in-cap GP path cannot transport: over-cap sret (#11c/#234), a float-bearing field whose eightbyte classifies SSE (#11/#165), and a 3/5/6/7-byte sub-8 tail the single narrow tail MOV cannot express (the general cascade tail is the shared C2c/#11 follow-up, task #10). Value-asserting pins (poison-seeded, redden under each stage's independent revert) plus cfail pins for the three loud-stops.

Contained to the indexed base + in-cap call rhs; arr[i].f=src (#11b) and over-cap (#11c) are separate.
2026-06-27 18:49:03 +09:00

44 lines
1.9 KiB
Plaintext

// idx_dot_aggret_recv_runonly_test — #11 sub-8-tail anti-clobber through a
// LOCAL [N]<struct-with-sub-8-tail-field> array. The fix's MOVL (not MOVQ) tail
// + foff-on-every-eightbyte are VALUE-verified here: the dropped eb1 would read
// the poison 9, and a tail WIDENED to MOVQ would write bytes 8..15 and smash the
// adjacent g at +12 — both caught by asserting f.c AND g. Exit-correct under
// BOTH stages.
//
// _runonly (excluded from the test-lang-byteid T2 gate) because a local
// [N]<sub-8-tail-struct> trips a SEPARATE PRE-EXISTING let-array slotsize cs!=ww
// FRAME divergence — ww sizes the array element by slotsize (S slot-padded to
// 24 -> [2]S=48), cstage by natural size (S=16 -> 32) — that PREDATES and is
// INDEPENDENT of #11: `let arr:[2]S; return arr[1].g` already diverges $32 vs
// $48 with no call involved. The #11 receive INSTRUCTIONS are byte-identical
// (both stages emit the MOVL tail); only the container's frame SIZE differs.
// The byte-id twin (idx_dot_aggret_recv_test) covers the same sub-8-tail shape
// via global-backed bases, where the slotsize bug does not bite.
package idx_dot_aggret_recv_runonly_test;
type t12 = struct { a: i32, b: i32, c: i32 };
type s12 = struct { f: t12, g: i32 };
fn mk12() t12 = { return t12{a=10i32, b=20i32, c=30i32}; };
fn one() i64 = { return 1i64; };
@test fn subtail_local_const() void = {
let a: [2]s12 = [s12{f=t12{a=9i32,b=9i32,c=9i32},g=9i32}, s12{f=t12{a=9i32,b=9i32,c=9i32},g=9i32}];
a[1].f = mk12();
assert(a[1].f.a == 10i32);
assert(a[1].f.b == 20i32);
assert(a[1].f.c == 30i32);
assert(a[1].g == 9i32);
assert(a[0].f.a == 9i32);
};
@test fn subtail_local_runtime() void = {
let a: [2]s12 = [s12{f=t12{a=9i32,b=9i32,c=9i32},g=9i32}, s12{f=t12{a=9i32,b=9i32,c=9i32},g=9i32}];
a[one()].f = mk12();
assert(a[1].f.a == 10i32);
assert(a[1].f.b == 20i32);
assert(a[1].f.c == 30i32);
assert(a[1].g == 9i32);
};