// strglobeq — #154 regression pin. `str == str` / `str != str` delegate to // rt_streq, and cgen's str-compare arm had an N_IDENT fast-path that ALWAYS // read the header off BP+localfind(name). For a module-GLOBAL str ident // localfind→0, so it loaded saved-BP/retaddr garbage instead of name(SB) — // a silent cstage miscompile (the header lives at name(SB), not the frame). // Fix mirrors #148's slice global branch: LEAQ name(SB), load ptr/len off it. // // Table-driven: each row is {input, expected}; the loop feeds every input // through the five compile-time-distinct comparison shapes (the bug is per // SHAPE in cgen, so the shapes are separate fns the rows drive). Shapes cover // const-global AND let-global operands, ident on RHS AND on LHS, == AND !=, // and a length>1 global ("/usr") so the LEN word — not just the ptr — is read // off name(SB) on both sub-sites. signalled = row*10+shape pinpoints failures. // // Run with `out/bin/ww run test/wcc/989_strglobeq.ww`; exit 0 = all pass. package main; import os; const csep: str = "/"; let lsep: str = "/"; const longsep: str = "/usr"; // rhs-ident global (p == g): const, let, len>1, and !=. fn eqr_const(p: str) bool = { return p == csep; }; fn eqr_let(p: str) bool = { return p == lsep; }; fn eqr_long(p: str) bool = { return p == longsep; }; fn ner_const(p: str) bool = { return p != csep; }; // lhs-ident global (g == p): const and len>1. fn eql_const(p: str) bool = { return csep == p; }; fn eql_long(p: str) bool = { return longsep == p; }; type row = struct { in: str, eqsep: bool, // in == "/" eqlong: bool, // in == "/usr" }; let signalled: i32 = 0; fn fail() void = { os.exit(signalled + 10); }; export fn main() i32 = { let rows: [_]row = [ row { in = "/", eqsep = true, eqlong = false }, row { in = "foo", eqsep = false, eqlong = false }, row { in = "/usr", eqsep = false, eqlong = true }, ]; // len() stamps i32 on cstage (#26); the index must match for the bound. for (let i: i32 = 0; i < len(rows); i += 1) { let r = rows[i]; signalled = i * 10 + 1; if (eqr_const(r.in) != r.eqsep) { fail(); }; signalled = i * 10 + 2; if (eqr_let(r.in) != r.eqsep) { fail(); }; signalled = i * 10 + 3; if (eql_const(r.in) != r.eqsep) { fail(); }; signalled = i * 10 + 4; if (ner_const(r.in) != !r.eqsep) { fail(); }; signalled = i * 10 + 5; if (eqr_long(r.in) != r.eqlong) { fail(); }; signalled = i * 10 + 6; if (eql_long(r.in) != r.eqlong) { fail(); }; }; return 0; };