Skip to content

Codex/release 0.4.0 validation - #12

Merged
tragisch merged 18 commits into
masterfrom
codex/release-0.4.0-validation
Oct 17, 2026
Merged

tragisch merged 18 commits into
masterfrom
codex/release-0.4.0-validation

Conversation

@tragisch

Copy link
Copy Markdown
Owner

No description provided.

tragisch and others added 18 commits October 10, 2026 09:44
Keep Unity runner CLI flags aligned with its linked library so Bazel tests run.
//doc:requirements.txt needs a BUILD file in doc/, which would turn doc/
into a package and break the glob in the root BUILD. Referencing the file
through the root package fixes bazel build //:docs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add st_binary_broadcast and st_binary_broadcast_into implementing nm_lib's
run_binary semantics: NumPy broadcasting over any axes, fast paths for
equal shapes, scalars, and shape suffixes, and a strided walk with
vectorized row kernels. bf16 operands promote to f32; a bf16 output is
rounded back. Division is IEEE-exact: vDSP_vdiv differs by 1 ulp and
-ffast-math rewrites division by an invariant scalar into a rounded
reciprocal, so the scalar path uses a precise-mode helper. OpenMP starts
only above 2M output elements; bench_st_binary's sweep shows regressions
below that on this 4-core machine. Bit-exact tests cover broadcast shape
cases, sizes, error paths, thread-count determinism, and bf16 promote.
Add st_layernorm (nm_lib run_layernorm semantics: sum8 mean and variance
with eight deterministic partial sums, optional gamma/beta, in-place safe,
bit-identical across thread counts) and st_reduce_max/_into (axes-mask
reduction with keepdims). Reduce-max propagates the first NaN in scan
order instead of silently dropping it, documented in the header; trailing
masks fold vectorized contiguous runs, non-trailing masks walk like the
reference plus one vectorized NaN pre-scan. The max fold avoids OpenMP
reduction(max:) and compiler padding lanes, which under -ffinite-math-only
substitute -FLT_MAX and swallow -INFINITY inputs; the eight-lane combine
runs in a noinline helper so all lanes come from memory. Thread thresholds
are backed by bench_st_norm_reduce (layernorm 262k, reduce 1M elements).
Add st_matmul_batched implementing nm_lib's run_matmul semantics: rank 2
to 4 operands, NumPy broadcast over the leading batch axes, and the
single-matrix fast path that stacks a's batches into one GEMM. Every
product goes through the sm_gemm backend (Accelerate/OpenBLAS, MPS via
the runtime backend). Batch GEMMs are distributed over OpenMP only for
at least 8 batches of at most 262144 elements so BLAS threads are never
oversubscribed; the benchmark measures this neutral on Accelerate, which
serializes small GEMMs. bf16 operands promote to f32, and results follow
the backend accumulation order, so tests use a 1e-4 relative tolerance
including across thread counts.
Add st_gather/st_gather_raw (int64 indices, negative indices count from
the end, indices validated before any copy so out-of-range fails without
partial output, contiguous block memcpy, raw variant with an element-size
parameter for nm_lib's int64 and bool buffers) and
st_permute_copy_into/_bytes, the materializing transpose nm_lib needs for
pooled output buffers; st_permute alone only creates views. The strided
permute rows use typed 4/8-byte loops like the reference walk_copy, and
the gather stays sequential below 4M copied elements after a measured 2x
regression at 1M. The migration map now records run_concat as covered by
st_concat and run_slice as not covered (st_split only does equal splits).
Add st_f32_to_f16/st_f16_to_f32 and the bulk variants, reproducing
nm_lib's nm_halfprec.h bit for bit: round-to-nearest-even, exact
subnormals, overflow to infinity, quiet NaN with sign preserved, sign of
+/-0 kept. The bulk NEON path blends the reference NaN pattern into NaN
lanes because FCVT keeps the payload; tests sweep all 65536 f16 patterns
in both directions, a strided sample of the f32 pattern space, the
conversion-critical exponent range, an edge table, and bulk lengths 0
to 33. Conversion stays a uint16_t buffer API; no StDtype entry was
added. The bulk kernels measure 10-16x over the per-element reference
loop.
Review follow-ups on the interpreter kernels:

- Unify the raw-buffer suffix: st_gather_raw is now st_gather_bytes,
  matching st_permute_copy_into_bytes (both take an element-size
  parameter).
- Document and test the aliasing policy: write-in kernels reject views,
  st_binary_broadcast_into may alias an output with a same-shaped operand
  (element-wise in-place, e.g. x += bias, covered for the same-shape,
  suffix, and walk paths), st_layernorm keeps its in-place guarantee,
  and every other output must not overlap its inputs. Headers state the
  rules per function.
- The new test suites run clean under ASan/UBSan; the sanitizer pass
  caught a buffer overrun in the new in-place test itself and a fragile
  LayerNorm comparison. The LayerNorm check now scales its tolerance
  with the reference's intermediate magnitude, because -ffast-math
  rounding of the apply chain differs between the library and the test
  reference and result-relative tolerances blow up on outputs where the
  scaled value cancels against beta.
- f16 bulk coverage now converts f32 values around every subnormal half
  (including rounding boundaries) and round-trips all 65536 patterns
  through both bulk kernels, proving flush-to-zero does not occur.
The contiguity contract is now tested for every write-in kernel;
st_permute_copy_into was the only one without a non-contiguous input
and output rejection case.
@tragisch
tragisch merged commit 5ffce6f into master Oct 17, 2026
2 checks passed
@tragisch
tragisch deleted the codex/release-0.4.0-validation branch October 17, 2026 10:11
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.

1 participant