diff --git a/docs/reports/suite_expectations.json b/docs/reports/suite_expectations.json index 16443dced8..b7edbc403d 100644 --- a/docs/reports/suite_expectations.json +++ b/docs/reports/suite_expectations.json @@ -2,7 +2,7 @@ "schema_version": 1, "generated_by": "t27c suite --bless-expectations", "max_gate_failures": 2, - "max_entries": 83, + "max_entries": 82, "entries": [ { "path": "specs/api/sdk_contract.t27", @@ -685,13 +685,6 @@ "issue": 5549, "expires": "2026-11-30" }, - { - "path": "specs/port/scripts/gen_w698.t27", - "phase": "gen-verilog", - "reason": "gen-verilog cannot lower 2-D arrays of aggregate type ([8][]const u8 pads, [1][]const u8 sub_args): W469 2-D array-of-struct lowering is still unimplemented (docs/reports/W469_2D_STRUCT_ARRAY_DESIGN.md). Port spec keeps upstream shape; recorded until the emitter grows the lowering.", - "issue": 1959, - "expires": "2026-11-30" - }, { "path": "specs/port/scripts/run_v51_multiple.t27", "phase": "gen-verilog", diff --git a/specs/port/scripts/gen_w698.t27 b/specs/port/scripts/gen_w698.t27 index 719bce1132..80922f41a4 100644 --- a/specs/port/scripts/gen_w698.t27 +++ b/specs/port/scripts/gen_w698.t27 @@ -1,5 +1,7 @@ module port::scripts::gen_w698; +use port::scripts::gen_w_tree; + // Port of scripts/gen_w698.py (gHashTag/t27 at 88821271d8be, 145 lines), the // generator of specs/scratch/w698_bench_module_215x2p6_aos_var_call_write.t27. // @@ -31,126 +33,9 @@ pub const MID_Y: i64 = (2 * MID_E + 1) % COORD_MOD; pub const WRAP_LAST_X: i64 = (2 * (TOTAL - 1) + COORD_MOD) % COORD_MOD; pub const WRAP_LAST_Y: i64 = (2 * (TOTAL - 1) + 1 + COORD_MOD) % COORD_MOD; -// Original line 24: def indent(level: int) -> str: return " " * level. -// Python's string multiply gives "" for level <= 0. The original's call -// sites use only levels 1 and 2; the table covers 0..=7 and clamps above 7, -// which no original call reaches. -pub fn indent(level: i64) -> str { - const pads: [8][]const u8 = ["", " ", " ", " ", " ", " ", " ", " "]; - var idx: usize = 0; - if (level <= 0) { - idx = 0; - } else if (level > 7) { - idx = 7; - } else { - idx = level as usize; - } - return pads[idx]; -} - -// The leaf entry coordinates (original lines 40-42): element e is written as -// Pt { .x = (2*e + offset) % 32768, .y = (2*e + offset + 1) % 32768 }. -pub fn elem_x(e: i64, offset: i64) -> i64 { - return (2 * e + offset) % COORD_MOD; -} - -pub fn elem_y(e: i64, offset: i64) -> i64 { - return (2 * e + offset + 1) % COORD_MOD; -} - -// What one build_tree call decides, as observed in the text it emits in the -// original: the coordinates of the first and last leaf in row-major order, -// the number of leaf entries, and the base the caller continues from (the -// second half of the original's tuple return). -pub struct TreeBuild { - first_x: i64, - first_y: i64, - last_x: i64, - last_y: i64, - leaves: i64, - next_base: i64, -} - -// Recursive worker mirroring the original's recursion (original lines 28-58): -// dim is the dimension being expanded, the leaf case is the last dimension, -// and base threads through the children in row-major element order. -fn build_level(shape: []const i64, dim: usize, base: i64, offset: i64) -> TreeBuild { - if (dim + 1 == shape.len) { - const n: i64 = shape[dim]; - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base + n - 1, offset), - last_y: elem_y(base + n - 1, offset), - leaves: n, - next_base: base + n, - }; - } - const n: i64 = shape[dim]; - if (n < 1) { - // Python emits no children for a zero-width dimension and leaves - // base untouched. - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base, offset), - last_y: elem_y(base, offset), - leaves: 0, - next_base: base, - }; - } - var b: i64 = base; - var first: TreeBuild = build_level(shape, dim + 1, b, offset); - var last: TreeBuild = first; - b = first.next_base; - var i: i64 = 1; - while (i < n) { - last = build_level(shape, dim + 1, b, offset); - b = last.next_base; - i += 1; - } - return TreeBuild { - first_x: first.first_x, - first_y: first.first_y, - last_x: last.last_x, - last_y: last.last_y, - leaves: last.leaves * n, - next_base: b, - }; -} - -// Original line 28: def build_tree(shape: list[int], base: int, offset: int) -// -> tuple[str, int]. The port returns the numeric decisions (TreeBuild) -// instead of the built text; the text itself is string plumbing .t27 cannot -// express. -pub fn build_tree(shape: []const i64, base: i64, offset: i64) -> TreeBuild { - return build_level(shape, 0, base, offset); -} - -// Row-major flat element number of a multi-dimensional index. The original -// computes [MID_IDX][1][0][0][0][0][0] as MID_IDX * 64 + 32 (lines 15-16) -// and the footer it emits asserts through such indices. -pub fn flat_index(shape: []const i64, idx: []const i64) -> i64 { - var flat: i64 = 0; - var i: usize = 0; - while (i < shape.len) { - flat = flat * shape[i] + idx[i]; - i += 1; - } - return flat; -} - -// The original refuses to write the file unless every character is ASCII -// (original line 135: raise ValueError). Ported as a pure predicate; the -// raise itself is the caller's plumbing. -pub fn is_ascii(s: []const u8) -> bool { - for c in s { - if (c > 127) { - return false; - } - } - return true; -} +// TreeBuild, indent, elem_x, elem_y, build_level, build_tree, flat_index and is_ascii +// (original lines 24, 28-58, 40-42 and 135) live in gen_w_tree.t27, shared by the +// eight gen_w bench ports. // Original line 61: def generate() -> None. Writes the assembled text to // DST and prints a one-line summary - pure data moving out (file, stdout). diff --git a/specs/port/scripts/gen_w709.t27 b/specs/port/scripts/gen_w709.t27 index cb106c977f..dd8fe31bb9 100644 --- a/specs/port/scripts/gen_w709.t27 +++ b/specs/port/scripts/gen_w709.t27 @@ -7,6 +7,8 @@ module port::scripts::gen_w709; +use port::scripts::gen_w_tree; + // 237 x 2**6 Pt grid. The x/y of element e under offset are // (2e + offset) % 32768 and (2e + offset + 1) % 32768 (original lines 13-21, // 40-42); the expected array in the emitted footer is folded the same way. @@ -24,138 +26,9 @@ const MID_Y: i64 = (2 * MID_E + 1) % COORD_MOD; // 15169 const WRAP_LAST_X: i64 = (2 * (TOTAL - 1) + COORD_MOD) % COORD_MOD; // 30334 const WRAP_LAST_Y: i64 = (2 * (TOTAL - 1) + 1 + COORD_MOD) % COORD_MOD; // 30335 -// Original lines 24-25: def indent(level: int) -> str: return " " * level. -// .t27 cannot multiply a string, so the level maps through a padded table; -// anything above the deepest level the original ever uses (7) clamps. -pub fn indent(level: i64) -> str { - if (level <= 0) { - return ""; - } - if (level == 1) { - return " "; - } - if (level == 2) { - return " "; - } - if (level == 3) { - return " "; - } - if (level == 4) { - return " "; - } - if (level == 5) { - return " "; - } - if (level == 6) { - return " "; - } - return " "; -} - -// x of element number e under offset: (2e + offset) % 32768 (original line 41). -pub fn elem_x(e: i64, offset: i64) -> i64 { - return (2 * e + offset) % COORD_MOD; -} - -// y of element number e under offset: (2e + offset + 1) % 32768 (original line 42). -pub fn elem_y(e: i64, offset: i64) -> i64 { - return (2 * e + offset + 1) % COORD_MOD; -} - -// The numeric decisions the built literal text carries: the coordinates of -// its first and last leaves, how many leaves it holds, and the next base -// the caller must continue from. -struct TreeBuild { - first_x: i64, - first_y: i64, - last_x: i64, - last_y: i64, - leaves: i64, - next_base: i64, -} - -// Original lines 28-58: def build_tree(shape: list[int], base: int, -// offset: int) -> tuple[str, int]. Recursion walks the shape; the last -// dimension becomes the leaf of Pt entries. -fn build_level(shape: []const i64, dim: usize, base: i64, offset: i64) -> TreeBuild { - const n: i64 = shape[dim]; - if (dim + 1 == shape.len) { - // Leaf case: entries e = base .. base+n-1, each mapped through - // x = (2*e + offset) % 32768 and y = (2*e + offset + 1) % 32768 - // (original lines 40-42). - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base + n - 1, offset), - last_y: elem_y(base + n - 1, offset), - leaves: n, - next_base: base + n, - }; - } - if (n < 1) { - // Python emits no children for a zero-width dimension and leaves - // base untouched. - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base, offset), - last_y: elem_y(base, offset), - leaves: 0, - next_base: base, - }; - } - var b: i64 = base; - var first: TreeBuild = build_level(shape, dim + 1, b, offset); - var last: TreeBuild = first; - b = first.next_base; - var i: i64 = 1; - while (i < n) { - last = build_level(shape, dim + 1, b, offset); - b = last.next_base; - i += 1; - } - return TreeBuild { - first_x: first.first_x, - first_y: first.first_y, - last_x: last.last_x, - last_y: last.last_y, - leaves: last.leaves * n, - next_base: b, - }; -} - -// Original line 28: def build_tree(shape: list[int], base: int, offset: int) -// -> tuple[str, int]. The port returns the numeric decisions (TreeBuild) -// instead of the built text; the text itself is string plumbing .t27 cannot -// express. -pub fn build_tree(shape: []const i64, base: i64, offset: i64) -> TreeBuild { - return build_level(shape, 0, base, offset); -} - -// Row-major flat element number of a multi-dimensional index. The original -// computes [MID_IDX][1][0][0][0][0][0] as MID_IDX * 64 + 32 (lines 15-17) -// and the footer it emits asserts through such indices. -pub fn flat_index(shape: []const i64, idx: []const i64) -> i64 { - var flat: i64 = 0; - var i: usize = 0; - while (i < shape.len) { - flat = flat * shape[i] + idx[i]; - i += 1; - } - return flat; -} - -// The original refuses to write the file unless every character is ASCII -// (original line 136: raise ValueError). Ported as a pure predicate; the -// raise itself is the caller's plumbing. -pub fn is_ascii(s: []const u8) -> bool { - for c in s { - if (c > 127) { - return false; - } - } - return true; -} +// indent, elem_x, elem_y, TreeBuild, build_level, build_tree, flat_index and is_ascii +// (original lines 24-25, 28-58, 40-42 and 136) live in gen_w_tree.t27, shared by the +// eight gen_w bench ports. // Original line 61: def generate() -> None. Writes the assembled text to // DST and prints a one-line summary - pure data moving out (file, stdout). diff --git a/specs/port/scripts/gen_w713.t27 b/specs/port/scripts/gen_w713.t27 index 6e03ea51d1..f46acfd401 100644 --- a/specs/port/scripts/gen_w713.t27 +++ b/specs/port/scripts/gen_w713.t27 @@ -23,6 +23,8 @@ module port::scripts::gen_w713; +use port::scripts::gen_w_tree; + // Header constants (lines 9-21), verbatim arithmetic. const COORD_MOD: i64 = 32768; const OUTER: i64 = 245; @@ -38,146 +40,9 @@ const MID_Y: i64 = (2 * MID_E + 1) % COORD_MOD; const WRAP_LAST_X: i64 = (2 * (TOTAL - 1) + COORD_MOD) % COORD_MOD; const WRAP_LAST_Y: i64 = (2 * (TOTAL - 1) + 1 + COORD_MOD) % COORD_MOD; -// What the recursion decides for one literal: the first and last element -// coordinates, the number of Pt entries, and the next free element index. -// The original returns the built text plus the advanced base (line 29); -// the text is the string plumbing named in the header, these numbers are -// what it encodes. -pub struct TreeBuild { - first_x: i64, - first_y: i64, - last_x: i64, - last_y: i64, - leaves: i64, - next_base: i64, -} - -// Original line 24: def indent(level: int) -> str. " " * level cannot be -// written in .t27 (no string repetition), so the levels the generator can -// reach are spelled out; above level 7 the result clamps at the deepest -// string here. Negative levels are "" as in Python (" " * -2 == ""). -pub fn indent(level: i64) -> str { - if (level <= 0) { - return ""; - } - if (level == 1) { - return " "; - } - if (level == 2) { - return " "; - } - if (level == 3) { - return " "; - } - if (level == 4) { - return " "; - } - if (level == 5) { - return " "; - } - if (level == 6) { - return " "; - } - return " "; -} - -// Original lines 40-42: x = (2 * e + offset) % 32768 for entry e of a leaf -// run. Python's % and the generated % agree on this non-negative domain. -pub fn elem_x(e: i64, offset: i64) -> i64 { - return (2 * e + offset) % COORD_MOD; -} - -// Original lines 41-42: y is x + 1 under the same modulus. -pub fn elem_y(e: i64, offset: i64) -> i64 { - return (2 * e + offset + 1) % COORD_MOD; -} - -// The recursion of original lines 28-58, over (shape, dim) because .t27 -// cannot slice shape[1:]. The leaf case (dim is the last dimension) walks -// entries e = base .. base+n-1 through elem_x/elem_y and advances the base -// by n (lines 35-46). An inner node threads the base through its n -// children unchanged and reports the first child's and last child's -// decisions (lines 48-57). A zero-width dimension emits no children and -// leaves the base untouched, as range(0) does in Python. -fn build_level(shape: []const i64, dim: usize, base: i64, offset: i64) -> TreeBuild { - const n: i64 = shape[dim]; - if (dim + 1 == shape.len) { - // Leaf case: entries e = base .. base+n-1, each mapped through - // x = (2*e + offset) % 32768 and y = (2*e + offset + 1) % 32768 - // (original lines 40-42). - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base + n - 1, offset), - last_y: elem_y(base + n - 1, offset), - leaves: n, - next_base: base + n, - }; - } - if (n < 1) { - // Python emits no children for a zero-width dimension and leaves - // base untouched. - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base, offset), - last_y: elem_y(base, offset), - leaves: 0, - next_base: base, - }; - } - var b: i64 = base; - var first: TreeBuild = build_level(shape, dim + 1, b, offset); - var last: TreeBuild = first; - b = first.next_base; - var i: i64 = 1; - while (i < n) { - last = build_level(shape, dim + 1, b, offset); - b = last.next_base; - i += 1; - } - return TreeBuild { - first_x: first.first_x, - first_y: first.first_y, - last_x: last.last_x, - last_y: last.last_y, - leaves: last.leaves * n, - next_base: b, - }; -} - -// Original line 28: def build_tree(shape: list[int], base: int, offset: int) -// -> tuple[str, int]. The port returns the numeric decisions (TreeBuild) -// instead of the built text; the text itself is string plumbing .t27 cannot -// express. -pub fn build_tree(shape: []const i64, base: i64, offset: i64) -> TreeBuild { - return build_level(shape, 0, base, offset); -} - -// Row-major flat element number of a multi-dimensional index. The original -// computes [MID_IDX][1][0][0][0][0][0] as MID_IDX * 64 + 32 (lines 15-17) -// and the footer it emits asserts through such indices. -pub fn flat_index(shape: []const i64, idx: []const i64) -> i64 { - var flat: i64 = 0; - var i: usize = 0; - while (i < shape.len) { - flat = flat * shape[i] + idx[i]; - i += 1; - } - return flat; -} - -// The original refuses to write the file unless every character is ASCII -// (original line 136: raise ValueError). Ported as a pure predicate; the -// raise itself is the caller's plumbing. -pub fn is_ascii(s: []const u8) -> bool { - for c in s { - if (c > 127) { - return false; - } - } - return true; -} +// TreeBuild, indent, elem_x, elem_y, build_level, build_tree, flat_index and is_ascii +// (original lines 24-25, 28-58, 40-42 and 136) live in gen_w_tree.t27, shared by the +// eight gen_w bench ports. // Original line 61: def generate() -> None. Writes the assembled text to // specs/scratch/w713_bench_module_245x2p6_aos_var_call_write.t27 and prints diff --git a/specs/port/scripts/gen_w716.t27 b/specs/port/scripts/gen_w716.t27 index e39d799f87..6b722ecc61 100644 --- a/specs/port/scripts/gen_w716.t27 +++ b/specs/port/scripts/gen_w716.t27 @@ -23,6 +23,8 @@ module port::scripts::gen_w716; +use port::scripts::gen_w_tree; + // Header constants (lines 9-21), verbatim arithmetic. const COORD_MOD: i64 = 32768; const OUTER: i64 = 251; @@ -38,146 +40,9 @@ const MID_Y: i64 = (2 * MID_E + 1) % COORD_MOD; const WRAP_LAST_X: i64 = (2 * (TOTAL - 1) + COORD_MOD) % COORD_MOD; const WRAP_LAST_Y: i64 = (2 * (TOTAL - 1) + 1 + COORD_MOD) % COORD_MOD; -// What the recursion decides for one literal: the first and last element -// coordinates, the number of Pt entries, and the next free element index. -// The original returns the built text plus the advanced base (line 29); -// the text is the string plumbing named in the header, these numbers are -// what it encodes. -pub struct TreeBuild { - first_x: i64, - first_y: i64, - last_x: i64, - last_y: i64, - leaves: i64, - next_base: i64, -} - -// Original line 24: def indent(level: int) -> str. " " * level cannot be -// written in .t27 (no string repetition), so the levels the generator can -// reach are spelled out; above level 7 the result clamps at the deepest -// string here. Negative levels are "" as in Python (" " * -2 == ""). -pub fn indent(level: i64) -> str { - if (level <= 0) { - return ""; - } - if (level == 1) { - return " "; - } - if (level == 2) { - return " "; - } - if (level == 3) { - return " "; - } - if (level == 4) { - return " "; - } - if (level == 5) { - return " "; - } - if (level == 6) { - return " "; - } - return " "; -} - -// Original lines 40-42: x = (2 * e + offset) % 32768 for entry e of a leaf -// run. Python's % and the generated % agree on this non-negative domain. -pub fn elem_x(e: i64, offset: i64) -> i64 { - return (2 * e + offset) % COORD_MOD; -} - -// Original lines 41-42: y is x + 1 under the same modulus. -pub fn elem_y(e: i64, offset: i64) -> i64 { - return (2 * e + offset + 1) % COORD_MOD; -} - -// The recursion of original lines 28-58, over (shape, dim) because .t27 -// cannot slice shape[1:]. The leaf case (dim is the last dimension) walks -// entries e = base .. base+n-1 through elem_x/elem_y and advances the base -// by n (lines 35-46). An inner node threads the base through its n -// children unchanged and reports the first child's and last child's -// decisions (lines 48-58). A zero-width dimension emits no children and -// leaves the base untouched, as range(0) does in Python. -fn build_level(shape: []const i64, dim: usize, base: i64, offset: i64) -> TreeBuild { - const n: i64 = shape[dim]; - if (dim + 1 == shape.len) { - // Leaf case: entries e = base .. base+n-1, each mapped through - // x = (2*e + offset) % 32768 and y = (2*e + offset + 1) % 32768 - // (original lines 40-42). - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base + n - 1, offset), - last_y: elem_y(base + n - 1, offset), - leaves: n, - next_base: base + n, - }; - } - if (n < 1) { - // Python emits no children for a zero-width dimension and leaves - // base untouched. - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base, offset), - last_y: elem_y(base, offset), - leaves: 0, - next_base: base, - }; - } - var b: i64 = base; - var first: TreeBuild = build_level(shape, dim + 1, b, offset); - var last: TreeBuild = first; - b = first.next_base; - var i: i64 = 1; - while (i < n) { - last = build_level(shape, dim + 1, b, offset); - b = last.next_base; - i += 1; - } - return TreeBuild { - first_x: first.first_x, - first_y: first.first_y, - last_x: last.last_x, - last_y: last.last_y, - leaves: last.leaves * n, - next_base: b, - }; -} - -// Original line 28: def build_tree(shape: list[int], base: int, offset: int) -// -> tuple[str, int]. The port returns the numeric decisions (TreeBuild) -// instead of the built text; the text itself is string plumbing .t27 cannot -// express. -pub fn build_tree(shape: []const i64, base: i64, offset: i64) -> TreeBuild { - return build_level(shape, 0, base, offset); -} - -// Row-major flat element number of a multi-dimensional index. The original -// computes [MID_IDX][1][0][0][0][0][0] as MID_IDX * 64 + 32 (lines 15-17) -// and the footer it emits asserts through such indices. -pub fn flat_index(shape: []const i64, idx: []const i64) -> i64 { - var flat: i64 = 0; - var i: usize = 0; - while (i < shape.len) { - flat = flat * shape[i] + idx[i]; - i += 1; - } - return flat; -} - -// The original refuses to write the file unless every character is ASCII -// (original line 136: raise ValueError). Ported as a pure predicate; the -// raise itself is the caller's plumbing. -pub fn is_ascii(s: []const u8) -> bool { - for c in s { - if (c > 127) { - return false; - } - } - return true; -} +// TreeBuild, indent, elem_x, elem_y, build_level, build_tree, flat_index and is_ascii +// (original lines 24-25, 28-58, 40-42 and 136) live in gen_w_tree.t27, shared by the +// eight gen_w bench ports. // Original line 61: def generate() -> None. Writes the assembled text to // specs/scratch/w716_bench_module_251x2p6_aos_var_call_write.t27 and prints diff --git a/specs/port/scripts/gen_w721.t27 b/specs/port/scripts/gen_w721.t27 index 3084c2a4cc..0f9b4babd4 100644 --- a/specs/port/scripts/gen_w721.t27 +++ b/specs/port/scripts/gen_w721.t27 @@ -23,6 +23,8 @@ module port::scripts::gen_w721; +use port::scripts::gen_w_tree; + // Header constants (lines 9-21), verbatim arithmetic. const COORD_MOD: i64 = 32768; const OUTER: i64 = 261; @@ -38,146 +40,9 @@ const MID_Y: i64 = (2 * MID_E + 1) % COORD_MOD; const WRAP_LAST_X: i64 = (2 * (TOTAL - 1) + COORD_MOD) % COORD_MOD; const WRAP_LAST_Y: i64 = (2 * (TOTAL - 1) + 1 + COORD_MOD) % COORD_MOD; -// What the recursion decides for one literal: the first and last element -// coordinates, the number of Pt entries, and the next free element index. -// The original returns the built text plus the advanced base (line 29); -// the text is the string plumbing named in the header, these numbers are -// what it encodes. -pub struct TreeBuild { - first_x: i64, - first_y: i64, - last_x: i64, - last_y: i64, - leaves: i64, - next_base: i64, -} - -// Original line 24: def indent(level: int) -> str. " " * level cannot be -// written in .t27 (no string repetition), so the levels the generator can -// reach are spelled out; above level 7 the result clamps at the deepest -// string here. Negative levels are "" as in Python (" " * -2 == ""). -pub fn indent(level: i64) -> str { - if (level <= 0) { - return ""; - } - if (level == 1) { - return " "; - } - if (level == 2) { - return " "; - } - if (level == 3) { - return " "; - } - if (level == 4) { - return " "; - } - if (level == 5) { - return " "; - } - if (level == 6) { - return " "; - } - return " "; -} - -// Original lines 40-42: x = (2 * e + offset) % 32768 for entry e of a leaf -// run. Python's % and the generated % agree on this non-negative domain. -pub fn elem_x(e: i64, offset: i64) -> i64 { - return (2 * e + offset) % COORD_MOD; -} - -// Original lines 41-42: y is x + 1 under the same modulus. -pub fn elem_y(e: i64, offset: i64) -> i64 { - return (2 * e + offset + 1) % COORD_MOD; -} - -// The recursion of original lines 28-58, over (shape, dim) because .t27 -// cannot slice shape[1:]. The leaf case (dim is the last dimension) walks -// entries e = base .. base+n-1 through elem_x/elem_y and advances the base -// by n (lines 35-46). An inner node threads the base through its n -// children unchanged and reports the first child's and last child's -// decisions (lines 48-58). A zero-width dimension emits no children and -// leaves the base untouched, as range(0) does in Python. -fn build_level(shape: []const i64, dim: usize, base: i64, offset: i64) -> TreeBuild { - const n: i64 = shape[dim]; - if (dim + 1 == shape.len) { - // Leaf case: entries e = base .. base+n-1, each mapped through - // x = (2*e + offset) % 32768 and y = (2*e + offset + 1) % 32768 - // (original lines 40-42). - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base + n - 1, offset), - last_y: elem_y(base + n - 1, offset), - leaves: n, - next_base: base + n, - }; - } - if (n < 1) { - // Python emits no children for a zero-width dimension and leaves - // base untouched. - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base, offset), - last_y: elem_y(base, offset), - leaves: 0, - next_base: base, - }; - } - var b: i64 = base; - var first: TreeBuild = build_level(shape, dim + 1, b, offset); - var last: TreeBuild = first; - b = first.next_base; - var i: i64 = 1; - while (i < n) { - last = build_level(shape, dim + 1, b, offset); - b = last.next_base; - i += 1; - } - return TreeBuild { - first_x: first.first_x, - first_y: first.first_y, - last_x: last.last_x, - last_y: last.last_y, - leaves: last.leaves * n, - next_base: b, - }; -} - -// Original line 28: def build_tree(shape: list[int], base: int, offset: int) -// -> tuple[str, int]. The port returns the numeric decisions (TreeBuild) -// instead of the built text; the text itself is string plumbing .t27 cannot -// express. -pub fn build_tree(shape: []const i64, base: i64, offset: i64) -> TreeBuild { - return build_level(shape, 0, base, offset); -} - -// Row-major flat element number of a multi-dimensional index. The original -// computes [MID_IDX][1][0][0][0][0][0] as MID_IDX * 64 + 32 (lines 15-17) -// and the footer it emits asserts through such indices. -pub fn flat_index(shape: []const i64, idx: []const i64) -> i64 { - var flat: i64 = 0; - var i: usize = 0; - while (i < shape.len) { - flat = flat * shape[i] + idx[i]; - i += 1; - } - return flat; -} - -// The original refuses to write the file unless every character is ASCII -// (original line 136: raise ValueError). Ported as a pure predicate; the -// raise itself is the caller's plumbing. -pub fn is_ascii(s: []const u8) -> bool { - for c in s { - if (c > 127) { - return false; - } - } - return true; -} +// TreeBuild, indent, elem_x, elem_y, build_level, build_tree, flat_index and is_ascii +// (original lines 24-25, 28-58, 40-42 and 136) live in gen_w_tree.t27, shared by the +// eight gen_w bench ports. // Original line 61: def generate() -> None. Writes the assembled text to // specs/scratch/w721_bench_module_261x2p6_aos_var_call_write.t27 and prints diff --git a/specs/port/scripts/gen_w728.t27 b/specs/port/scripts/gen_w728.t27 index ef17d071d6..5a0557df94 100644 --- a/specs/port/scripts/gen_w728.t27 +++ b/specs/port/scripts/gen_w728.t27 @@ -23,6 +23,8 @@ module port::scripts::gen_w728; +use port::scripts::gen_w_tree; + // Header constants (lines 9-21), verbatim arithmetic. const COORD_MOD: i64 = 32768; const OUTER: i64 = 275; @@ -38,146 +40,9 @@ const MID_Y: i64 = (2 * MID_E + 1) % COORD_MOD; const WRAP_LAST_X: i64 = (2 * (TOTAL - 1) + COORD_MOD) % COORD_MOD; const WRAP_LAST_Y: i64 = (2 * (TOTAL - 1) + 1 + COORD_MOD) % COORD_MOD; -// What the recursion decides for one literal: the first and last element -// coordinates, the number of Pt entries, and the next free element index. -// The original returns the built text plus the advanced base (line 29); -// the text is the string plumbing named in the header, these numbers are -// what it encodes. -pub struct TreeBuild { - first_x: i64, - first_y: i64, - last_x: i64, - last_y: i64, - leaves: i64, - next_base: i64, -} - -// Original line 24: def indent(level: int) -> str. " " * level cannot be -// written in .t27 (no string repetition), so the levels the generator can -// reach are spelled out; above level 7 the result clamps at the deepest -// string here. Negative levels are "" as in Python (" " * -2 == ""). -pub fn indent(level: i64) -> str { - if (level <= 0) { - return ""; - } - if (level == 1) { - return " "; - } - if (level == 2) { - return " "; - } - if (level == 3) { - return " "; - } - if (level == 4) { - return " "; - } - if (level == 5) { - return " "; - } - if (level == 6) { - return " "; - } - return " "; -} - -// Original lines 40-42: x = (2 * e + offset) % 32768 for entry e of a leaf -// run. Python's % and the generated % agree on this non-negative domain. -pub fn elem_x(e: i64, offset: i64) -> i64 { - return (2 * e + offset) % COORD_MOD; -} - -// Original lines 41-42: y is x + 1 under the same modulus. -pub fn elem_y(e: i64, offset: i64) -> i64 { - return (2 * e + offset + 1) % COORD_MOD; -} - -// The recursion of original lines 28-58, over (shape, dim) because .t27 -// cannot slice shape[1:]. The leaf case (dim is the last dimension) walks -// entries e = base .. base+n-1 through elem_x/elem_y and advances the base -// by n (lines 35-46). An inner node threads the base through its n -// children unchanged and reports the first child's and last child's -// decisions (lines 48-58). A zero-width dimension emits no children and -// leaves the base untouched, as range(0) does in Python. -fn build_level(shape: []const i64, dim: usize, base: i64, offset: i64) -> TreeBuild { - const n: i64 = shape[dim]; - if (dim + 1 == shape.len) { - // Leaf case: entries e = base .. base+n-1, each mapped through - // x = (2*e + offset) % 32768 and y = (2*e + offset + 1) % 32768 - // (original lines 40-42). - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base + n - 1, offset), - last_y: elem_y(base + n - 1, offset), - leaves: n, - next_base: base + n, - }; - } - if (n < 1) { - // Python emits no children for a zero-width dimension and leaves - // base untouched. - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base, offset), - last_y: elem_y(base, offset), - leaves: 0, - next_base: base, - }; - } - var b: i64 = base; - var first: TreeBuild = build_level(shape, dim + 1, b, offset); - var last: TreeBuild = first; - b = first.next_base; - var i: i64 = 1; - while (i < n) { - last = build_level(shape, dim + 1, b, offset); - b = last.next_base; - i += 1; - } - return TreeBuild { - first_x: first.first_x, - first_y: first.first_y, - last_x: last.last_x, - last_y: last.last_y, - leaves: last.leaves * n, - next_base: b, - }; -} - -// Original line 28: def build_tree(shape: list[int], base: int, offset: int) -// -> tuple[str, int]. The port returns the numeric decisions (TreeBuild) -// instead of the built text; the text itself is string plumbing .t27 cannot -// express. -pub fn build_tree(shape: []const i64, base: i64, offset: i64) -> TreeBuild { - return build_level(shape, 0, base, offset); -} - -// Row-major flat element number of a multi-dimensional index. The original -// computes [MID_IDX][1][0][0][0][0][0] as MID_IDX * 64 + 32 (lines 15-17) -// and the footer it emits asserts through such indices. -pub fn flat_index(shape: []const i64, idx: []const i64) -> i64 { - var flat: i64 = 0; - var i: usize = 0; - while (i < shape.len) { - flat = flat * shape[i] + idx[i]; - i += 1; - } - return flat; -} - -// The original refuses to write the file unless every character is ASCII -// (original line 136: raise ValueError). Ported as a pure predicate; the -// raise itself is the caller's plumbing. -pub fn is_ascii(s: []const u8) -> bool { - for c in s { - if (c > 127) { - return false; - } - } - return true; -} +// TreeBuild, indent, elem_x, elem_y, build_level, build_tree, flat_index and is_ascii +// (original lines 24-25, 28-58, 40-42 and 136) live in gen_w_tree.t27, shared by the +// eight gen_w bench ports. // Original line 61: def generate() -> None. Writes the assembled text to // specs/scratch/w728_bench_module_275x2p6_aos_var_call_write.t27 and prints diff --git a/specs/port/scripts/gen_w729.t27 b/specs/port/scripts/gen_w729.t27 index 8658365eb2..c9004ac95e 100644 --- a/specs/port/scripts/gen_w729.t27 +++ b/specs/port/scripts/gen_w729.t27 @@ -23,6 +23,8 @@ module port::scripts::gen_w729; +use port::scripts::gen_w_tree; + // Header constants (lines 9-21), verbatim arithmetic. const COORD_MOD: i64 = 32768; const OUTER: i64 = 277; @@ -38,146 +40,9 @@ const MID_Y: i64 = (2 * MID_E + 1) % COORD_MOD; const WRAP_LAST_X: i64 = (2 * (TOTAL - 1) + COORD_MOD) % COORD_MOD; const WRAP_LAST_Y: i64 = (2 * (TOTAL - 1) + 1 + COORD_MOD) % COORD_MOD; -// What the recursion decides for one literal: the first and last element -// coordinates, the number of Pt entries, and the next free element index. -// The original returns the built text plus the advanced base (line 29); -// the text is the string plumbing named in the header, these numbers are -// what it encodes. -pub struct TreeBuild { - first_x: i64, - first_y: i64, - last_x: i64, - last_y: i64, - leaves: i64, - next_base: i64, -} - -// Original line 24: def indent(level: int) -> str. " " * level cannot be -// written in .t27 (no string repetition), so the levels the generator can -// reach are spelled out; above level 7 the result clamps at the deepest -// string here. Negative levels are "" as in Python (" " * -2 == ""). -pub fn indent(level: i64) -> str { - if (level <= 0) { - return ""; - } - if (level == 1) { - return " "; - } - if (level == 2) { - return " "; - } - if (level == 3) { - return " "; - } - if (level == 4) { - return " "; - } - if (level == 5) { - return " "; - } - if (level == 6) { - return " "; - } - return " "; -} - -// Original lines 40-42: x = (2 * e + offset) % 32768 for entry e of a leaf -// run. Python's % and the generated % agree on this non-negative domain. -pub fn elem_x(e: i64, offset: i64) -> i64 { - return (2 * e + offset) % COORD_MOD; -} - -// Original lines 41-42: y is x + 1 under the same modulus. -pub fn elem_y(e: i64, offset: i64) -> i64 { - return (2 * e + offset + 1) % COORD_MOD; -} - -// The recursion of original lines 28-58, over (shape, dim) because .t27 -// cannot slice shape[1:]. The leaf case (dim is the last dimension) walks -// entries e = base .. base+n-1 through elem_x/elem_y and advances the base -// by n (lines 35-46). An inner node threads the base through its n -// children unchanged and reports the first child's and last child's -// decisions (lines 48-58). A zero-width dimension emits no children and -// leaves the base untouched, as range(0) does in Python. -fn build_level(shape: []const i64, dim: usize, base: i64, offset: i64) -> TreeBuild { - const n: i64 = shape[dim]; - if (dim + 1 == shape.len) { - // Leaf case: entries e = base .. base+n-1, each mapped through - // x = (2*e + offset) % 32768 and y = (2*e + offset + 1) % 32768 - // (original lines 40-42). - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base + n - 1, offset), - last_y: elem_y(base + n - 1, offset), - leaves: n, - next_base: base + n, - }; - } - if (n < 1) { - // Python emits no children for a zero-width dimension and leaves - // base untouched. - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base, offset), - last_y: elem_y(base, offset), - leaves: 0, - next_base: base, - }; - } - var b: i64 = base; - var first: TreeBuild = build_level(shape, dim + 1, b, offset); - var last: TreeBuild = first; - b = first.next_base; - var i: i64 = 1; - while (i < n) { - last = build_level(shape, dim + 1, b, offset); - b = last.next_base; - i += 1; - } - return TreeBuild { - first_x: first.first_x, - first_y: first.first_y, - last_x: last.last_x, - last_y: last.last_y, - leaves: last.leaves * n, - next_base: b, - }; -} - -// Original line 28: def build_tree(shape: list[int], base: int, offset: int) -// -> tuple[str, int]. The port returns the numeric decisions (TreeBuild) -// instead of the built text; the text itself is string plumbing .t27 cannot -// express. -pub fn build_tree(shape: []const i64, base: i64, offset: i64) -> TreeBuild { - return build_level(shape, 0, base, offset); -} - -// Row-major flat element number of a multi-dimensional index. The original -// computes [MID_IDX][1][0][0][0][0][0] as MID_IDX * 64 + 32 (lines 15-17) -// and the footer it emits asserts through such indices. -pub fn flat_index(shape: []const i64, idx: []const i64) -> i64 { - var flat: i64 = 0; - var i: usize = 0; - while (i < shape.len) { - flat = flat * shape[i] + idx[i]; - i += 1; - } - return flat; -} - -// The original refuses to write the file unless every character is ASCII -// (original line 136: raise ValueError). Ported as a pure predicate; the -// raise itself is the caller's plumbing. -pub fn is_ascii(s: []const u8) -> bool { - for c in s { - if (c > 127) { - return false; - } - } - return true; -} +// TreeBuild, indent, elem_x, elem_y, build_level, build_tree, flat_index and is_ascii +// (original lines 24-25, 28-58, 40-42 and 136) live in gen_w_tree.t27, shared by the +// eight gen_w bench ports. // Original line 61: def generate() -> None. Writes the assembled text to // specs/scratch/w729_bench_module_277x2p6_aos_var_call_write.t27 and prints diff --git a/specs/port/scripts/gen_w732.t27 b/specs/port/scripts/gen_w732.t27 index 4e8227099d..0831f6509a 100644 --- a/specs/port/scripts/gen_w732.t27 +++ b/specs/port/scripts/gen_w732.t27 @@ -27,6 +27,8 @@ module port::scripts::gen_w732; +use port::scripts::gen_w_tree; + // Header constants (lines 9-21), verbatim arithmetic. const COORD_MOD: i64 = 32768; const OUTER: i64 = 283; @@ -42,146 +44,9 @@ const MID_Y: i64 = (2 * MID_E + 1) % COORD_MOD; const WRAP_LAST_X: i64 = (2 * (TOTAL - 1) + COORD_MOD) % COORD_MOD; const WRAP_LAST_Y: i64 = (2 * (TOTAL - 1) + 1 + COORD_MOD) % COORD_MOD; -// What the recursion decides for one literal: the first and last element -// coordinates, the number of Pt entries, and the next free element index. -// The original returns the built text plus the advanced base (line 28); -// the text is the string plumbing named in the header, these numbers are -// what it encodes. -pub struct TreeBuild { - first_x: i64, - first_y: i64, - last_x: i64, - last_y: i64, - leaves: i64, - next_base: i64, -} - -// Original lines 24-25: def indent(level: int) -> str. " " * level cannot -// be written in .t27 (no string repetition), so the levels the generator can -// reach are spelled out; above level 7 the result clamps at the deepest -// string here. Negative levels are "" as in Python (" " * -2 == ""). -pub fn indent(level: i64) -> str { - if (level <= 0) { - return ""; - } - if (level == 1) { - return " "; - } - if (level == 2) { - return " "; - } - if (level == 3) { - return " "; - } - if (level == 4) { - return " "; - } - if (level == 5) { - return " "; - } - if (level == 6) { - return " "; - } - return " "; -} - -// Original line 41: x = (2 * e + offset) % 32768 for entry e of a leaf run. -// Python's % and the generated % agree on this non-negative domain. -pub fn elem_x(e: i64, offset: i64) -> i64 { - return (2 * e + offset) % COORD_MOD; -} - -// Original line 42: y is x + 1 under the same modulus. -pub fn elem_y(e: i64, offset: i64) -> i64 { - return (2 * e + offset + 1) % COORD_MOD; -} - -// The recursion of original lines 28-58, over (shape, dim) because .t27 -// cannot slice shape[1:]. The leaf case (dim is the last dimension) walks -// entries e = base .. base+n-1 through elem_x/elem_y and advances the base -// by n (lines 35-46). An inner node threads the base through its n -// children unchanged and reports the first child's and last child's -// decisions (lines 48-58). A zero-width dimension emits no children and -// leaves the base untouched, as range(0) does in Python. -fn build_level(shape: []const i64, dim: usize, base: i64, offset: i64) -> TreeBuild { - const n: i64 = shape[dim]; - if (dim + 1 == shape.len) { - // Leaf case: entries e = base .. base+n-1, each mapped through - // x = (2*e + offset) % 32768 and y = (2*e + offset + 1) % 32768 - // (original lines 40-42). - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base + n - 1, offset), - last_y: elem_y(base + n - 1, offset), - leaves: n, - next_base: base + n, - }; - } - if (n < 1) { - // Python emits no children for a zero-width dimension and leaves - // base untouched. - return TreeBuild { - first_x: elem_x(base, offset), - first_y: elem_y(base, offset), - last_x: elem_x(base, offset), - last_y: elem_y(base, offset), - leaves: 0, - next_base: base, - }; - } - var b: i64 = base; - var first: TreeBuild = build_level(shape, dim + 1, b, offset); - var last: TreeBuild = first; - b = first.next_base; - var i: i64 = 1; - while (i < n) { - last = build_level(shape, dim + 1, b, offset); - b = last.next_base; - i += 1; - } - return TreeBuild { - first_x: first.first_x, - first_y: first.first_y, - last_x: last.last_x, - last_y: last.last_y, - leaves: last.leaves * n, - next_base: b, - }; -} - -// Original line 28: def build_tree(shape: list[int], base: int, offset: int) -// -> tuple[str, int]. The port returns the numeric decisions (TreeBuild) -// instead of the built text; the text itself is string plumbing .t27 cannot -// express. -pub fn build_tree(shape: []const i64, base: i64, offset: i64) -> TreeBuild { - return build_level(shape, 0, base, offset); -} - -// Row-major flat element number of a multi-dimensional index. The original -// computes [MID_IDX][1][0][0][0][0][0] as MID_IDX * 64 + 32 (lines 15-16) -// and the footer it emits asserts through such indices. -pub fn flat_index(shape: []const i64, idx: []const i64) -> i64 { - var flat: i64 = 0; - var i: usize = 0; - while (i < shape.len) { - flat = flat * shape[i] + idx[i]; - i += 1; - } - return flat; -} - -// The original refuses to write the file unless every character is ASCII -// (original line 136: raise ValueError). Ported as a pure predicate; the -// raise itself is the caller's plumbing. -pub fn is_ascii(s: []const u8) -> bool { - for c in s { - if (c > 127) { - return false; - } - } - return true; -} +// TreeBuild, indent, elem_x, elem_y, build_level, build_tree, flat_index and is_ascii +// (original lines 24-25, 28-58, 40-42 and 136) live in gen_w_tree.t27, shared by the +// eight gen_w bench ports. // Original line 61: def generate() -> None. Re-indents the built literal, // wraps it in make_grid/header/footer text, checks the ASCII gate, writes diff --git a/specs/port/scripts/gen_w_tree.t27 b/specs/port/scripts/gen_w_tree.t27 new file mode 100644 index 0000000000..e992edd22c --- /dev/null +++ b/specs/port/scripts/gen_w_tree.t27 @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: Apache-2.0 +// The tree-walk helpers the ports of scripts/gen_w698.py, gen_w709.py, gen_w713.py, +// gen_w716.py, gen_w721.py, gen_w728.py, gen_w729.py and gen_w732.py share, written once. +// Each of those scripts generates a "bench module" for an N x 2**6 array-of-structs grid and +// carries the same helpers: the indent table, the coordinate rule, the recursive build over a +// shape, the row-major flat index and the ASCII gate. The eight ports had copied every one of +// them, and the duplicate-bodies gate went red on master (build_level, indent, flat_index and +// is_ascii each copied 7 or 8 times). Each port now keeps only its own header constants, its +// generate() stub and its own tests; the helpers resolve through `use`, as the gen_w310 .. +// gen_w322 ports resolve gen_w_blocks.t27. +// The helpers carry the generators' decisions, not their string plumbing: the built literal +// text becomes the numeric decisions that determine it (TreeBuild). +module port::scripts::gen_w_tree; + +// The modulus every coordinate folds through (original lines 13-21, 41-42). +const COORD_MOD: i64 = 32768; + +// What the recursion decides for one literal: the first and last element +// coordinates, the number of Pt entries, and the next free element index. +// The original returns the built text plus the advanced base (line 28); +// the text is string plumbing .t27 cannot express, these numbers are what it encodes. +pub struct TreeBuild { + first_x: i64, + first_y: i64, + last_x: i64, + last_y: i64, + leaves: i64, + next_base: i64, +} + +// Original lines 24-25: def indent(level: int) -> str. " " * level cannot be +// written in .t27 (no string repetition), so the levels the generator can +// reach are spelled out; above level 7 the result clamps at the deepest +// string here. Negative levels are "" as in Python (" " * -2 == ""). +pub fn indent(level: i64) -> str { + if (level <= 0) { + return ""; + } + if (level == 1) { + return " "; + } + if (level == 2) { + return " "; + } + if (level == 3) { + return " "; + } + if (level == 4) { + return " "; + } + if (level == 5) { + return " "; + } + if (level == 6) { + return " "; + } + return " "; +} + +// Original lines 40-42: x = (2 * e + offset) % 32768 for entry e of a leaf run. +// Python's % and the generated % agree on this non-negative domain. +pub fn elem_x(e: i64, offset: i64) -> i64 { + return (2 * e + offset) % COORD_MOD; +} + +// Original lines 41-42: y is x + 1 under the same modulus. +pub fn elem_y(e: i64, offset: i64) -> i64 { + return (2 * e + offset + 1) % COORD_MOD; +} + +// The recursion of original lines 28-58, over (shape, dim) because .t27 +// cannot slice shape[1:]. The leaf case (dim is the last dimension) walks +// entries e = base .. base+n-1 through elem_x/elem_y and advances the base +// by n (lines 35-46). An inner node threads the base through its n +// children unchanged and reports the first child's and last child's +// decisions (lines 48-58). A zero-width dimension emits no children and +// leaves the base untouched, as range(0) does in Python. +fn build_level(shape: []const i64, dim: usize, base: i64, offset: i64) -> TreeBuild { + const n: i64 = shape[dim]; + if (dim + 1 == shape.len) { + // Leaf case: entries e = base .. base+n-1, each mapped through + // x = (2*e + offset) % 32768 and y = (2*e + offset + 1) % 32768 + // (original lines 40-42). + return TreeBuild { + first_x: elem_x(base, offset), + first_y: elem_y(base, offset), + last_x: elem_x(base + n - 1, offset), + last_y: elem_y(base + n - 1, offset), + leaves: n, + next_base: base + n, + }; + } + if (n < 1) { + // Python emits no children for a zero-width dimension and leaves + // base untouched. + return TreeBuild { + first_x: elem_x(base, offset), + first_y: elem_y(base, offset), + last_x: elem_x(base, offset), + last_y: elem_y(base, offset), + leaves: 0, + next_base: base, + }; + } + var b: i64 = base; + var first: TreeBuild = build_level(shape, dim + 1, b, offset); + var last: TreeBuild = first; + b = first.next_base; + var i: i64 = 1; + while (i < n) { + last = build_level(shape, dim + 1, b, offset); + b = last.next_base; + i += 1; + } + return TreeBuild { + first_x: first.first_x, + first_y: first.first_y, + last_x: last.last_x, + last_y: last.last_y, + leaves: last.leaves * n, + next_base: b, + }; +} + +// Original line 28: def build_tree(shape: list[int], base: int, offset: int) +// -> tuple[str, int]. The port returns the numeric decisions (TreeBuild) +// instead of the built text. +pub fn build_tree(shape: []const i64, base: i64, offset: i64) -> TreeBuild { + return build_level(shape, 0, base, offset); +} + +// Row-major flat element number of a multi-dimensional index. The original +// computes [MID_IDX][1][0][0][0][0][0] as MID_IDX * 64 + 32 (lines 15-17) +// and the footer it emits asserts through such indices. +pub fn flat_index(shape: []const i64, idx: []const i64) -> i64 { + var flat: i64 = 0; + var i: usize = 0; + while (i < shape.len) { + flat = flat * shape[i] + idx[i]; + i += 1; + } + return flat; +} + +// The original refuses to write the file unless every character is ASCII +// (original line 136: raise ValueError). Ported as a pure predicate; the +// raise itself is the caller's plumbing. +pub fn is_ascii(s: []const u8) -> bool { + for c in s { + if (c > 127) { + return false; + } + } + return true; +} + +test indent_clamps_and_folds_negative { + const l1: str = indent(1); + const l2: str = indent(2); + const l7: str = indent(7); + const l99: str = indent(99); + assert(indent(0) == ""); + assert(indent(-2) == ""); + assert(l1 == " "); + assert(l2.len == 8); + assert(l7.len == 28); + assert(l99.len == 28); +} + +test elem_coords_fold_modulo { + assert(elem_x(0, 0) == 0); + assert(elem_y(0, 0) == 1); + assert(elem_x(16383, 0) == 32766); + assert(elem_y(16383, 0) == 32767); + assert(elem_x(16384, 0) == 0); + assert(elem_y(16384, 0) == 1); + assert(elem_x(5, 32768) == 10); +} + +test build_tree_leaf_walks_base { + var shape: [1]i64 = [5]; + const t: TreeBuild = build_tree(&shape, 3, 0); + assert(t.first_x == 6); + assert(t.first_y == 7); + assert(t.last_x == 14); + assert(t.last_y == 15); + assert(t.leaves == 5); + assert(t.next_base == 8); +} + +test build_tree_nested_threads_base { + var shape: [2]i64 = [2, 2]; + const t: TreeBuild = build_tree(&shape, 7, 0); + assert(t.first_x == 14); + assert(t.first_y == 15); + assert(t.last_x == 20); + assert(t.last_y == 21); + assert(t.leaves == 4); + assert(t.next_base == 11); +} + +test build_tree_zero_width_dim_keeps_base { + var shape: [2]i64 = [0, 3]; + const t: TreeBuild = build_tree(&shape, 5, 0); + assert(t.leaves == 0); + assert(t.next_base == 5); +} + +test flat_index_is_row_major { + var shape: [3]i64 = [4, 3, 2]; + var first: [3]i64 = [0, 0, 0]; + var mid: [3]i64 = [1, 2, 1]; + var last: [3]i64 = [3, 2, 1]; + assert(flat_index(&shape, &first) == 0); + assert(flat_index(&shape, &mid) == 11); + assert(flat_index(&shape, &last) == 23); +} + +test is_ascii_gate { + assert(is_ascii("module w_tree\n")); + assert(is_ascii("")); + var bad: [4]u8 = [80, 116, 210, 10]; + assert(!is_ascii(&bad)); +} diff --git a/specs/port/trinity/fpga/openxc7-synth/trinity_block_step1_top.t27 b/specs/port/trinity/fpga/openxc7-synth/trinity_block_step1_top.t27 index 206d756160..4458f7d568 100644 --- a/specs/port/trinity/fpga/openxc7-synth/trinity_block_step1_top.t27 +++ b/specs/port/trinity/fpga/openxc7-synth/trinity_block_step1_top.t27 @@ -30,6 +30,17 @@ // faked: ternary_matvec_bram reads its weight pattern from a BRAM .mem file, // and the weights here are recomputed from the generator pattern documented // in the Verilog header. uart_rx drives nothing in the original logic either. +// +// Deliberate copies (Refs #9631, #8769): weight_sign, led_state_next, +// led_counter_next, debug_state_bits, bit_at, uart_tx_bit_at, +// build_report_frame and on_comb are written the same way in +// trinity_block_step1_top.t27 and trinity_block_step2_top.t27, because each +// top must carry them itself. on_comb is this module's data port in +// gen-verilog, and gen-verilog does not emit a function brought in by `use` +// (#8769, open): moved into a shared module, they would leave the RTL calling +// functions it never defines, and gen-verilog would still exit 0. The copies +// are recorded in tools/duplicate_bodies_baseline.txt; share them once #8769 +// is fixed. module trinity_block_step1_top { // PARAMETERS (localparam block) diff --git a/specs/port/trinity/fpga/openxc7-synth/trinity_block_step2_top.t27 b/specs/port/trinity/fpga/openxc7-synth/trinity_block_step2_top.t27 index 93ac2e4111..7878dd099b 100644 --- a/specs/port/trinity/fpga/openxc7-synth/trinity_block_step2_top.t27 +++ b/specs/port/trinity/fpga/openxc7-synth/trinity_block_step2_top.t27 @@ -34,6 +34,17 @@ // clocked plumbing (the mv1 address is delayed one cycle to align with the // ReLU), and uart_rx drives nothing in the original logic. The weights here // are recomputed from the generator pattern documented in the Verilog header. +// +// Deliberate copies (Refs #9631, #8769): weight_sign, led_state_next, +// led_counter_next, debug_state_bits, bit_at, uart_tx_bit_at, +// build_report_frame and on_comb are written the same way in +// trinity_block_step1_top.t27 and trinity_block_step2_top.t27, because each +// top must carry them itself. on_comb is this module's data port in +// gen-verilog, and gen-verilog does not emit a function brought in by `use` +// (#8769, open): moved into a shared module, they would leave the RTL calling +// functions it never defines, and gen-verilog would still exit 0. The copies +// are recorded in tools/duplicate_bodies_baseline.txt; share them once #8769 +// is fixed. module trinity_block_step2_top { // PARAMETERS (localparam block) diff --git a/tools/duplicate_bodies_baseline.txt b/tools/duplicate_bodies_baseline.txt index 0a8789a3ba..d67c1c8eec 100644 --- a/tools/duplicate_bodies_baseline.txt +++ b/tools/duplicate_bodies_baseline.txt @@ -51,7 +51,7 @@ list_active 3 mem_eql_at 3 negate 3 neuronN 3 -on_comb 3,2 +on_comb 3,2,2 pack2 3 pow2_frac 3 publish_result_to_string 3 @@ -74,11 +74,13 @@ assert_pass 2 axi4_full_master 2 axi4_lite_master 2 beam_search_prm_pipeline 2 +bit_at 2 bits 2 booth_mul_i16 2 booth_mul_u32_inner 2 build_edges_from_shared_ports 2 build_knowledge_graph 2 +build_report_frame 2 bytes32_eq 2 bytes64_eq 2 bytes_eq 2 @@ -99,6 +101,7 @@ cordic_z_next 2 cos_approx 2 count_keyword_diffs 2 counter_24bit 2 +debug_state_bits 2 declare_module_ports 2 declare_top_ports 2 decode_logits 2 @@ -113,7 +116,6 @@ exp2 2 extract_mantissa 2,2 fallback_to_template 2 find_shared_port_names 2 -flat_index 2 full_adder 2 generate_diverse_candidates 2 generate_diverse_candidates_inner 2 @@ -135,11 +137,12 @@ has_at 2 hw_place_before 2 instantiate_modules 2 instantiate_ports 2 -is_ascii 2 is_counter_power_of_two 2 is_name_byte 2 kill 2 led_config 2 +led_counter_next 2 +led_state_next 2 line_end 2 local_branch 2 log2_frac 2 @@ -188,6 +191,7 @@ trit_compare 2 trit_max 2 trit_min 2 trit_mul_closed 2 +uart_tx_bit_at 2 unsubscribe_result_create 2 v_cs_chimera 2 validate_blink_state 2 @@ -196,6 +200,7 @@ validate_led_config 2 validate_modules_have_ports 2 validate_trits 2 wave_segments 2 +weight_sign 2 wide_tail 2 wire_modules 2 xor2 2