Completes the #14 close-by-construction begun by the helper extraction (e7fefa3): every <=24B aggregate register-store now routes through cg_agg_reg_store/cgaggregstore and handles all tail sizes. B/C/D/G fix a silent both-stage drop of a 3/5/6/7-byte tail (byte-id-blind: both stages dropped identically, so the gate could not see it). A/F enable a previously loud-rejected shape (a cgen backend gap, not a type rejection; harec accepts and lowers it). G (global g=f() array) routes symmetrically, dest_padded=false. The #11 arr[i].f scratch loops fold into the helper (dest_padded=true, byte-id zero-change), completing the grep-audit. Pins value-assert each eightbyte (the class is byte-id-blind) and redden under each stage's independent revert; site H's 3/5/6/7 let-receive stays a loud fatal (#22).
139 lines
5.4 KiB
Plaintext
139 lines
5.4 KiB
Plaintext
// narrow_tail_widen_test — #14 commit-2: the narrow-tail aggregate-register
|
|
// materialise choke-point (cg_agg_reg_store / cgaggregstore), now reached by
|
|
// the WIDENED gates. Before #14 these sites gated `tail%8 ∈ {0,1,2,4}` and a
|
|
// 3/5/6/7-byte aggregate tail fell through to a lone narrow MOV (a SILENT
|
|
// both-stage member drop — both cstage and wwstage emitted IDENTICALLY wrong
|
|
// asm, so byte-id was GREEN and BLIND). Widening each gate to the full
|
|
// `sz<=24` routes 3/5/6/7 through the choke-point's non-padded scratch detour
|
|
// (dest_padded=false: MOVQ the tail eightbyte into a ceil-8 pad, then an
|
|
// exact `tail`-byte aggcopy into the packed dest).
|
|
//
|
|
// Each @test POISON-SEEDS every dest eightbyte with a sentinel distinct from
|
|
// every mk() value, performs the aggregate store, then value-asserts each
|
|
// eightbyte INCLUDING the dropped 3/5/6/7 tail word. A drop leaves the poison
|
|
// (mismatch). Where the dest is a PACKED field/element (C, D) a trailing
|
|
// neighbour is sentinel-checked too: it pins dest_padded=FALSE (a wrong =true
|
|
// would over-store the tail eightbyte and clobber the neighbour).
|
|
//
|
|
// Heterogeneous shapes per site + #111 (row-array @test blocked) => inline
|
|
// @test fns, not a row table. A 14B struct/array (maxalign<=2) keeps a real
|
|
// tail-6: an i64-bearing field pads to 16B (tail 0) and never trips it.
|
|
|
|
package narrow_tail_widen_test;
|
|
|
|
type t14 = struct { v: [7]i16 }; // 14B: full=1, tail=6
|
|
type boxed = struct { f: t14, guard: i16 }; // f@0 (14B), guard@14
|
|
type nested = struct { m: boxed }; // o.m.f chained dot
|
|
type myerr = !i32; // site B unwrap error variant
|
|
|
|
fn mk14() t14 = {
|
|
return t14 { v = [10i16, 20i16, 30i16, 40i16, 50i16, 60i16, 70i16] };
|
|
};
|
|
fn mk7arr() [7]i16 = {
|
|
return [10i16, 20i16, 30i16, 40i16, 50i16, 60i16, 70i16];
|
|
};
|
|
fn mk14res() (t14 | myerr) = {
|
|
return t14 { v = [10i16, 20i16, 30i16, 40i16, 50i16, 60i16, 70i16] };
|
|
};
|
|
|
|
let gg: [7]i16 = [0i16, 0i16, 0i16, 0i16, 0i16, 0i16, 0i16]; // site G dest
|
|
let gb: boxed = boxed { // site B dest
|
|
f = t14 { v = [0i16, 0i16, 0i16, 0i16, 0i16, 0i16, 0i16] },
|
|
guard = 0i16,
|
|
};
|
|
|
|
fn poison7(p: *[7]i16) void = {
|
|
let i: i32 = 0;
|
|
for (i < 7) { p[i] = 0x7f7fi16; i += 1; };
|
|
};
|
|
|
|
// Site F (cstage cgen.c N_ASSIGN local-ident array `g = call`; ww cgenexpr.ww
|
|
// 12574). Whole local array reassign from an aggregate-returning call.
|
|
@test fn f_local_array() void = {
|
|
let g: [7]i16;
|
|
poison7(&g);
|
|
g = mk7arr();
|
|
assert(g[0] == 10i16);
|
|
assert(g[3] == 40i16);
|
|
assert(g[4] == 50i16); // eb1 byte 0-1
|
|
assert(g[5] == 60i16); // eb1 byte 2-3 — tail, dropped pre-#14
|
|
assert(g[6] == 70i16); // eb1 byte 4-5 — tail, dropped pre-#14
|
|
};
|
|
|
|
// Site F (struct twin; ww cgenexpr.ww 12537). Whole local struct reassign.
|
|
@test fn f_local_struct() void = {
|
|
let s: t14;
|
|
poison7(&s.v);
|
|
s = mk14();
|
|
assert(s.v[0] == 10i16);
|
|
assert(s.v[4] == 50i16);
|
|
assert(s.v[5] == 60i16); // tail, dropped pre-#14
|
|
assert(s.v[6] == 70i16); // tail, dropped pre-#14
|
|
};
|
|
|
|
// Site G (cstage cgen.c N_ASSIGN global-ident array `g = call`, the inline
|
|
// loop now routed; ww cgenexpr.ww 12231). Whole GLOBAL array reassign — G
|
|
// had NO {0,1,2,4} gate, it dropped 3/5/6/7 via a lone MOVB.
|
|
@test fn g_global_array() void = {
|
|
poison7(&gg);
|
|
gg = mk7arr();
|
|
assert(gg[0] == 10i16);
|
|
assert(gg[4] == 50i16);
|
|
assert(gg[5] == 60i16); // tail, dropped pre-#14 (MOVB wrote only byte 0)
|
|
assert(gg[6] == 70i16); // tail, dropped pre-#14
|
|
};
|
|
|
|
// Site C (cstage cgen.c single-dot `b.f = call`; ww cgenexpr.ww 10845 local
|
|
// twin). PACKED field => guard neighbour pins dest_padded=false.
|
|
@test fn c_single_dot() void = {
|
|
let b: boxed;
|
|
poison7(&b.f.v);
|
|
b.guard = 0x55aai16; // neighbour sentinel
|
|
b.f = mk14();
|
|
assert(b.f.v[0] == 10i16);
|
|
assert(b.f.v[4] == 50i16);
|
|
assert(b.f.v[5] == 60i16); // tail, dropped pre-#14
|
|
assert(b.f.v[6] == 70i16); // tail, dropped pre-#14
|
|
assert(b.guard == 0x55aai16); // intact: tail aggcopy is exactly 6 bytes
|
|
};
|
|
|
|
// Site D (cstage cgen.c chained-dot terminal `o.m.f = call`; ww cgenexpr.ww
|
|
// 11781). PACKED field of a nested struct => guard neighbour check.
|
|
@test fn d_chained_dot() void = {
|
|
let o: nested;
|
|
poison7(&o.m.f.v);
|
|
o.m.guard = 0x55aai16;
|
|
o.m.f = mk14();
|
|
assert(o.m.f.v[0] == 10i16);
|
|
assert(o.m.f.v[4] == 50i16);
|
|
assert(o.m.f.v[5] == 60i16); // tail, dropped pre-#14
|
|
assert(o.m.f.v[6] == 70i16); // tail, dropped pre-#14
|
|
assert(o.m.guard == 0x55aai16);
|
|
};
|
|
|
|
// Site A (cstage cgen.c cg_structlit_fill nested-CALL field; ww cgenutil.ww
|
|
// cgstructlitfill 5388). A struct-LITERAL whose field is an aggregate call.
|
|
@test fn a_structlit_field() void = {
|
|
let x: boxed = boxed { f = mk14(), guard = 999i16 };
|
|
assert(x.f.v[0] == 10i16);
|
|
assert(x.f.v[4] == 50i16);
|
|
assert(x.f.v[5] == 60i16); // tail, dropped pre-#14
|
|
assert(x.f.v[6] == 70i16); // tail, dropped pre-#14
|
|
assert(x.guard == 999i16);
|
|
};
|
|
|
|
// Site B (cstage cgen.c N_ASSIGN #16 global/chained `g.f = mk()!` unwrap; ww
|
|
// cgenexpr.ww 8483). A GLOBAL struct's field unwrap-receive — pre-#16 the
|
|
// generic single-word store DROPPED w1/w2; #16 routed it through the
|
|
// {AX,DX,CX} materialise, #14 widens its tail to 3/5/6/7.
|
|
@test fn b_global_unwrap() void = {
|
|
poison7(&gb.f.v);
|
|
gb.guard = 0x55aai16;
|
|
gb.f = mk14res()!;
|
|
assert(gb.f.v[0] == 10i16);
|
|
assert(gb.f.v[4] == 50i16);
|
|
assert(gb.f.v[5] == 60i16); // tail, dropped pre-#14
|
|
assert(gb.f.v[6] == 70i16); // tail, dropped pre-#14
|
|
assert(gb.guard == 0x55aai16);
|
|
};
|