Skip to content

feat(t27b): bench blocks as the reference path handles them (Closes #6179) - #6258

Merged
gHashTag merged 2 commits into
masterfrom
claude/t27b-bench
Oct 4, 2026
Merged

gHashTag merged 2 commits into
masterfrom
claude/t27b-bench

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Closes #6179
Refs #6063

Stacked on #6254 (enums), which is stacked on #6249 and #6247.

FR-001 -- what the reference does with a bench

t27c gen specs/numeric/e8m0.t27 emits the bench as a plain fn. Nothing calls it, and the output does not mention its name anywhere else:

fn bench_e8m0_decode_encode() void {
    // bench: e8m0_decode_encode
    if (!(e8m0_exponent(E8M0_ONE) == 0)) __t27_assert_fail(...);
    ...
}

specs/config/paths.t27 gives the same shape: fn bench_paths_join_latency() void { ... }, and so on for each bench.

So zig test neither runs nor counts a bench. Because Zig analyzes lazily, it does not even type-check the body:

  • I put const bogus: u8 = "not a u8"; into bench_e8m0_decode_encode. zig test still printed All 18 tests passed.
  • I added test "reference the bench" { _ = &bench_e8m0_decode_encode; }. zig test then failed with error: expected type 'u8', found '*const [8:0]u8'.

What t27b now does (FR-002)

  • Each bench body is lowered with the test binding rule, which is the rule gen_bench_block uses (the first assignment becomes a const).
  • The body is then compiled to AArch64 with codegen::compile_func and dropped. It is never run and never counted as a test, so a failing assert in a bench does not fail the file, as in the reference.
  • A body t27b cannot lower rejects the file under the construct it contains (for example StmtFor(range)), never under BenchBlock. A codegen refusal rejects the file too.
  • There is no interpreter fallback and no skipped body. This is stricter than Zig, which never looks at the body.
  • BenchBlock is still named for a bench the front-end only partly parsed, the same way TestBlock and InvariantBlock are.

FR-003

cli/t27b/tests/differential.rs:

  • bench_bodies_compile_but_never_run lowers a spec with two failing benches (a brace bench and a colon bench). Only the one test runs, and JIT and interpreter agree on it. It then renames the same bodies to test/invariant: they run and trap at the same site in both the JIT and the interpreter.
  • bench_unlowerable_body_names_its_construct checks that an unlowerable bench body is rejected as StmtFor(range) and never as BenchBlock.

cargo test -p t27b passes.

Corpus (t27b corpus specs, macOS arm64, from the worktree root)

before (#6254 head) after
pass 165 (973 tests) 169 (1024 tests)
pass_vacuous 278 278
fail 2 2 (same two files)
rejected 760 756
JIT/interpreter mismatch 0 0

pass_vacuous gained nothing.

New passes, each checked with t27c gen + zig test. The reference agrees on all four, with the same test count:

file reference
boards/wukong_v1 15/15
igla/race/ternary_lut_table 15/15
numeric/e8m0 18/18
numeric/golden_sieve 3/3

New fails: none.

The 112 other former-BenchBlock files now stop on a real construct:

construct files
StmtAssign(undeclared) 23
StmtExpr 22
ExprLiteral(negative literal) 19
ExprCall(method) 7
ExprArrayLiteral 6
type mismatch 5
others 30

All 22 StmtExpr stops are "empty statement" inside a bench written in the prose form measure: nanoseconds to ... / target: < 100ns. The t27c front-end lowers that form to nothing; its Zig output says // NOT LOWERED: empty statement -- statement rendered to nothing (T43). Under FR-002, t27b rejects such a body rather than passing an empty one.

Top first blockers

  • before: BenchBlock 116, type f64 107, type f32 69, ?T 47, std.mem.Allocator 44
  • after: type f64 110, type f32 70, type ?T 47, type std.mem.Allocator 44, type [N]T 39, ExprBinary(<< >>) 36, type (undeclared) 36, StmtExpr 35

Reference-side finding: broken bench bodies the reference never checks

For the 116 former-BenchBlock files I ran t27c gen + zig test, then again with _ = &bench_x; added for every bench:

  • 37 files pass, 78 fail, and fpga/testbench/gf16_accel_tb hangs in test_add_zero.
  • In 8 of the 37 passing files, Zig rejects the bench body as soon as it is referenced:
    • fpga/boards/arty_a7_integration, fpga/boards/qmtech_a100t_integration, and fpga/testbench/{cts,partition,power,simulator,router}_tb: value of type 'u32' ignored. Example: estimate_latency(...) called as a statement in bench_cts.
    • isa/ternary_gates: unable to resolve comptime value. It indexes a .{...} tuple with a runtime value.
  • t27b rejects all 8 files anyway, on earlier constructs.

These are spec bugs that lazy analysis hides, not t27c miscompiles. I left them for a separate issue.

🤖 Generated with Claude Code

…6179)

t27c's Zig backend emits a bench as `fn bench_<name>() void { ... }`
that nothing calls: `zig test` neither runs nor counts it, and lazy
analysis does not even type-check it. t27b now lowers each bench body
with the test binding rule, compiles it to AArch64 and drops it: never
run, never a test. A body it cannot lower rejects the file under the
construct it contains, never `BenchBlock`.

corpus specs: pass 165 -> 169, pass_vacuous 278 -> 278, fail 2 -> 2,
rejected 760 -> 756, mismatch 0. The 4 new passes agree with the
reference (15/15, 15/15, 18/18, 3/3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-04 21:03:11 UTC

Summary

Status Count
Total Open PRs 44
PRs with Failing Checks 32
PRs with All Checks Green 12
READY 11
FAILING 32
PENDING 0
NO CHECKS YET 0

These columns do not partition: 11 + 32 + 0 + 0 = 43, and there are 44 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=8597b6ded596 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

t27b: bench blocks handled as the reference path handles them (first rejection in 35 specs)

1 participant