Fan out the str-cap read (933-936) and store (937-939) families into in-language @test files, following the 932 str_elem_cap template. Additive: the *_run.c stay in the C corpus (they are the only wwstage-runtime net for these cs==ww byte-id-blind shapes); de-dup deferred to fold 6. Per-shape @test fns, not a data table: each fn varies the codegen shape (base reg / chain depth / tuple return-ABI / store position), so the row-array idiom (blocked by #111) would lose coverage. Read family keeps the spoil()/register-clobber + junk==44 discrimination where the .c has it; store family pre-poisons the slot via a path distinct from the store under test. Asserts are primitives only.
63 lines
2.4 KiB
Plaintext
63 lines
2.4 KiB
Plaintext
// str_massign_store_cap_test — a tuple-destructure REASSIGNMENT `a, s = call()`
|
|
// (N_MASSIGN) whose str element must write the full 24B {ptr,len,cap} header
|
|
// into the str slot, not just {ptr}, migrated from
|
|
// test/wcc/939_str_massign_store_cap_run.c (G3 fold). str is 24B since Phase 2
|
|
// (#1); the N_MASSIGN arm previously stored the str element with the bare
|
|
// scalar path (one word), dropping len/cap. cs==ww held (byte-id-blind), so
|
|
// behavioral @test is the net.
|
|
//
|
|
// N_MASSIGN vs N_MLET: `let a, s = call()` is N_MLET (fresh bindings) and
|
|
// ALREADY destructures 3-word. `a, s = call()` with a, s PRE-DECLARED is
|
|
// N_MASSIGN (reassignment) — the arm under test. The bindings MUST be
|
|
// pre-declared then reassigned WITHOUT `let`, or the parser emits N_MLET and
|
|
// this arm is never reached (silent false green).
|
|
//
|
|
// RHS cap!=len: the returned str is a literal whose .cap is mutated DISTINCT
|
|
// from its len. PRE-POISON: s is seeded with a DIFFERENT str (ptr='q', len=4,
|
|
// cap=5) via `let s: str = q` — a PROVEN already-3-word let-init copy, which
|
|
// both DECLARES s (so the comma-assign is N_MASSIGN) and poisons its slot. A
|
|
// broken 1-word store writes only s.ptr, so the read-back observes the poison
|
|
// len 4 / cap 5, never 2 / 8. The full-triple assert (s[0]='h'=104, len=2,
|
|
// cap=8) plus the scalar guard (a==5) confirm the XOR branch wires both slots.
|
|
|
|
package str_massign_store_cap_test;
|
|
|
|
fn mk() (i64, str) = {
|
|
let p: str = "hi"; p.cap = 8i32;
|
|
return (5i64, p);
|
|
};
|
|
|
|
fn mk2() (str, i64) = {
|
|
let p: str = "hi"; p.cap = 8i32;
|
|
return (p, 5i64);
|
|
};
|
|
|
|
@test fn massign_store_str_pos1() void = {
|
|
// A — `a, s = mk()`, str the 2nd tuple element (l1). a and s are
|
|
// pre-declared (so the comma-assign is N_MASSIGN, not N_MLET); s is
|
|
// poisoned (cap=5,len=4,'q') by its let-init copy. The G3 store then
|
|
// lands the test str (cap=8,len=2,'h') via (DX,CX,R8)->s, AX->a.
|
|
let q: str = "qqqq"; q.cap = 5i32;
|
|
let a: i64 = 7i64;
|
|
let s: str = q;
|
|
a, s = mk();
|
|
assert(s.cap: i32 == 8);
|
|
assert(s.len: i32 == 2);
|
|
assert(s[0] == 104u8);
|
|
assert(a == 5);
|
|
};
|
|
|
|
@test fn massign_store_str_pos0() void = {
|
|
// B — `s, a = mk2()`, str the 1st tuple element (l0). Same poison and
|
|
// test values; exercises the s0_is_str routing (DX,CX,R8)->s, AX->a from
|
|
// the other XOR side.
|
|
let q: str = "qqqq"; q.cap = 5i32;
|
|
let s: str = q;
|
|
let a: i64 = 7i64;
|
|
s, a = mk2();
|
|
assert(s.cap: i32 == 8);
|
|
assert(s.len: i32 == 2);
|
|
assert(s[0] == 104u8);
|
|
assert(a == 5);
|
|
};
|