SFEP-0052
Accelerated ML — Substrate Interop and Capability-Typed Accelerator Programming
- Status
- Accepted
- Type
- informational
- Created
- Updated
- Author
- agent:orchestrator (Sailbot); human review
SFEP-0052 — Accelerated ML: Substrate Interop and Capability-Typed Accelerator Programming
Strategy umbrella. This SFEP fixes a direction and an architecture spine; each numbered track below graduates into its own runtime/language/tooling SFEP before implementation. It is deliberately not a single-PR design.
1. Summary
Sailfin should enter the modern AI-compiler arena, but not by reimplementing XLA. This SFEP commits Sailfin to a two-track architecture:
-
Track A — reuse the substrate (interop-first backend). Add a shape-typed tensor IR above the scalar
native_ir, and lower it to an existing, battle-hardened accelerator substrate — StableHLO/MLIR and/or vendor libraries (cuBLAS, cuDNN, NCCL, and Triton-generated kernels) through a typed FFI — rather than hand-authoring tensor-core codegen and autotuning from scratch. This buys competitive FLOPS for a fraction of the engineering surface and keeps Sailfin inside the ecosystem where models are actually trained. -
Track B — the defensible wedge (capability-typed accelerators). Extend Sailfin’s three pillars — effects, capabilities, structured concurrency — end-to-end through the tensor graph, the device, and the collective. Make
![gpu]and![model]enforced; makePII<T>/Secret<T>taint provably bounded through a training/inference graph; make device and multi-node orchestration a structured-concurrency nursery with no orphaned kernels; and make a produced model artifact carry a capability-sealed record (SFEP-0016) of everything it touched. No incumbent — Mojo, Triton, JAX/XLA, Bend — offers a type system that reaches through the accelerator. That is the novel, timeless surface Sailfin can own.
Track A is how we become fast. Track B is why anyone switches.
2. Motivation
2.1 The market and the honest gap
Mojo (MLIR-based systems+kernel language), Triton (Python-embedded GPU kernel
DSL), JAX (composable grad/vmap/jit transforms), and XLA/StableHLO (the
tensor compiler underneath) do not compete on syntax. They compete as array
compilers with three capabilities Sailfin has zero of today: a shape-aware
tensor IR that fuses and tiles, accelerator codegen (GPU/TPU), and automatic
differentiation. A 2026-07 survey of the tree confirms the starting line:
- Backend emits CPU only — host default triple plus one Windows MSVC
cross-triple (
compiler/src/build/target.sfn:55). No NVPTX/AMDGPU/SPIR-V anywhere incompiler/src/llvm/lowering/oremit_native.sfn. native_ir.sfnis scalar-only — no vector/tensor types, no fusion pass.- Floats are f32/f64 only (
typecheck_types.sfn:1747). No bf16/fp16/fp8/tf32 — the numeric substrate of modern training is absent. ![gpu]/![model]are inert taxonomy strings — parsed, reserved, zero detectors (effect_checker.sfnhas no gpu/model logic;effect_taxonomy.sfn:29).- No autodiff of any kind.
nn/tensor/layers/lossescapsules are real but CPU scalar-loop, forward-pass only —matmulis a naive triple-nested O(n³) loop overfloat[](capsules/sfn/tensor/src/mod.sfn:224); no BLAS, SIMD, or backward pass.nn’s own header states GPU dispatch and training are “planned.”
2.2 Why the old cost priors do not bind us
The reflex objection is “XLA took a decade and hundreds of engineers.” That prior is measuring the pre-agentic cost of the labor-bound work: backend plumbing, op-coverage breadth, lowering boilerplate, and the enormous test surface. A disciplined agentic engineering pipeline compresses exactly that class of work by a large factor — it is mechanical, spec-drivable, and verifiable. What it does not compress is (a) picking the right architecture and (b) the correctness bar: a miscompiled gradient is still a miscompiled gradient, and a capability type-system hole is still a hole. So the binding constraints shift from headcount and time to design judgment and verification rigor — which is a level playing field, and one where a small team with a coherent thesis can now credibly ship what previously required an org. This SFEP is written in that posture: ambitious on scope, uncompromising on correctness, and deliberately architecture-first so the compressible work stays compressible.
2.3 Why now, and why this is on-brand rather than a dilution
CLAUDE.md warns against diluting the three pillars with half-finished AI
features and against chasing 6-month-half-life API wrappers. Track B honors that
warning by construction: it is not an AI-syntax land-grab, it is the existing
pillars pointed at ML. And a key foundation is in place — SFEP-0038 (generic
constraints + monomorphization) is Implemented for pointer-width T
(int/float/bool/string/ptr and boxed struct references), which is enough to begin
a typed Tensor<T, [dims]> surface over existing scalar dtypes. Two generics
follow-ons remain and are on the critical path here — by-value aggregate T
layout and generic collections (draft-generic-collections) — but the
constraint/monomorphization machinery itself is no longer the blocker. This is the
moment the rest becomes buildable.
3. Design
The architecture spine is a new tensor IR tier inserted between typecheck and
the existing scalar native_ir, with two lowering exits (Track A) and a
type-system extension that spans it (Track B).
AST → typecheck(+effects, +low-precision floats) → Tensor IR (shape-typed) ──┬─▶ StableHLO / MLIR ─▶ XLA/vendor runtime (Track A, primary) [fusion, autodiff] ├─▶ vendor-FFI kernels (cuBLAS/cuDNN/NCCL, (Track A, pragmatic) │ Triton-emitted PTX) via typed extern └─▶ scalar native_ir ─▶ LLVM ─▶ CPU (reference / self-host, exists today)3.1 Track A — the interop backend (become fast without rebuilding XLA)
- Numeric substrate. Add real
bf16,f16,fp8(e4m3/e5m2), andtf32to the type system, lowering, and runtime, with explicit mixed-precision accumulation rules. (Own SFEP; extends the sized-int/float work.) - Shape-typed Tensor IR. A tier above
native_ircarrying dtype + static (and later dynamic) shape, elementwise/reduction/contraction/broadcast ops, and layout. This is the only place a fusion pass can live — unfused scalar loops are 10–100× off, which is the entire reason XLA/Triton exist. - Substrate lowering. Emit StableHLO (portable, versioned) as the primary exit so we inherit XLA’s fusion/tiling/layout and its CPU/GPU/TPU backends; provide a vendor-FFI exit (typed extern bindings to cuBLAS/cuDNN/NCCL and Triton-emitted kernels) for hot paths and for deployments that can’t take an XLA dependency.
- Autodiff. Reverse-mode AD as a transform over the Tensor IR (JAX/Enzyme shaped), composing with fusion. Training needs this; it must be an IR pass, not a runtime tape, to stay fast.
- Distribution. Collectives (all-reduce/all-gather/reduce-scatter) and sharding annotations, lowered to NCCL/RCCL or StableHLO’s collective ops.
// Illustrative Track-A surface (typed tensors on the generics that already shipped)fn attention(q: Tensor<bf16, [B, H, S, D]>, k: Tensor<bf16, [B, H, S, D]>, v: Tensor<bf16, [B, H, S, D]>) -> Tensor<bf16, [B, H, S, D]> ![gpu] { let scores = matmul(q, transpose(k)) |> scale(1.0 / sqrt(D as float)); return matmul(softmax(scores), v); // lowers to StableHLO; XLA fuses the chain}3.2 Track B — capability-typed accelerators (why anyone switches)
Track B is the differentiator, and each piece is a real enforcement upgrade of a pillar that is currently inert for ML:
![gpu]/![model]become enforced. Wire detectors ineffect_checker.sfnso any tensor op that dispatches to a device requires![gpu], and any model-engine call requires![model]— with spans and fix-its, exactly like the shippedio/netdetectors. “Reserved string” → real capability gate.- Taint that reaches through the graph.
PII<T>/Secret<T>(today parsed-only) become enforced along tensor dataflow: a kernel or collective that would move tainted data off-device, into a log, or across a![net]boundary fails to compile. This is confidential-compute and data-governance as a type error, which no incumbent offers. - Structured concurrency over devices and nodes. Extend the
routine {}nursery (pillar 3) to GPU streams and multi-node ranks: join-all semantics, no orphaned kernels, cancel-on-fault across a collective. Distributed training as a structured-concurrency program rather than a pile of async callbacks. - Capability-sealed model artifacts. A produced model carries a sealed record (SFEP-0016) of the effects/capabilities it exercised — an auditable, supply-chain-verifiable provenance manifest for the trained artifact.
// Illustrative Track-B guarantee: taint is bounded through the acceleratorfn train_step(batch: PII<Tensor<bf16, [B, D]>>, w: Tensor<bf16, [D, D]>) -> Tensor<bf16, [D, D]> ![gpu, model] { let logits = matmul(declassify_for_training(batch), w); // explicit, audited // print.info(batch) // ← would be E-taint: PII may not cross ![io] return grad(loss)(w);}3.3 Sequencing (each is a child SFEP, gated independently)
bf16/fp8 numerics → Tensor IR + fusion → StableHLO exit (+ vendor-FFI exit)
→ enforced ![gpu]/![model] → autodiff → taint-through-graph → collectives + device nurseries → sealed artifacts. The numeric and Tensor-IR tracks unblock
everything; enforcement (Track B) can proceed in parallel with autodiff once the
Tensor IR exists.
4. Effect & capability impact
This is the center of gravity, not an afterthought:
- New enforcement, not new effects.
gpuandmodelstay in the canonical six (effect_taxonomy.sfn); this SFEP makes them checked. Effect lists stay alphabetical (![gpu, model, net]). - Taint enforcement extends to tensor dataflow.
PII<T>/Secret<T>gain real propagation and barrier diagnostics along the Tensor IR, with an explicit, auditeddeclassify_*escape. New E-codes to be allocated from an unused range at child-SFEP time (grep the range first, percode-style.md). - Capability manifests gain a device/collective axis. A capsule’s
capabilitiesmay scope which devices/collectives it may touch, enforced at the workspace envelope (SFEP-0051). - Self-host invariant is untouched by design (see §5).
5. Self-hosting impact
Passes touched (across child SFEPs): typecheck_types.sfn (low-precision
floats), a new Tensor IR module + fusion/autodiff passes, effect_checker.sfn
(gpu/model/taint detectors), and new lowering exits (StableHLO emitter +
vendor-FFI). Crucially, self-hosting is not at risk: the Sailfin compiler is not
a tensor program. The accelerator path exists for user code; the compiler
continues to compile itself through the existing scalar native_ir → LLVM → CPU
route. make compile remains the gate and does not require a GPU. Track A’s
substrate dependency (XLA/vendor libs) is a runtime dependency of compiled ML
programs, never of the bootstrap — preserving bootstrap.toml/seed discipline and
the SFEP-0015 toolchain-independence trajectory for the compiler itself.
6. Alternatives considered
- Full from-scratch tensor compiler (the “beat XLA” path). Rejected as the
primary path: it re-opens tensor-core codegen and autotuning every hardware
generation and is the exact dilution
CLAUDE.mdwarns against. Track A’s vendor-FFI exit keeps a narrow native-kernel option for hot paths without betting the strategy on it. - MLIR-native middle-end (Mojo’s bet) instead of StableHLO emit. Deferred, not rejected — a heavier substrate coupling; StableHLO gives portability with a smaller surface first, and an MLIR exit can be added later.
- Do nothing — keep AI a pure post-1.0 library concern. Honest and charter-compliant, but forfeits the one ML surface (capability-typed accelerators) that is uniquely Sailfin’s and timeless. Track B is the reason to act now rather than later.
- Runtime-tape autodiff (PyTorch eager style). Rejected for the compiled path: it doesn’t compose with fusion and leaves performance on the table; IR-level AD is the correct altitude.
7. Stage1 readiness mapping
This is a strategy umbrella; readiness is tracked per child SFEP, not here. As of this draft, the whole slate is pre-implementation:
- Parses — (typed-tensor surface builds on shipped generics, SFEP-0038)
- Type-checks / effect-checks — new floats, enforced
![gpu]/![model], taint - Emits valid
.sfn-asm— Tensor IR tier + scalar reference path - Lowers to LLVM IR / StableHLO / vendor-FFI
- Regression coverage — see §8
- Self-hosts — preserved by construction (§5); compiler stays CPU
-
sfn fmt --checkclean - Documented in
docs/status.md+ spec/preview
8. Test plan
Per child SFEP, but the shape: numeric-precision unit tests (bf16/fp8 round-trip,
mixed-precision accumulation); Tensor IR + fusion snapshot tests
(expect_snapshot); effect-enforcement negatives (assert_does_not_compile that
a device op without ![gpu] and a PII<T> crossing ![io] are rejected with the
right E-codes); autodiff correctness against finite-difference references; a
StableHLO golden-emit e2e; and a CPU-reference numerical-equivalence e2e so the
scalar path stays a trustworthy oracle. All native *_test.sfn (no bash e2e).
9. References
- Survey ground truth (2026-07-19):
compiler/src/build/target.sfn:55,compiler/src/native_ir.sfn,compiler/src/typecheck_types.sfn:1747,compiler/src/effect_taxonomy.sfn:29,compiler/src/effect_checker.sfn,capsules/sfn/{tensor,nn,layers,losses}/src/mod.sfn,docs/status.md. - SFEP-0038 — Generic Constraints and Monomorphization (
Implemented; the unblocking foundation for typed tensors). - SFEP-0024 — Model Engines, Adapters, Tensors, Training (
Draft; the library surface this backend serves). - SFEP-0016 — The Capability-Sealed Runtime (sealed model artifacts).
- SFEP-0015 — Toolchain Independence (compiler-side backend trajectory; Track A’s substrate dependency is runtime-only, not bootstrap).
- SFEP-0051 — Workspace Manifest / capability envelope (device/collective axis).
CLAUDE.md— three-pillars charter, “libraries over keywords,” “chase timeless problems.”- Prior art: OpenXLA/StableHLO, JAX (
grad/vmap/pjit), Triton, Mojo/MLIR, Enzyme (IR-level autodiff), NCCL/RCCL, GSPMD/shard_map.