// global_index_test — the GLOBAL `str` / GLOBAL slice index family (s/g are // module-level lets): the READ `s[i]`/`g[i]` (#10), the ADDR-OF `&s[i]`/`&g[i]` // and the STORE `g[i] = v` (#11), migrated from test/wcc/803_globalidx_run.c. // wwstage's cgindex dispatched the element size + base off the base's tnode KIND // (only N_TARRAY / N_TPTR), so a global str (N_TNAME "str") and a global slice // (N_TSLICE) matched neither arm: esz stayed 8 and the base fell to the // wide-header fallback — an 8-byte stride + full-word MOVQ, reading 8 bytes at // ptr+8 instead of the single byte at ptr+1. The store was an 8-byte // OUT-OF-BOUNDS MOVQ instead of MOVB. cstage dispatched esz off the RESOLVED // base TYPE (uniform), so it was correct. The fix aligns cgindex/cgun/cgassign // UP to that type-driven dispatch. The slice rows reset the global each fn and // sum ADJACENT elements so a mis-strided / over-wide write FAILS; local rows are // regression pins for the already-clean local path. package global_index_test; let s: str = "ABC"; let g: []u8; let gi: []i32; @test fn gstr_first() void = { assert(s[0]: i32 == 65); }; @test fn gstr_mid() void = { // the exact #10 repro: s[1] == 'B' == 66 (pre-fix an 8-byte word at ptr+8). assert(s[1]: i32 == 66); }; @test fn gstr_last() void = { assert(s[2]: i32 == 67); }; @test fn gstr_sum() void = { // two byte indices summed (65+66) pins the load width — a full-word load // would carry the high bytes. assert(s[0]: i32 + s[1]: i32 == 131); }; @test fn gslice_mid() void = { let a: [3]u8 = [10u8, 20u8, 30u8]; g = a; assert(g[1]: i32 == 20); }; @test fn gislice_mid() void = { // WIDTH>1, SIGNED: g[1]-g[0] == 20-(-5) == 25 pins esz=4 + sign-extend. let a: [3]i32 = [-5, 20, 30]; gi = a; assert(gi[1] - gi[0] == 25); }; @test fn gstr_addr() void = { // #11 ADDR-OF, global str: &s[1] read back == 'B' == 66. let p: *u8 = &s[1]; assert((*p): i32 == 66); }; @test fn gslice_addr() void = { // #11 ADDR-OF, global []u8: &g[1] read back == 20. let a: [3]u8 = [10u8, 20u8, 30u8]; g = a; let p: *u8 = &g[1]; assert((*p): i32 == 20); }; @test fn gislice_addr() void = { // #11 ADDR-OF, global []i32 WIDTH>1: &g[1] == 20 pins esz=4 stride. let a: [3]i32 = [-5, 20, 30]; gi = a; let p: *i32 = &gi[1]; assert(*p == 20); }; @test fn gslice_store() void = { // #11 STORE, global []u8: g[1]=99; g[1]+g[0]+g[2] == 99+10+30 == 139. The // g[0]/g[2] addends are the OOB-WRITE GUARD (pre-fix a full-word MOVQ at an // 8-byte stride wrote 99 at ptr+8 and left g[1]==20). let a: [3]u8 = [10u8, 20u8, 30u8]; g = a; g[1] = 99u8; assert(g[1]: i32 + g[0]: i32 + g[2]: i32 == 139); }; @test fn gislice_store() void = { // #11 STORE, global []i32 SIGNED: g[1]=42; g[1]+g[0]+g[2] == 42+(-5)+30 == 67. let a: [3]i32 = [-5, 20, 30]; gi = a; gi[1] = 42; assert(gi[1] + gi[0] + gi[2] == 67); }; @test fn gslice_compound() void = { // #11 COMPOUND STORE, global []u8: g[1] += 79 → 99; sum == 139. The third // fixed arm (load-combine-store in place), pre-fix an 8-byte OOB RMW. let a: [3]u8 = [10u8, 20u8, 30u8]; g = a; g[1] += 79u8; assert(g[1]: i32 + g[0]: i32 + g[2]: i32 == 139); }; @test fn gislice_compound() void = { // #11 COMPOUND STORE, global []i32 SIGNED: g[1] += 47 → 42; g[1]+g[0]+g[2] // == 42+(-25)+30 == 47. let a: [3]i32 = [-25, -5, 30]; gi = a; gi[1] += 47; assert(gi[1] + gi[0] + gi[2] == 47); }; @test fn lstr_addr() void = { // regression pin: local str ADDR-OF (already clean) — &s[1] == 66. let s: str = "ABC"; let p: *u8 = &s[1]; assert((*p): i32 == 66); }; @test fn lslice_store() void = { // regression pin: local slice STORE (already clean) — g[1]=99; sum == 139. let a: [3]u8 = [10u8, 20u8, 30u8]; let g: []u8 = a; g[1] = 99u8; assert(g[1]: i32 + g[0]: i32 + g[2]: i32 == 139); }; @test fn lstr_mid() void = { // regression pin: local str index (already clean) — s[1] == 66. let s: str = "ABC"; assert(s[1]: i32 == 66); }; @test fn lslice_last() void = { // regression pin: local slice index, last elem (already clean) — g[2] == 30. let a: [3]u8 = [10u8, 20u8, 30u8]; let g: []u8 = a; assert(g[2]: i32 == 30); }; @test fn larr_mid() void = { // regression pin: direct local array index (already clean) — a[1] == 20. let a: [3]u8 = [10u8, 20u8, 30u8]; assert(a[1]: i32 == 20); };