PyTorch 2.0 introduced torch.compile to bring compilation benefits to Python-first ML. MIND takes a fundamentally different approach: a purpose-built language with a direct compilation pipeline. This document compares the two architectures and explains why the design differences matter.
The fundamental difference: PyTorch must discover the computation graph by running Python. MIND declares it in source code. Discovery is inherently more expensive than declaration.
Pipeline Overview
PyTorch 2.0 Pipeline
- 01Python SourceDynamic Python code with tensor ops
- 02TorchDynamoCPython bytecode interception via PEP 523
- 03FX GraphTraced computation graph (may fail on dynamic control flow)
- 04ATen / Prim IR~2,000+ operators decomposed to primitives
- 05TorchInductorLoop-level IR generation (Triton for GPU, C++ for CPU)
- 06Triton / CUDAJIT-compiled GPU kernels
6 stages · JIT compilation · Python runtime required · 99–878 ms cold start
MIND Pipeline
- 01MIND SourceTensor-native syntax with static types and shapes
- 02ASTHand-written recursive descent parser (zero allocations)
- 03Typed ASTFull type + shape inference, all errors caught here
- 04MIND IR (SSA)17 Core v1 ops in static single assignment form
- 05Backend: MLIR → LLVM (default) or native (opt-in)--backend mlir carries floats, tensors and specialty targets via a pluggable backend trait; --backend native is pure MIND emitting ELF, Mach-O and PE/COFF directly, determinism by construction, for the integer and control-flow subset
- 06Native binaryAOT native code: clang-linked on the MLIR path, or a static ELF, Mach-O or PE/COFF image from the native backend (the self-host path)
6 stages · AOT compilation · No runtime dependency · 1.8–15.5 µs total
Scope note
MIND benchmarks measure frontend compilation (parse → typecheck → IR generation). PyTorch times measure torch.compile cold-start (TorchDynamo + TorchInductor + Triton codegen). These are different scopes of work: MIND’s pipeline is narrower by design, which is the architectural point.
The backend flag, as the compiler describes it (captured)
$ mindc build --help
--backend <BACKEND>
Code-generation backend: mlir (default) | native.
`mlir` drives the production MLIR-text → mlir-opt/clang pipeline. `native` (RI-D Option A) bridges the build to the pure-MIND native compiler for a runnable ELF, Mach-O or PE/COFF binary with zero MLIR/LLVM/clang; fail-closed on any construct the pure-MIND subset cannot lower (never a silent MLIR fallback). The default `mlir` build is unaffected.1. Frontend: Direct Parse vs Bytecode Interception
PyTorch: TorchDynamo
TorchDynamo intercepts CPython bytecode at runtime using PEP 523 frame evaluation hooks. It “sniffs” Python execution, captures tensor operations into an FX graph, and falls back to the Python interpreter for unsupported patterns (“graph breaks”).
- Must handle arbitrary Python: closures, exceptions, generators, metaclasses
- Graph breaks fragment compilation into multiple subgraphs
- Guard system re-validates assumptions on every call
- Tracing overhead proportional to Python complexity
MIND: Recursive Descent Parser
MIND has a hand-written recursive descent parser that directly reads source code into an AST. No tracing, no bytecode interception, no Python runtime. The parser is a single-pass, zero-allocation Rust function.
- Deterministic: same source always produces same AST
- No graph breaks: the entire program is always compiled
- No guard overhead: types are statically known
- Parser throughput: ~338,000 compilations/sec
2. Type and Shape System
PyTorch: Runtime Shape Discovery
PyTorch tensors carry shape and dtype information at runtime. TorchDynamo captures these as “guards”: runtime assertions that the shapes haven’t changed since tracing. If a guard fails, the entire graph is re-traced and re-compiled.
# PyTorch: shapes discovered at runtime
x = torch.randn(batch, 784)
y = model(x) # shape checked at runtime
# RuntimeError: shape mismatch
# (only discovered during execution)MIND: Compile-Time Shape Resolution
MIND encodes tensor shapes directly in the type system. The type checker resolves all shapes at compile time using a shape algebra that supports broadcasting, dimension propagation, and reduction inference. Shape mismatches are compile errors.
// MIND: shapes verified at compile time
let x: Tensor<[batch, 784], f32> = input;
let y = matmul(x, w); // shape checked now
// E2102: shape mismatch
// (caught before any code runs)Compile-time shape checking eliminates an entire category of production failures. In PyTorch, a shape mismatch in an inference path that only triggers on certain inputs can reach production. In MIND, it cannot compile.
3. Intermediate Representation
PyTorch: ATen + Prim IR
PyTorch’s FX graph uses ATen operators (~2,000+) that must be decomposed into a smaller Prim IR for optimization. The decomposition is non-trivial: each ATen op may expand to dozens of Prim ops. This large surface area makes optimization harder and slower.
MIND: Purpose-Built SSA IR
MIND IR is a minimal, purpose-built static single assignment (SSA) form with a Core v1 operator surface of exactly 17 operations. Every operation has precise, formally specified semantics. The small surface area makes optimization fast, verification tractable, and the entire IR auditable.
The ratio matters: optimizing across 17 operations is a tractable problem. Optimizing across 2,000+ operators requires heuristics, decomposition passes, and significant compile-time overhead. MIND’s minimal IR is why compilation takes microseconds, not seconds.
4. Lowering Path
PyTorch: TorchInductor + Triton
TorchInductor generates loop-level IR from the FX graph, then emits Triton kernels for GPU or OpenMP C++ for CPU. Triton itself runs another compilation pass (Triton → LLVM IR → PTX). The result: two full compilation pipelines stacked on top of each other.
- FX Graph
- TorchInductor loop IR
- Triton source
- Triton source
- Triton IR
- LLVM IR
- PTX
- Two independent optimization phases
- Cache invalidation across both layers
MIND: MLIR → LLVM (default) + native (opt-in)
MIND IR (the IRModule data shape, see /docs/ir) has two backend paths. The default mindc build path (--backend mlir) lowers through MLIR to LLVM; it carries floats, tensors and specialty targets via a pluggable backend trait, with commercial backends in the private mind-runtime implementing that trait. The opt-in normative self-host path (--backend native) emits native x86-64/ELF directly from the MIND IR for the integer and control-flow subset: determinism by construction (the native ELF is a pure function of the IR), with no MLIR or LLVM dependency in the self-host loop. Two canonical serialisations of the same IR shape: mic@1 text, mic@3 binary (RFC 0021).
- MIND IR → MLIR linalg/tensor/arith → LLVM (default
--backend mlir) - MIND IR → native ELF / Mach-O / PE/COFF on x86-64 and ARM64 (opt-in
--backend native, the normative self-host path) - Pluggable backend trait for exotic targets (GPU, TPU, FPGA)
- Evidence-chain attestation (RFC 0016) anchored on the canonical
mic@3trace hash
PyTorch’s two-layer compilation (TorchInductor + Triton) exists because it must bridge from Python semantics to GPU kernels incrementally. MIND’s direct path exists because the source language was designed for compilation from the start, with the native-ELF backend closing the self-host fixed point byte-for-byte.
4.1 Accelerator Targets (Roadmap)
Commercial mind-runtime roadmapUnder active development
The compiler architecture supports multiple accelerator targets through a pluggable backend trait, with each target class assigned a dedicated dialect namespace (mind.<target>.*) for the MLIR interchange path. The normative self-host target is the native-ELF backend. Additional vendor targets listed below are under active development in the commercial mind-runtime roadmap and will be announced when stable.
| Target | Dialect | Vendor SDK |
|---|---|---|
| cuda | mind.cuda.* | cuBLASLt, cuDNN, NCCL |
| rocm | mind.rocm.* | rocBLAS |
| metal | mind.metal.* | MPS |
| webgpu / webnn | mind.webgpu.* | WGSL, W3C WebNN |
| tpu | mind.tpu.* | libtpu.so |
| npu | mind.npu.* | CoreML, QNN, OpenVINO |
| lpu | mind.lpu.* | libgroq.so |
| dpu | mind.dpu.* | DOCA Flow, DPDK |
| fpga | mind.fpga.* | XRT, OpenCL FPGA |
| asic | mind.asic.* | XRM-SSD reference |
| cerebras | mind.cerebras.* | CSL, Cerebras Runtime |
| taalas | mind.taalas.* | in-house tape-out card |
| tenstorrent | mind.tt.* | TT-Metalium |
| sambanova | mind.rdu.* | SambaFlow |
| ipu | mind.ipu.* | Poplar, PopART |
| gaudi | mind.gaudi.* | SynapseAI |
5. Automatic Differentiation
PyTorch: runtime tape
iteration 1
iteration 2
iteration 3
MIND: compile-time transform
compile
gradient generated once
iteration 1
run gradient code
iteration 2
run gradient code
iteration 3
run gradient code
PyTorch: Runtime Tape (Autograd)
PyTorch records a computation graph (the “tape”) during the forward pass. On .backward(), it replays the tape in reverse to compute gradients. This recording happens on every forward pass, every iteration, every batch.
- Tape recorded per-iteration (memory + time overhead)
- Graph nodes allocated on heap during forward pass
- Gradient computation interleaved with Python GC
- torch.compile partially addresses this via AOTAutograd
MIND: Compile-Time Autodiff
MIND performs automatic differentiation as a compiler transform on the IR. The gradient function is generated once at compile time and emitted as native code. This avoids a runtime tape for the supported transform. Executing the generated gradient still consumes time and memory; runtime wiring and whole-model performance need separate validation.
- Gradient code generated once, compiled to native binary
- No tape-construction overhead for the supported compile-time transform
- Compile-time optimization of the gradient graph
- ~38 µs generation cost in the reported compiler microbenchmark, amortized over repeated calls
Reusing a generated gradient can amortize compilation over repeated calls. The compiler microbenchmark does not establish a speedup for a complete training run; compare full workloads against both eager and compiled framework execution.
6. Determinism
PyTorch: Configurable Determinism
torch.use_deterministic_algorithms(True) selects deterministic alternatives where available and rejects known nondeterministic operations without an alternative. PyTorch does not guarantee identical results across releases and platforms. See its reproducibility documentation.
- Deterministic alternatives may have a performance cost
- Seeds, library configuration, platform, and release affect reproducibility
- Graph specialization is not itself evidence of nondeterministic output
- Benchmark the chosen deterministic configuration on the same workload
MIND: Gated Bit Identity
MIND ensures deterministic compilation via structural properties (no tracing, no runtime-dependent graph construction). The keystone compiler and --no-default-features builds achieve bit-identical output, verified via SHA-256 hashing across 40 compilation runs with 4 test programs.
- SHA-256 verified: identical output across 40 runs on reference platform (keystone and --no-default-features builds)
- No execution-dependent graph construction
- Optimizations must preserve the admitted arithmetic contract
- Enables audit trails for regulated industries
Determinism is not a feature flag in MIND: it’s a structural property of the compiler architecture. Because there is no tracing and no runtime-dependent graph construction, the output is deterministic by construction, not by enforcement.
Measured Performance Impact
These architectural differences produce measurable results. All numbers from verified benchmarks on the same reference platform (Ubuntu 24.04, a commodity x86 CPU, Ampere-class GPU, CUDA 12.8):
- Compilation (scalar_math)56,000×1.77 µs99 ms
- Compilation (conv2d)176,000×~5 µs878 ms
- Compilation (large network)48,500×15.5 µs752 ms
| Metric | MIND | PyTorch 2.10 | Ratio |
|---|---|---|---|
| Compilation (scalar_math) | 1.77 µs | 99 ms | 56,000× |
| Compilation (conv2d) | ~5 µs | 878 ms | 176,000× |
| Compilation (large network) | 15.5 µs | 752 ms | 48,500× |
| Determinism | Bit-identical (SHA-256, 40/40 runs) | Not guaranteed | — |
| Autodiff overhead | 0 (compiled) | Per-iteration tape | — |
| IR surface area | 19 ops | ~2,000+ ops | 105× smaller |
Methodology
MIND compilation measured with Criterion.rs (100 samples, 95% CI, in-process). PyTorch measured as torch.compile cold-start on GPU (Ampere-class GPU, CUDA 12.8). See Performance and Running Benchmarks for full methodology and reproduction instructions.
Why This Matters
For Development
Microsecond compilation means instant feedback. Change a model definition, recompile in 2 µs, catch shape errors before running any data. No waiting for torch.compile to warm up.
For Production
Bit-identical builds enable audit trails. Compile-time autodiff eliminates per-request overhead. No Python runtime in the deployment artifact. The binary is the deployment.
For CI/CD
At 338,000 compilations/sec, the entire test suite compiles in milliseconds. Shape errors become CI failures, not production incidents. Deterministic builds mean reproducible pipelines.
The Rust Analogy
Rust didn’t make CPUs faster. It made everything around CPU execution safer and faster: memory management, concurrency, build systems, deployment. The CPU instructions themselves are the same.
MIND follows the same pattern. The GPU kernels hit the same silicon: on the GPU path (which ships in the commercial mind-runtime), MIND calls into the same vendor kernels PyTorch does, so the kernels themselves are at hardware parity. What MIND eliminates is everything around the kernel execution:
| Around the kernel | MIND | vs |
|---|---|---|
| Compilation overhead: | microseconds | seconds |
| Shape validation: | compile time | runtime crashes |
| Autodiff cost: | zero per-iteration | tape per-iteration |
| Deployment artifact: | native binary | Python + CUDA runtime |
| Build reproducibility: | guaranteed | best-effort |
The result is a system where the total cost of running ML models is dominated by the actual computation, not the framework overhead.
Explore the Pipeline
Dive deeper into MIND’s compiler internals, run the benchmarks yourself, or see how the comparison plays out across frameworks.