Skip to content

t27b: @abs, @max, @min and std.math.pi / e lower from a t27 plan (Closes #7394) - #7614

Merged
gHashTag merged 4 commits into
masterfrom
claude/t27b-builtin-plan-7394
Oct 7, 2026
Merged

gHashTag merged 4 commits into
masterfrom
claude/t27b-builtin-plan-7394

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Closes #7394. Part of #6063 (t27b coverage, lane 4); written in t27 under the port epic #6198. Supersedes draft #7411, which did the same in 133 hand-written Rust lines.

What

t27b now lowers @abs(x), @max(a, b), @min(a, b), std.math.pi and std.math.e. gen-zig prints all of them as written. A bare abs(x) with no fn abs declared now goes through the same path. The semantics are #7411's, which were measured on the t27b lab against Zig 0.16 Debug:

  • @abs of an f64 / f32 is the magnitude. A literal folds. A typed integer is refused, because Zig's @abs of an iN is a uN.
  • @max / @min:
    • Two floats of one type: a NaN gives the other operand, and equal operands give the first. For -0.0 against +0.0 that is t27b's choice; see "Signed zero" below.
    • A literal beside a typed float takes that float's type.
    • Two integers of one type: the larger or smaller value.
    • Each operand is evaluated once.
  • std.math.pi / std.math.e are Zig's comptime_float digits, held as binary128.

What t27b decides is a t27 spec. specs/tri/t27b/builtin_plan.t27 holds:

  • the arity of each call;
  • the decision table for where the result type comes from (refuse, first operand, second operand, or fold);
  • the select chain each call lowers to, as rows over numbered slots;
  • the operator of each row;
  • the names a refusal reports;
  • the digits of the two constants.

t27c gen-rust turns it into gen/rust/tri/t27b/builtin_plan.rs. cli/t27b/src/lower.rs mounts that file with #[path], the way a64.rs and macho.rs mount theirs.

What the hand-written glue does:

  • maps the call name to a code;
  • classifies each lowered operand (typed float, typed int, comptime float, comptime int, other);
  • folds @abs of a literal;
  • evaluates each operand once;
  • turns the rows of the plan into IR selects;
  • matches the std.math.X shape.

The spec's run_plan walks the same rows over f64 values, so its tests check the semantics on the plan itself.

Lines

file kind added deleted
cli/t27b/src/lower.rs hand-written glue 40 0
cli/t27b/src/lower_float.rs hand-written glue 37 34
gen/rust/tri/t27b/builtin_plan.rs t27c gen-rust, not hand-edited 247 0
specs/tri/t27b/builtin_plan.t27 spec, 12 tests 388 0
specs/tri/t27b/conformance/builtin_abs_max_min_pi.t27 #7411's conformance spec, one test made target-neutral, 12 tests 211 0
.trinity/seals/*.json (2) t27c seal --save 40 0
docs/reports/t27b_expectations.json ledger 11 9
AGENTS.md t27b remainder line 4 1

Hand-written glue is 77 added lines: 40 in lower.rs and 37 in lower_float.rs. That is under the #7371 cap of 40 per file and 80 per PR. The 34 deleted lines are the old hand-written bare_abs lowering.

Both glue files were already in master's tools/policy/foreign-exceptions.txt. This PR does not change that file and needs no label.

Hand-written Rust in cli/t27b/src/*.rs, measured with wc -l, goes from 14769 to 14812. cli/t27b/tests/*.rs stays at 7814.

Gates (run on the t27c Railway lab)

  • check_budget(), master's gen/c/policy/own_language.c with the one-line C main from lefthook.yml, over git diff --numstat --no-renames origin/master...HEAD: exit 0.
  • check_all(), with the exception list from origin/master:tools/policy/foreign-exceptions.txt, in both the -- (pre-push) and --ci forms: exit 0.
  • Negative controls: 41 added lines in one file, 81 in all, and an unlisted new .rs file are each denied.
  • tools/l2_regen_check.py --base 95182e95b: t27c gen-rust specs/tri/t27b/builtin_plan.t27 reproduces the generated file byte for byte. gen-rust was deterministic over 3 runs.
  • tools/check_seal_coverage.py and tools/check_seal_currency.py: exit 0. Both new seals pass t27c seal --verify with all hashes MATCH.
  • The other spec gates this PR could move, run at the head:
    • t27c suite --repo-root . --ratchet --corpus-only: RATCHET CLEAN, 77 / 77.
    • tri types ratchet: CLEAN, 101 names.
    • tri types classified: OK.
    • tools/check_assertionless_spec_tests.py: ok.
    • tools/check_verilog_widths.py --require: 0 new.
    • tools/dupe_scan.py: only the five groups its base 95182e9 already reports, none from this PR.
  • About 1fee253: the first head's same_text test helper duplicated same in specs/tri/utils/template.t27. The tests now use std.mem.eql(u8, ...) instead, and the helper is gone. After that change the spec was re-run (12/12, 0 vacuous), resealed, and its mutants re-run (10 of 10 killed). t27b runs the spec under --check with 12 passed and 103 runtime asserts.

Spec checks (t27c lab, t27c built from master 95182e9, zig 0.16.0)

t27c test-report (head 7e6b26c):

  • specs/tri/t27b/builtin_plan.t27: 12/12 pass, 0 of 12 vacuous, 103 runtime asserts.
  • the conformance spec: 12/12 pass, 0 of 12 vacuous.
  • Both specs also pass zig test for aarch64-linux-musl under qemu-aarch64: all 12 tests each.

Mutants. I tested 10 mutants of the plan spec, each on a copy of the spec, and all 10 were killed:

  • max row 0 picks the smaller operand;
  • a NaN row uses <;
  • the abs row uses < instead of <=;
  • a float beside a literal takes the literal's side;
  • integer @max keeps the NaN rows;
  • digit 25 of pi is changed;
  • the bare-abs arity refusal is renamed;
  • a comptime_int is not treated as a literal;
  • mixed int types are accepted;
  • min row 0 compares a < b.

One of them, the b-NaN row using <, is caught only by the exact row-table test. With row 0 as written, that row cannot change a result: it is there because #7411's chain has it, and this PR keeps the IR identical.

t27b lab: full corpus with the reference

Master base 95182e9. These are the lab's own scheduled run numbers: https://t27b-lab-production.up.railway.app/runs/95182e95b389cca697f0edd3fd8433dcf5fa06a9.json (qemu-aarch64 t27b corpus specs --json --runner qemu-aarch64 --timeout-ms 60000 --jobs 24).

Branch head 7e6b26c, and the earlier heads 1fee253 and 0ab8f32:

  • Each ran the deployed /opt/t27b-lab/lab.py lab_run in a private work dir in the same container.
  • Each used the same image and toolchain, --jobs 12, and 3 reference workers.
  • Fuzz was off.
  • The run JSONs are not published at the lab URL. Their sha256 values are f437ddb3..., 9463db16... and 3737880c....
  • The three branch runs agree file by file (verdicts, blockers, tests and asserts), with one exception: the conformance spec has 59 asserts at the head and 57 before it, because of the test edited in 7e6b26c.
master 95182e9 branch 7e6b26c
files 1562 1564 (+2: the new specs)
pass 860 868
pass_vacuous 151 151
blocked 532 526
fail 16 16
timeout 2 2
mismatch (= jit_interp_mismatch) 1 1
reference pass 1076 1078
reference disagree 0 0
cargo test --release -p t27b (aarch64, qemu) 128 passed, 0 failed 128 passed, 0 failed

Per file:

  • These six move from blocked to pass:
    • specs/ml/rl/dqn.t27
    • specs/port/trinity/src/tri/string_dualities.t27
    • specs/ml/layers/residual_connection.t27
    • specs/ml/loss/huber_loss.t27
    • specs/ml/loss/mse_loss.t27
    • specs/ml/optimizer/rmsprop.t27
  • Two stay blocked with a later first blocker:
    • weber_tuning: @abs -> std.*;
    • probability: @min -> @exp.
  • Both new specs pass with runtime asserts: builtin_plan.t27 has 103 and the conformance spec has 59.
  • Nothing leaves pass. Every other file has the same verdict, first blocker, test count and assert count on both runs.

The one mismatch is specs/port/trinity/src/tri/gen_canvas.t27, on master as well. It is inherited and filed as #7550.

Ledger

tri t27b ratchet compared the branch run with the master run. The only verdict moves are the six above plus the two new UNLISTED specs.

  • How the rows were made: those 8 rows come from ratchet --bless of the branch run, and every other row is master's.
  • Counts: pass 846 -> 854, not_pass 67 -> 61, max_not_pass 67 -> 61.
  • Size: 1065 rows, no duplicate path.
  • Ratchet result: against the new ledger, the branch run shows exactly master's existing findings: UNEXPECTED PASS 2, UNLISTED 14, STALE 1. It adds one informational MOVED, the weber_tuning blocker.

Signed zero

The first t27b-native CI run of this PR, on ubuntu-24.04-arm, failed one conformance test in the reference: amp_equal_operands_give_the_first, from #7411. The ratchet then called the new spec STALE.

Zig 0.16 leaves the sign of @max / @min of -0.0 and +0.0 to the target. I measured it on the t27b lab with zig test, natively and for aarch64-linux-musl under qemu-aarch64:

max(-0,+0) max(+0,-0) min(-0,+0) min(+0,-0)
x86_64 -0 +0 -0 +0
aarch64 +0 +0 -0 -0

On x86_64 the result is always the first operand. On aarch64 it follows IEEE maxNum / minNum (fmaxnm / fminnm).

What changed:

  • The conformance test is now amp_equal_operands_give_an_equal_value. It asserts == 0.0 and two equal-value cases, which hold on both targets.
  • t27b keeps the first operand, which is t27b lane 4: @abs, @max, @min and std.math.pi / std.math.e #7394's stated semantics and the x86_64 answer that the t27b lab's reference gives.
  • builtin_plan.t27 says in its header that this is t27b's choice. Its own run_plan test of that choice is plain compare-and-select, so it passes on both targets.

No other corpus spec depends on the sign: the arm64 CI run disagreed with t27b on that one test only.

gen-rust gaps

Generated with Claude Code

claude and others added 2 commits October 8, 2026 03:33
 #7394)

What t27b decides about these calls is specs/tri/t27b/builtin_plan.t27:
which operands each call takes, where the result type comes from, the
select chain each call lowers to (rows over numbered slots), the operator
of each row, the names a refusal reports, and Zig's digits of std.math.pi
and std.math.e. `t27c gen-rust` gives gen/rust/tri/t27b/builtin_plan.rs,
mounted in cli/t27b/src/lower.rs the way a64.rs and macho.rs mount theirs.
The Rust glue classifies the lowered operands, evaluates each one once and
turns the rows into IR selects. A bare `abs(x)` now goes through the same
plan; its IR is unchanged.

Hand Rust added: lower.rs 40, lower_float.rs 37 (34 deleted), 77 in all,
under the #7371 cap of 40 per file and 80 per PR. Generated: 261 lines.
Spec: 395 lines, 12 tests, 0 vacuous on `t27c test-report`; 10 of 10
mutants killed. The conformance spec is #7411's, 12 of 12 on the reference.

Closes #7394

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oses #7394)

`tri t27b ratchet` of a private t27b lab run of 0ab8f32 (the deployed
lab.py lab_run), compared with the lab's own run of its base 95182e9:
the only verdict moves are blocked -> pass for dqn, string_dualities,
residual_connection, huber_loss, mse_loss and rmsprop, and both new specs
pass. Those eight rows come from `ratchet --bless` of the branch run;
every other row is master's. pass 846 -> 854, not_pass 67 -> 61,
max_not_pass 67 -> 61; 1065 rows, no duplicate path.

Closes #7394

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…7394)

The spec's own `same_text` helper had the body of `same` in
specs/tri/utils/template.t27, a new duplicate group for tools/dupe_scan.py.
The tests now use `std.mem.eql(u8, ...)`, which gen-zig prints as written
and t27b lowers, and the helper is gone; the generated Rust loses it too
(261 -> 247 lines). Resealed with t27c from master 95182e9 on the t27c
lab: 12/12 pass, 0 vacuous, all hashes MATCH; 10 of 10 mutants still
killed; on the t27b lab `t27b test --check` gives 12 passed and 103
runtime asserts, so the ledger row stays `pass`.

Closes #7394

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

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-07 21:26:18 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 47
PRs with All Checks Green 3
READY 1
FAILING 47
PENDING 0
NO CHECKS YET 0

These columns do not partition: 1 + 47 + 0 + 0 = 48, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=39fa3908f9fd != 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).

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-07 21:36:33 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 46
PRs with All Checks Green 4
READY 1
FAILING 46
PENDING 0
NO CHECKS YET 0

These columns do not partition: 1 + 46 + 0 + 0 = 47, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=39fa3908f9fd != 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).

….0 (Closes #7394)

The t27b-native CI corpus (ubuntu-24.04-arm) had the reference fail
amp_equal_operands_give_the_first, so the ratchet called the new
conformance spec STALE. Zig 0.16 leaves that sign to the target. Measured
on the t27b lab, `zig test` natively and for aarch64-linux-musl under
qemu-aarch64:

  x86_64:  max(-0,+0) = -0, max(+0,-0) = +0, min(-0,+0) = -0, min(+0,-0) = +0
  aarch64: max gives +0 both ways, min gives -0 both ways

The conformance test now asserts that equal operands give an equal value,
which both targets do. builtin_plan.t27 says in its header that the first
operand is t27b's choice (the x86_64 answer, which the t27b lab's
reference gives); its run_plan test of that choice is plain compare and
select and passes on both. Both specs: `t27c test-report` 12/12, 0
vacuous; `zig test` for aarch64 under qemu: all 12 pass. Resealed with
t27c from master 706788b (bootstrap/src/compiler.rs unchanged since
95182e9); builtin_plan's generated Rust is byte-identical.

Closes #7394

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
auto-merge was automatically disabled October 7, 2026 21:59

Head branch was modified

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-07 22:04:38 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 49
PRs with All Checks Green 1
READY 1
FAILING 49
PENDING 0
NO CHECKS YET 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=39fa3908f9fd != 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 lane 4: @abs, @max, @min and std.math.pi / std.math.e

2 participants