test: migrate gunsigned/chainidx/idxarg behavior to test/lang @test
Batch 2 of the test-arch reframe. These three are codegen-SHAPE tests,
not data-row tests: each subject is a distinct node shape (N_IDENT
module-global read; chained N_INDEX m[i][k]; index-base node-kind). A
[N]struct row-table would interpose its own N_INDEX/N_DOT lowering and
mask the shape under test, so each uses per-shape @test fns with direct
asserts (rob-ratified rule: table where the row is data, per-fn where
the row is a codegen shape). Lossless from the matching
989_{gunsigned,chainidx,idxarg}_run.c; additive (C kept); both stages green.
This commit is contained in:
52
test/lang/chainidx_test.ww
Normal file
52
test/lang/chainidx_test.ww
Normal file
@@ -0,0 +1,52 @@
|
||||
// chainidx_test — a CHAINED index `m[i][k]` whose element is a str/slice must
|
||||
// load the full 24B/16B header, both stages, migrated from
|
||||
// test/wcc/989_chainidx_run.c (#22). The chained-index arm in cgindex read
|
||||
// the element tinfo for esz/signedness but NOT elemisstr/elemisslice, so a
|
||||
// chained index over [N][M]str / [N][M][]T loaded only the .ptr word and left
|
||||
// .len/.cap stale — a cat-A divergence the bootstrap corpus never hits.
|
||||
//
|
||||
// Each "row" is a distinct chained-index SHAPE (str read, str as call-arg,
|
||||
// slice read, scalar control), not data, so this file uses per-shape asserts
|
||||
// rather than the uniesc row-loop idiom. The [N][M] arrays are built by
|
||||
// per-element store — the nested array literal `[[..],[..]]` is independently
|
||||
// #270-1c-blocked (orthogonal).
|
||||
|
||||
package chainidx_test;
|
||||
|
||||
fn takelen(s: str) int = { return len(s): int; };
|
||||
|
||||
@test fn chain_str() void = {
|
||||
let m: [2][2]str;
|
||||
m[0][0] = "aa"; m[0][1] = "bbb";
|
||||
m[1][0] = "c"; m[1][1] = "ddddd";
|
||||
|
||||
// chain_str_read: m[1][1] = "ddddd", len 5 (bug dropped the .len load).
|
||||
let str0: str = m[1][1];
|
||||
assert(len(str0) == 5);
|
||||
|
||||
// chain_str_call: the chained str element passed as a CALL ARG — needs
|
||||
// both the c2 push-side recognizer and this c3 read-side header load.
|
||||
assert(takelen(m[1][1]) == 5);
|
||||
};
|
||||
|
||||
@test fn chain_slice() void = {
|
||||
let a: []int = [1, 2];
|
||||
let b: []int = [9, 9, 9, 9, 9, 9, 9];
|
||||
let m: [2][2][]int;
|
||||
m[0][0] = a; m[0][1] = a;
|
||||
m[1][0] = a; m[1][1] = b;
|
||||
|
||||
// chain_slice_read: m[1][1] = b, len 7 (bug dropped the .len/.cap load).
|
||||
let xs: []int = m[1][1];
|
||||
assert(len(xs) == 7);
|
||||
};
|
||||
|
||||
@test fn chain_scalar() void = {
|
||||
let m: [2][2]int;
|
||||
m[0][0] = 1; m[0][1] = 2;
|
||||
m[1][0] = 3; m[1][1] = 42;
|
||||
|
||||
// chain_scalar_read: control — the scalar chained index the arm already
|
||||
// handled; c3 must not regress it. m[1][1] == 42.
|
||||
assert(m[1][1] == 42);
|
||||
};
|
||||
40
test/lang/gunsigned_test.ww
Normal file
40
test/lang/gunsigned_test.ww
Normal file
@@ -0,0 +1,40 @@
|
||||
// gunsigned_test — a module-GLOBAL unsigned ident on the divide / shift /
|
||||
// relational path must select the UNSIGNED opcode (DIVQ / SHRQ / JA), migrated
|
||||
// from test/wcc/989_gunsigned_run.c (#25). nodeisunsigned read the LOCAL's
|
||||
// declared tnode and fell to signed (false) for a module-global ident, so a
|
||||
// u64 global fed to `/ % >> >= >` got the signed opcode and diverged from
|
||||
// cstage on a high-bit-set value — the cat-A signature.
|
||||
//
|
||||
// The subject IS the module-global IDENT, so the rows MUST stay package-scope
|
||||
// globals exercised directly: a struct-array row-table would route the values
|
||||
// through N_INDEX/N_DOT and never hit the N_IDENT-global codegen path the bug
|
||||
// lives on (so this file does not use the uniesc row-loop idiom — the shapes,
|
||||
// not the data, are what vary).
|
||||
|
||||
package gunsigned_test;
|
||||
|
||||
let g: u64 = 0;
|
||||
let s: i64 = 0;
|
||||
|
||||
@test fn global_unsigned_path() void = {
|
||||
// global_ushr: (1<<63) >> 1 unsigned == 1<<62 (bug: signed SARQ).
|
||||
g = 9223372036854775808u64;
|
||||
let r0: u64 = g >> 1;
|
||||
assert(r0 == 4611686018427387904u64);
|
||||
|
||||
// global_udiv: (1<<63) / (1<<62) unsigned == 2 (bug: signed IDIVQ).
|
||||
g = 9223372036854775808u64;
|
||||
let r1: u64 = g / 4611686018427387904u64;
|
||||
assert(r1 == 2u64);
|
||||
|
||||
// global_ucmp: (1<<63) > 1 is true unsigned, false signed (bug: JG).
|
||||
g = 9223372036854775808u64;
|
||||
assert(g > 1u64);
|
||||
|
||||
// signed_global_ctl: a SIGNED i64 global must KEEP the signed shift —
|
||||
// -8 >> 1 == -4 (control: c5 reads the stamp, no blanket
|
||||
// global -> unsigned over-conversion).
|
||||
s = -8;
|
||||
let r3: i64 = s >> 1;
|
||||
assert(r3 == -4);
|
||||
};
|
||||
50
test/lang/idxarg_test.ww
Normal file
50
test/lang/idxarg_test.ww
Normal file
@@ -0,0 +1,50 @@
|
||||
// idxarg_test — an INDEXED slice/str element passed as a call argument must
|
||||
// push its full multi-word header, both stages, migrated from
|
||||
// test/wcc/989_idxarg_run.c (#45/#46). pushargsrev sizes a call arg via
|
||||
// nodeisslice/nodeisstr; pre-fix nodeisslice had no N_INDEX arm (#45, slice
|
||||
// element fell to a 1-word scalar push) and nodeisstr's N_INDEX arm was a
|
||||
// base-kind whitelist that only knew N_IDENT/N_DOT bases (#46, a non-ident/
|
||||
// non-dot base fell through to a 1-word push). Either way the callee read
|
||||
// garbage .len/.cap — a cat-A divergence invisible to byte-id.
|
||||
//
|
||||
// Each "row" is a distinct index-base SHAPE (slice element, N_CALL base,
|
||||
// N_IDENT base, plain local control), not data, so this file uses per-shape
|
||||
// asserts rather than the uniesc row-loop idiom.
|
||||
|
||||
package idxarg_test;
|
||||
|
||||
fn takeintlen(xs: []int) int = { return len(xs): int; };
|
||||
fn takestrlen(s: str) int = { return len(s): int; };
|
||||
|
||||
fn getarr() []str = {
|
||||
let a: []str = ["x", "ddddd", "zz"];
|
||||
return a;
|
||||
};
|
||||
|
||||
@test fn idx_slice_arg() void = {
|
||||
// slice_elem_arg (#45): a []int slice element `rows[1]` as a call arg —
|
||||
// pre-fix nodeisslice had no N_INDEX arm, so a 1-word push gave the
|
||||
// callee garbage len. len(rows[1]) == len(b) == 2.
|
||||
let a: []int = [10, 20, 30, 40];
|
||||
let b: []int = [1, 2];
|
||||
let rows: [2][]int = [a, b];
|
||||
assert(takeintlen(rows[1]) == 2);
|
||||
};
|
||||
|
||||
@test fn idx_str_arg() void = {
|
||||
// call_str_elem (#46): an index whose base is an N_CALL (`getarr()[1]`)
|
||||
// — the non-ident/non-dot base the old whitelist missed. len == 5.
|
||||
assert(takestrlen(getarr()[1]) == 5);
|
||||
|
||||
// ident_str_elem (#46 control): an N_IDENT base `arr[1]` — the case the
|
||||
// old whitelist DID handle; the stamp read must not regress it.
|
||||
let arr: [3]str = ["x", "ddddd", "zz"];
|
||||
assert(takestrlen(arr[1]) == 5);
|
||||
};
|
||||
|
||||
@test fn idx_local_arg() void = {
|
||||
// slice_local_arg (control): a plain non-indexed str/slice local arg
|
||||
// (the c1 N_IDENT-local arm) — c2 must leave it alone. len == 3.
|
||||
let xs: []int = [7, 8, 9];
|
||||
assert(takeintlen(xs) == 3);
|
||||
};
|
||||
Reference in New Issue
Block a user