An AOT-compiled language for high-performance AI development.
Status: alpha. Phases 1 (Core Language) and 2 (Tensors and MLIR) are complete: the general-purpose language surface and the tensor stack compile and run. Phase 3 (Automatic Differentiation) is open. Breaking changes are expected. Per-phase status lives in one place, the Quick Roadmap.
AI development runs on two languages: an interpreted one to write in, and C++ or CUDA underneath for anything that has to be fast. Crossing that boundary is where performance and type safety are lost. Neuro is one language on both sides of it.
- Native code, no interpreter. Compiled ahead of time through LLVM 20, with no bytecode VM and
no global interpreter lock. On compute-bound programs it lands in the same range as
clang -O2; see Performance. - Shapes checked by the compiler.
Tensor<T, [d0, d1]>carries its dimensions in the type, so a dimension mismatch is a compile error rather than an exception thrown ninety minutes into a training run. - Ownership without a garbage collector. Move-by-default with
val/mut, borrows, and deterministic destruction, so there is no collector pause in the middle of a training step and no shared mutable state to make parallel tensor code unsafe.
The full reasoning, including what Neuro deliberately is not, is in DESIGN.md.
A single perceptron with ReLU activation, using structs, impl blocks, instance methods,
if-expressions and implicit returns. This file compiles and runs today.
struct Neuron {
weight: f64,
bias: f64
}
impl Neuron {
func new(weight: f64, bias: f64) -> Neuron {
Neuron { weight: weight, bias: bias }
}
// ReLU activation: pass-through if positive, clamp to zero otherwise
func activate(&self, input: f64) -> f64 {
val z = (input * self.weight) + self.bias
if z > 0.0 { z } else { 0.0 }
}
func is_active(&self, input: f64) -> bool {
val z = (input * self.weight) + self.bias
z > 0.0
}
}
func main() -> i32 {
val neuron = Neuron::new(0.5, -0.1)
val dead = neuron.activate(0.0) // 0.0 * 0.5 - 0.1 = -0.1 -> clamped to 0.0
val dead_fires = neuron.is_active(0.0)
println("input 0.0 -> {dead:.2} fires: {dead_fires}")
val active = neuron.activate(1.0) // 1.0 * 0.5 - 0.1 = 0.4 -> passes through
val active_fires = neuron.is_active(1.0)
println("input 1.0 -> {active:.2} fires: {active_fires}")
if dead > 0.0 { return 1 }
return (active * 10.0) as i32 // 4
}
input 0.0 -> 0.00 fires: false
input 1.0 -> 0.40 fires: true
More programs, each pinned to its exact exit code and printed output, are in examples/; examples/showcase/ holds the ones that combine several features at once.
| Requirement | Version | Notes |
|---|---|---|
| Rust | 1.85+ | Install via rustup |
| LLVM 20 | 20.x with dev libraries | Per-platform commands below |
| C linker | any | gcc / clang on Linux and macOS, MSVC on Windows |
This is the only step that differs between systems. Put the export in your shell profile
(~/.bashrc, ~/.zshrc) so it survives a new terminal.
# Arch Linux / CachyOS
sudo pacman -S llvm20
export LLVM_SYS_201_PREFIX=/usr/lib/llvm20
# Ubuntu / Debian
wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- 20
export LLVM_SYS_201_PREFIX=/usr/lib/llvm-20
# macOS (Homebrew)
brew install llvm@20
export LLVM_SYS_201_PREFIX="$(brew --prefix llvm@20)"Windows needs the MSVC toolchain and a full LLVM 20 development build: the official installer
ships Clang and LLVM-C.dll but no llvm-config.exe, no headers and no static libraries, so
llvm-sys cannot build against it. The PowerShell walkthrough is in the
installation guide, and
troubleshooting covers the errors that follow from getting it
wrong.
git clone https://github.com/PanzerPeter/Neuro.git
cd Neuro
cargo build --release
cargo test --workspace
cargo install --path compiler/neurc # optional, puts neurc on your PATHThe same four commands run unchanged in PowerShell on Windows.
neurc check examples/basics/hello.nr # type-check only, no binary
neurc run examples/basics/factorial.nr # compile and run, leaving no binary behind
neurc compile examples/basics/factorial.nr # native executable next to the sourceWithout cargo install, prefix each command with cargo run -p neurc --. Flags, --emit obj and
the zero-copy NumPy recipe are in the CLI guide.
Every row is implemented, tested and usable today. Depth lives in the documentation site and docs/; per-release detail is in CHANGELOG.md.
| Feature | Summary |
|---|---|
| Types and inference | i8 through u64, f16 / bf16 / f32 / f64, bool, char, string; literal suffixes, digit separators, as casts, type aliases |
| Control flow | if / elif / else, while, loop, range-for, labelled break / continue, block-as-value, for over any type implementing the prelude's iterator protocol |
| Functions | Recursion, forward references, implicit returns, named arguments with external labels, higher-order functions, |> pipelines, >> composition |
| Generics and traits | Generic functions, structs and impls, const generics, where clauses, turbofish; required and default methods, associated types, operator traits, impl Trait and dyn Trait dispatch. Fully monomorphized |
| Closures | |x: i32| x * x, move closures, (T) -> R function types, compiled to { fn_ptr, env_ptr } with no heap allocation |
| Structs, enums, newtypes | Fields, functional update ..base, impl blocks with &self / &mut self / consuming receivers; unit, tuple and struct-field variants carrying any sized payload; @derive(Copy, Clone, Debug, PartialEq) |
| Pattern matching | Exhaustive match over variant, literal, or, range and wildcard patterns with if guards, plus val-binding destructuring of structs and arrays |
| Arrays, tuples, collections | [T; N], tuples, zero-copy slices &[T] / &mut [T], and heap-backed Vec<T> / HashMap<K, V> / BTreeMap<K, V> / String (reference) |
| Tensors | Tensor<T, [d0, ...]> with shapes checked at compile time: broadcasting, a @ b matmul, slicing, shape generics, named and dynamic axes, reductions, sorting, einsum, .map / .zip / .reduce (reference) |
| Strings | Immutable fat-pointer string with slices, concatenation, codepoint iteration, interpolation "{x:.2}" and triple-quoted blocks; growable String buffer (reference) |
| Errors | Option<T> and Result<T, E> in the implicit prelude as ordinary generic enums; ?? unwraps with a lazy fallback, ? propagates, val-else exits the scope, checked_* arithmetic reports overflow |
| Ownership | Move-by-default, Copy, borrows with flow-sensitive exclusivity, lifetime elision, deterministic Drop, and pool { } arena blocks (reference) |
| Modules | Every .nr file is a module, mod.nr directories nest, inline module { } blocks group; import with renames and re-export facades, private-by-default visibility, implicit prelude (reference) |
| Toolchain | neurc check / run / compile on inkwell 0.10 and LLVM 20, --emit obj for C and NumPy interop, buffered print / println, and a panic / assert runtime with located diagnostics |
Alpha memory note. Stack values, literals, the owning collections and reassigned bindings are all reclaimed, and so is a heap
stringstored into a struct field, an array or tuple element, a call's argument, a call's return value, or a collection slot. What still leaks is the handful of storing positions whose owner the compiler cannot prove, each of which holds one buffer rather than handing out a dangling one. Full detail, and the reason the analysis answers conservatively, is in the memory model.
neurc compile -O 3 hands the module to the same LLVM 20 pipeline clang -O2 uses. The default
is -O 0, checked arithmetic with no optimization, so pass -O 3 before drawing any conclusion
about speed.
Best of nine runs on one machine, lower is better. Reproduce with python benchmarks/run.py,
which builds all three implementations of each program and refuses to report timings if they
disagree on output.
| Benchmark | What it stresses | Neuro -O 3 |
clang -O2 |
Python 3.14 |
|---|---|---|---|---|
mandelbrot |
scalar f64 in a tight loop |
166 ms | 166 ms | 5791 ms |
vector_sum |
Vec push, indexed sweep |
25 ms | 26 ms | 10068 ms |
call_overhead |
recursion, call and inline cost | 45 ms | 51 ms | 1389 ms |
print_lines |
integer holes to standard output | 13 ms | 22 ms | 110 ms |
format_floats |
f64 holes at a fixed precision |
118 ms | 109 ms | 214 ms |
int_divide |
guarded / and %, opaque divisor |
96 ms | 89 ms | 1318 ms |
Absolute times belong to the machine, and the Python column to whichever python3 is on your
PATH. Two rows are worth a word: print_lines beats C because an integer hole renders through a
digit loop instead of snprintf, and int_divide is the one place the compiler spends rather
than saves, since / and % guard the operand pairs the hardware leaves undefined.
Each numbered phase is a MAJOR-version milestone: completing Phase N ships v(N+1).0.0.
| Phase | Goal | Status |
|---|---|---|
| 1 | Core Language: types, control flow, LLVM backend, ownership and borrow checking, generics, traits, closures, enums and pattern matching, error handling, modules | Complete |
| 2 | Tensors and MLIR: first-class tensor types lowered through MLIR Linalg, the pool allocator, and the value model they need | Complete |
| 3 | Automatic differentiation: Enzyme MLIR pass, @grad(wrt: ...), .backward() / .zero_grad(), higher-order derivatives, SGD |
In progress |
| 4 | GPU acceleration: MLIR GPU dialects (nvgpu / rocdl), @gpu, KernelOut<T> aliasing model, device memory pool, CPU fallback |
Planned |
| 5 | Neural network standard library: TrainableTensor, ParameterList, optimizers, @model, Dense / Conv2d / Attention, .nrm serialization |
Planned |
| 6 | Async runtime: async func, Future<T>, spawn, join / race, an executor for data-loader and I/O overlap |
Planned |
| 7 | Interop: Python FFI via DLPack, spread operator, advanced pattern matching, custom attributes, defer |
Planned |
| 8 | Developer experience: debug info, incremental compilation, Language Server Protocol, formatter, @test runner |
Planned |
| 9 | Distribution: the neurpm package manager, cross-OS installer and self-updater, signed binaries, CPU parallelism, further optimization passes |
Planned |
Phase 2 is complete: 2A standard I/O and spec stragglers, 2B tensor core, 2C MLIR
lowering, 2D the pool allocator, 2E the value model and 2F functional sugar — the
|> and >> operators, Einstein notation, and the .map / .zip / .reduce traversals —
all shipped. Phase 3 opens on the binding question its first item names: whether a Rust
process can reach Enzyme's MLIR dialect at all.
Neuro follows Vertical Slice Architecture: code is organized by language feature, not by technical layer.
compiler/
├── infrastructure/ # Shared, zero-business-logic crates
│ ├── ast-types/ # AST node definitions
│ ├── shared-types/ # Primitives shared across slices
│ ├── source-location/ # Spans, positions, source files
│ └── neuro-hir/ # Typed High-Level IR (frontend <-> backend contract)
├── lexical-analysis/ # Tokenizer (logos, Unicode XID)
├── syntax-parsing/ # Pratt + statement parser -> AST
├── semantic-analysis/ # Type checker, scope and borrow analysis
├── hir-lowering/ # Type-checked AST -> typed HIR
├── llvm-backend/ # HIR -> object code (inkwell 0.10 / LLVM 20)
├── mlir-backend/ # HIR -> MLIR linalg (off-by-default `mlir` feature)
└── neurc/ # CLI compiler driver
Today a .nr file travels: tokens → AST → type-checked AST → typed HIR → LLVM object code →
system linker. The tensor path forks after HIR into MLIR (linalg, tensor, func, arith) and will
carry the Enzyme AD pass and the GPU dialects as Phases 3 and 4 land. Stage by stage:
docs/compiler/compilation.md.
| Getting started | Installation, first program, workflow |
| Language reference | One page per feature area, from types to modules |
| CLI guide | Commands, flags, environment variables, interop |
| Compiler internals | Pipeline and one page per slice |
| Editor support | Syntax highlighting for .nr files |
| DESIGN.md | Why the language is shaped this way, and its non-goals |
| CHANGELOG.md | What each release changed |
Everything is published at neuro-lang.netlify.app.
CONTRIBUTING.md has the architecture rules, coding standards, quality gates and
pull request process. Open defects are in docs/BUGS.md, and fixing one is the best
way to start. Work is most useful in Phase 3 (Automatic Differentiation), which opens on
proving that Enzyme's MLIR dialect is reachable from Rust before any @grad surface is designed.
See also SECURITY.md and the Code of Conduct.
Neuro Shared Source License v2.1. The license covers the compiler, not what you build with it.
You may freely use, study and modify the compiler for any personal or internal purpose, write Neuro programs and distribute or sell the compiled output under any terms you choose, build tools and editor integrations that call into the compiler, and contribute code back. Only redistributing the compiler itself, or a fork of it, as part of a commercial product requires a commercial license.
Neuro is pre-stabilization, and the license guards three risks specific to that: commercial re-packaging before the spec is stable, AI-assisted reproduction of the compiler for a competing product, and misleading forks that fragment an early ecosystem. A permissive license becomes possible once the language stabilizes.
Inspired by Rust (ownership, type system), Python (AI ecosystem simplicity), Swift (ergonomics) and Mojo (AI-first design). Built with inkwell, logos and LLVM.
