Skip to content

t27b: @log, @log2 and @log10 of an f32 call t27 ports of compiler_rt (Closes #7822) - #7918

Merged
gHashTag merged 8 commits into
masterfrom
t27b/gf16-logf
Oct 9, 2026
Merged

gHashTag merged 8 commits into
masterfrom
t27b/gf16-logf

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Closes #7822. Part of #7746 (t27b passes specs/numeric/gf16.t27, the numeric SSOT of law L6), which is part of #6063 (t27b coverage), item C10 of #6488. This is the third PR of #7746's split, after #7791 (#7818) and #7819 (#7863), both merged.

What

t27b now lowers @log, @log2 and @log10 of an f32 to calls of t27 ports in specs/tri/t27b/libm.t27:

  • the ports are compiler_rt's logf, log2f and log10f (log.zig, log2.zig and log10.zig): musl's fdlibm-style routines on the bits, not the table-driven f64 log that libm.t27 already holds;
  • @log2 and @log10 join specs/tri/t27b/libm_plan.t27, and an f32 @log is no longer refused;
  • an f64 @log2 or @log10 is refused (libm.t27 has no f64 routine for it), because compiler_rt's f64 log2 and log10 are not ported;
  • every builtin now has its f32 routine, so the plan drops has_f32 and REFUSE_NO_ROUTINE.

The ports set a variable from a bitcast (ix = @bitCast(x)), as compiler_rt does. The glue therefore gives @bitCast its result type from an assignment's target, as it already does for @floatFromInt, @intFromFloat and @floatCast. That is 1 line in lower.rs.

What the reference does

Measured on the t27c lab (zig 0.16.0, x86_64 Debug, no libc), with Zig probes:

  • A run-time @log, @log2 or @log10 of an f32 is a call of compiler_rt logf, log2f or log10f. None is correctly rounded. For example, @log10 of 1e-40 is -40.000004 (0xC2200001), and @log2 of the largest f32 is 128 exactly.
  • want_float_exceptions is true on x86_64 and aarch64. So a zero gives -1 / (x * x) (-inf), and a negative gives (x - x) / 0.0, a NaN with the platform's bits. +inf and a NaN come back as they are, a signalling NaN too (@log of 0x7F800001 is 0x7F800001).
  • A typed f32 operand Zig knows at compile time folds to the run-time bits. 0 of 24000 points differ per builtin: every 357913th bit pattern, and 12000 points between 0.125 and 2.

Decisions, including every float edge case

  • The ports are compiler_rt's, step for step.
    • The constants are written as exact decimals of their f32 values (Lg1 = 0xaaaaaa.0p-24 is 0.66666662693023681640625), so Zig and t27b read the same bits.
    • The operation order is compiler_rt's.
    • compiler_rt's ix << 1 == 0 is read through a mask.
  • The zeros, the infinities, a NaN and one are compared with Zig's builtin bit for bit: -1 / (x * x) gives -inf for both zeros, and +inf and NaN payloads pass through.
  • A negative operand's NaN has the platform's bits. Its value is never pinned. The sweeps compare the port with Zig's builtin, and both compute (x - x) / 0.0 on the same machine, so they agree on x86_64 and on aarch64 alike.
  • Refused: an f64 @log2 or @log10.

Specs

specs/tri/t27b/conformance/libm_logf.t27 (new) brings the ports in with use tri::t27b::libm;.

  • Sweeps. Each port against Zig's builtin, bit for bit:
    • every exponent of both signs, with the infinities and NaNs (5990 points);
    • 0.5 to 2, densely, and across the reduction's sqrt(2)/2 and sqrt(2) bands (3128 points);
    • the subnormals (3000 points).
  • Pinned values: the reference's bits at 2, 10, 0.7, 3, 8, 0.001, 1e-40 and the largest f32, and the special values.
spec t27c test-report t27b --check (aarch64, qemu)
conformance/libm_logf.t27 (new) 6/6, 0 vacuous 6/6, 71 runtime asserts
libm_plan.t27 9/9, 0 vacuous 9/9
libm.t27 18/18, 0 vacuous, 2 invariants proved 18/18, 90 runtime asserts
specs/ml/loss/kl_divergence.t27 4/4 4/4, 5 runtime asserts, 1 invariant held

All three t27b specs are sealed (seal --save, then --verify: all hashes MATCH).

Mutants

Each mutant ran on a copy, under both t27c test-report and t27b (qemu).

mutants of count killed by the reference killed by t27b
the three ports: each constant one ulp up (20), and the algorithm (13) 33 30 30
the new libm_plan.t27 rows 4 4 4

The first run killed 20 of the 33. Eleven constants one ulp up survived, as did logf of zero giving +inf and log10f's hi mask.

A Zig probe on the t27c lab then searched for points where each of those mutants changes a result. It scanned every 17th positive f32 (125 million points), and every positive finite f32 for Lg3 and Lg4. The new test log_family_agrees_where_one_ulp_of_a_constant_shows asks those points, and log_family_at_zero_infinity_and_nan asks the zeros. The rerun killed 10 of the 13.

The three survivors are equivalent. Each is Lg4 one ulp up, in logf, log2f and log10f: the search of every positive finite f32 found no result that it changes.

Glue mutant, run as cargo test --release -p t27b --test tail on the t27c lab: an assignment that gives @bitCast no result type. 1 of 1 killed.

Lines (git diff --numstat --no-renames origin/master...HEAD)

file kind added deleted
cli/t27b/src/lower.rs hand-written glue 1 1
cli/t27b/tests/tail.rs hand-written test 14 4
gen/rust/tri/t27b/libm_plan.rs t27c gen-rust, not hand-edited 23 16
specs/tri/t27b/conformance/libm_logf.t27 conformance spec, 6 tests 154 0
specs/tri/t27b/libm.t27 3 routines 126 2
specs/tri/t27b/libm_plan.t27 2 builtins, the f32 @log 53 41
.trinity/seals/*.json (3) t27c seal --save (t27c 0.5.1) 32 12
docs/reports/t27b_expectations.json ledger 6 5
AGENTS.md t27b remainder line 4 1

Hand-written foreign code: 15 added lines (1 in lower.rs, 14 in tests/tail.rs). That is under the #7371 cap.

wc -l, in AGENTS.md (measured on master 2dfe978 and on this branch): cli/t27b/src/*.rs stays at 15271, and cli/t27b/tests/*.rs goes from 8191 to 8201.

Gates

On the t27c lab, on this PR's tree:

Ledger

Three rows move:

On master 2dfe978's ledger (which keeps no counts since #7862), pass rows go 965 -> 967, not_pass rows go 30 -> 29, and max_not_pass goes 30 -> 29.

Evidence: signed lane receipts (#7686)

Requested from the t27b lab for this head and its merge base; the comparison follows in a comment.

gen-rust gaps

None new.

🤖 Generated with Claude Code

…loses #7822)

libm.t27 ports compiler_rt's logf, log2f and log10f on the bits; libm_plan.t27 plans @log2 and @log10, and an f32
@log is no longer refused. @bitcast takes its result type from an assignment. The conformance spec holds each
port to Zig's builtin bit for bit; specs/ml/loss/kl_divergence.t27 now passes. Part of #7746.

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

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-08 20:07:13 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)=3c0ade9e73e4 != 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).

AGENTS.md takes master's remainder line and adds this PR's entry, re-measured with wc -l on the merge; the ledger
takes master's rows and this PR's three.

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

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-08 20:45:39 UTC

Summary

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

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

Seal Status

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

AGENTS.md takes master's remainder line and adds this PR's entry, re-measured with wc -l on the merge; the ledger
takes master's rows and this PR's three.

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

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-09 07:22:40 UTC

Summary

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

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

Seal Status

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

AGENTS.md takes master's remainder line and adds this PR's entry, re-measured with wc -l on the merge; the ledger
takes master's rows and this PR's three.

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

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-09 08:40:01 UTC

Summary

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

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

Seal Status

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

@gHashTag
gHashTag merged commit fe9abb3 into master Oct 9, 2026
32 of 33 checks passed
@gHashTag
gHashTag deleted the t27b/gf16-logf branch October 9, 2026 08:49
gHashTag pushed a commit that referenced this pull request Oct 9, 2026
AGENTS.md takes master's and adds this branch's step: 15274 plus 1239 and
8232, on master 12ee225's 15271 plus 1239 and 8215. The ledger merges cleanly;
max_not_pass recomputed from the entries: 27.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gHashTag pushed a commit that referenced this pull request Oct 9, 2026
From master's side (#7918's f32 @log ports, and others). docs/reports/t27b_expectations.json:
master's ledger plus this branch's four rows, recomposed: max_not_pass 28 -> 26.
AGENTS.md: this branch's clause re-measured with `wc -l` over master
12ee225: src/*.rs 15271 -> 15285, src/*/*.rs 1239 -> 1270, tests/*.rs
8215 -> 8232.

Merged-tree checks on the t27c lab: cargo test --release -p t27b 135
passed, 0 failed; under `t27b test --check` tuple_local_index.t27,
tuple_local_plan.t27, ternary_gates.t27 and ultra_engine_v70_ultimate.t27
pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gHashTag added a commit that referenced this pull request Oct 9, 2026
…tion row

Ledger docs/reports/t27b_expectations.json recomputed, not picked:
master (#7918) moved kl_divergence to pass, moved gf16's blocker to
ExprCall(std.*) and added conformance/libm_logf.t27 (pass). The textual
merge was clean but kept max_not_pass 28 while only 27 rows were
non-passing.

specs/ml/recurrent/self_attention.t27 is put back as blocked
StmtAssign(undeclared), reason unimplemented. The row is held only because
the spec's reference result is host-dependent (#8051: an undefined slice
from the undeclared default_input()): the GitHub runner's reference passes
it, the Railway lab's fails it, so lab run 6b6386e left it out and
t27b-native-ratchet reported UNLISTED. The row goes away when #8051 fixes
the spec.

Result: 1220 rows, 1220 unique, sorted, every path exists; pass 1060,
pass_vacuous 132, non-pass 28, max_not_pass 28 (27 + self_attention).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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: f32 @log, @log2 and @log10 from libm.t27 (compiler_rt logf, log2f, log10f)

2 participants