An AOT-compiled language for high-performance AI development.
Status: Alpha. Phase 1 (Core Language) is complete: the full general-purpose language surface compiles and runs. Phase 2 (Tensors and MLIR) is now open. Per-phase status lives in one place: the Quick Roadmap.
Neuro is an Ahead-of-Time (AOT) compiled language for AI workloads. Python is interpreted and leans on C libraries for anything fast; Neuro compiles to native code through an LLVM 20 backend instead. Planned on top of that backend:
- MLIR-based tensor operations, for static shape-verified tensor types
- IR-level automatic differentiation via Enzyme
- GPU acceleration via MLIR GPU dialects (nvgpu, rocdl, Triton)
A single perceptron with ReLU activation; uses structs, impl blocks, associated functions, instance methods, if-expressions, implicit returns, and println. 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
}
php
input 0.0 -> 0.00 fires: false
input 1.0 -> 0.40 fires: true
Every row below is implemented, tested, and usable today. Depth lives elsewhere: the documentation site and docs/ for reference material, CHANGELOG.md for the per-release detail, and the Quick Roadmap for what is still ahead.
| Feature | Summary |
|---|---|
| Types & inference | i8 throughu64 ,f16 /bf16 /f32 /f64 ,bool ,char ,string ; literal suffixes, digit separators,as casts, type aliases,.is_nan() |
| Functions & control flow | Recursion, forward refs, implicit returns, named arguments with external labels ( clamp(x, min: 0.0) );if /elif /else ,while ,loop , range-for ,for (i, x) in xs.enumerate() , labelledbreak /continue , block-as-value;for over any type implementing the prelude'sIntoIterator /Iterator protocol, plus.map(f) /.filter(p) head adapters |
| Generics | Generic functions, structs, and impls plus const generics, where clauses, and turbofish, all fully monomorphized at zero runtime cost |
| Traits & dispatch | Required and default methods, associated types ( type Item /Self::Item ) andTrait<Assoc = T> bounds, operator traits,impl Trait (static) anddyn Trait (vtable) dispatch with object-safety checks |
| Closures & lambdas | |x: i32| x * x ,move closures,(T) -> R function types, higher-order functions; compiled to{ fn_ptr, env_ptr } , no heap |
| Structs & methods | Fields, shorthand init, functional update ..base ,impl blocks with&self /&mut self methods and associated functions;@derive(Copy, Clone, Debug, PartialEq) for copying,{p:?} rendering, and structural equality |
| Enums & newtypes | Unit, tuple, and struct-field variants; generic enums monomorphized per type argument; newtype for distinct nominal wrappers |
| Arrays, tuples & collections | Fixed-size [T; N] and anonymous tuples overCopy elements; borrowed slices&[T] /&mut [T] with zero-copy.slice(range) over an array or aVec ; heap-backedVec<T> ,HashMap<K, V> ,BTreeMap<K, V> ,String that move on assignment and free at scope exit; statically shapedTensor<T, [d0, ...]> built from an annotated nested literal orTensor::<T, [...]>::zeros() /ones() /identity() /random_normal() /scalar() /from() , owning its buffer with.clone() ,.to(device) , and in-place+= /-= /*= //= /%= |
| Pattern matching | Exhaustive match expressions over variant / literal / or / range / wildcard patterns withif guards, plusval Point { x, y } = p andval [a, ..rest] = arr destructuring |
Option / Result |
Option<T> andResult<T, E> from the implicit prelude. They are ordinary generic enums, available with no declaration and no import, variants included;?? unwraps either with a lazy fallback;? propagates the failure to the caller;val-else unwraps or exits the scope;checked_add /checked_sub /checked_mul report integer overflow asOption::None |
| Ownership & borrows | Move-by-default, Copy , deterministicDrop ,&T /&mut T with flow-sensitive exclusivity, lifetime elision and annotations |
| Strings | Immutable fat-pointer string with escapes,&string slices,== ,+ concatenation,.len() /.clone() /.slice(a..b) /.char_slice(a..b) , codepoint iteration with.chars() and.char_indices() , interpolation"{x:.2}" , triple-quoted""" blocks with dedent; growableString buffer for building text:push_str /clear /to_string |
| Modules & visibility | Multi-file programs: every .nr file is a module andmod.nr directories nest; inlinemodule { } blocks group within one file;import math::{sqrt} ,import ./utils ,as renames, module aliases, variant imports, andexport import re-export facades; declarations and struct fields are private untilexport opts them in; an implicit prelude putsOption /Result andSome /None /Ok /Err in every module, with@no_prelude to opt out |
| Toolchain | Native binaries via inkwell 0.10 / LLVM 20; neurc check andneurc compile ; bufferedprint /println to stdout, line-buffered on a terminal and drained on every exit path;panic /assert /unreachable runtime with located diagnostics, covering array bounds, string slices, a zero divisor, and debug-build integer overflow, all outlined off the hot path |
Alpha memory warning. Stack values are reclaimed on return and string literals live in .rodata, so neither leaks. Move semantics, borrows, deterministic Drop, and the owning collections have landed, so a Vec, HashMap, BTreeMap, or String frees its buffer at scope exit. A heap string (the one + concatenation and interpolation produce) is freed too when the compiler can prove who owns it: a temporary the statement consumes, or a binding whose initializer allocated it. A loop that formats output therefore holds steady rather than growing.
What still leaks is a heap string that escapes what the compiler can follow: one stored into a collection or a struct field, one returned from a function, and the prior value of a reassigned binding. The ownership test answers conservatively by design, since freeing a .rodata literal would be far worse than holding a buffer.
This block is removed once those results are tracked too. Until then, do not assume memory-safety semantics beyond what the table above claims.
If memory-safety semantics and compiler backend design are your thing, this is exactly where contributors are needed.
neurc compile -O 3 hands the module to the same LLVM 20 optimization pipeline clang -O2 uses, so compute-bound code lands in the same range as C++ rather than somewhere between C++ and Python.
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 rather than to the language, and the Python column to whichever python3 is on your PATH, which is why the version is named. Two rows are worth a word. print_lines beats C because an integer hole renders through a digit loop instead of snprintf; int_divide is the one place the compiler spends rather than saves, since / and % guard the operand pairs the hardware instruction leaves undefined and an opaque divisor keeps those guards in the loop.
The default is -O 0: checked arithmetic, no optimization pipeline. Pass -O 3 before drawing any conclusion about speed.
| Requirement | Version | Notes |
|---|---|---|
| Rust | 1.85+ | Install via rustup |
| LLVM 20 | 20.x with dev libs | Platform instructions below |
| C linker | any | gcc /clang on Linux/macOS; MSVC on Windows |
This is the only step that differs between systems. Add the export to 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 10 / 11 (x64) needs a longer walkthrough; see below.
With LLVM in place and Rust installed from rustup.rs:
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 PATH
On Windows the same four commands run unchanged in PowerShell, and
cargo install places neurc.exe in %USERPROFILE%\.cargo\bin, which rustup
has already added to PATH.
Windows needs the MSVC toolchain, not GNU, and LLVM does not come from a package manager. Four extra steps, after which Step 2 above runs unchanged.
Install Visual Studio Build Tools. Download from visualstudio.microsoft.com/downloads under Tools for Visual Studio β Build Tools for Visual Studio 2022, and select the Desktop development with C++ workload. 2019 or later works.
Install Rust. Run rustup-init.exe from rustup.rs and choose
1) Proceed with standard installation, which selects the
stable-x86_64-pc-windows-msvc toolchain. Open a new PowerShell window afterwards so
cargo and rustc are on PATH.
Install LLVM 20 to a path without spaces (the NSIS installer enforces this):
$version = "20.1.8"
$url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-$version/LLVM-$version-win64.exe"
curl.exe -fsSL -o "$env:TEMP\llvm-installer.exe" $url
Start-Process "$env:TEMP\llvm-installer.exe" -ArgumentList "/S /D=C:\LLVM" -Wait -PassThru | Out-Null
The installer is also downloadable by hand from the LLVM releases page.
Point the build at it. No admin rights needed:
[Environment]::SetEnvironmentVariable(
"LLVM_SYS_201_PREFIX", "C:\LLVM",
[EnvironmentVariableTarget]::User
)
$current = [Environment]::GetEnvironmentVariable("Path", "User")
[Environment]::SetEnvironmentVariable("Path", "$current;C:\LLVM\bin", "User")
Close and reopen PowerShell, then check with llvm-config --version, which should
print 20.x.y.
Troubleshooting Windows build errors
llvm-sys build script cannot find LLVM: confirm LLVM_SYS_201_PREFIX
is set in the current shell session (echo $env:LLVM_SYS_201_PREFIX)
and points to a directory that contains bin\llvm-config.exe.
link.exe not found: the MSVC Build Tools are not on PATH. Run the
build from a Developer PowerShell / x64 Native Tools Command Prompt
or install the C++ build tools workload as described above.
Version mismatch (llvm-sys-201 requires LLVM 20): an older LLVM is on
PATH. Set LLVM_SYS_201_PREFIX explicitly to the LLVM 20 prefix and
ensure C:\LLVM\bin precedes any other LLVM entries in PATH.
cargo run -p neurc -- check examples/basics/hello.nr
cargo run -p neurc -- compile examples/basics/factorial.nr
./examples/basics/factorial
neurc compile examples/basics/factorial.nr
// Immutable by default
val x: i32 = 42
val name: string = "Neuro"
// Mutable with reassignment
mut counter: i32 = 0
counter = counter + 1
// Type inference works for both val and mut
val pi = 3.14159 // inferred f64
val n = 100 // inferred i32
mut count = 0 // inferred i32; type annotation optional
php
// Explicit return
func add(a: i32, b: i32) -> i32 {
return a + b
}
// Expression-based implicit return (trailing expression)
func multiply(a: i32, b: i32) -> i32 {
a * b
}
php
func fizzbuzz(n: i32) -> i32 {
mut i: i32 = 1
while i <= n {
i = i + 1
}
i
}
func sum(n: i32) -> i32 {
mut total: i32 = 0
for i in 0..n {
total = total + i
}
total
}
php
struct Point {
x: f64,
y: f64
}
func distance(p: Point) -> f64 {
// field read
val dx = p.x
val dy = p.y
dx * dx + dy * dy // placeholder (no sqrt yet)
}
func main() -> i32 {
val origin = Point { x: 0.0, y: 0.0 }
// field mutation requires mut binding
mut cursor = Point { x: 3.0, y: 4.0 }
cursor.x = 1.0
return 0
}
Verbatim from examples/showcase/closures.nr. It compiles, links, prints the three results below, and exits with code 90.
// Apply `f` to each element of a 4-element array and sum the results.
func map_sum(xs: [i32; 4], f: (i32) -> i32) -> i32 {
mut total: i32 = 0
mut i: i32 = 0
while i < 4 {
total += f(xs[i])
i += 1
}
return total
}
struct Scaler {
factor: i32
}
impl Scaler {
func apply(&self, x: i32) -> i32 {
x * self.factor
}
}
func main() -> i32 {
val data: [i32; 4] = [1, 2, 3, 4]
// A closure capturing a Copy local (`bias`) by value.
val bias = 10
val biased = map_sum(data, |x: i32| x + bias) // 11+12+13+14 = 50
// A `move` closure with a block body and early return.
val scale = 3
val scaled = map_sum(data, move |x: i32| -> i32 {
val y = x * scale
return y
}) // 3+6+9+12 = 30
// A struct method still resolves alongside closures.
val s = Scaler { factor: 2 }
val doubled = s.apply(5) // 10
println("capture by value |x| x + bias = {biased}")
println("move closure move |x| x * scale = {scaled}")
println("struct method s.apply(5) = {doubled}")
val total = biased + scaled + doubled
println("total = {total}")
total // 50 + 30 + 10 = 90
}
Every runnable program in examples/showcase/ combines several features at once and is pinned twice: to an expected exit code in examples/expected.txt, and to the exact text it prints in a sibling .out file. By-value tensor arithmetic, @grad, and GPU kernels are not shown here because they do not exist yet; tensor construction does, in showcase/model_shapes.nr, and the in-place update in showcase/optimizer_step.nr. See the Quick Roadmap.
Neuro follows Vertical Slice Architecture (VSA): the code is organized by language feature, not by technical layer.
compiler/
βββ infrastructure/ # Shared, zero-business-logic crates
β βββ ast-types/ # AST node definitions
β βββ diagnostics/ # Error / warning types + rendering
β βββ project-config/ # Project / manifest configuration
β βββ 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 analysis
βββ control-flow/ # CFG data structures; no caller yet
βββ hir-lowering/ # Type-checked AST β typed HIR
βββ llvm-backend/ # HIR β object code (inkwell 0.10 / LLVM 20)
βββ mlir-backend/ # HIR β MLIR scaffold (off-by-default `mlir` feature)
βββ neurc/ # CLI compiler driver (pipeline orchestration)
Today:
Source (.nr)
β Lexical Analysis (tokens)
β Syntax Parsing (AST)
β Semantic Analysis (type-checked AST)
β HIR Lowering (typed High-Level IR, neuro-hir)
β LLVM Backend (object code via inkwell / LLVM 20)
β System Linker (native executable)
Planned extension (Phase 2+):
Tensor/AI path: typed High-Level IR (neuro-hir)
β MLIR (linalg/tensor/func/arith, LLVM 20 / MLIR 20)
β Enzyme MLIR AD pass (@grad)
β GPU dialects (nvgpu/rocdl/Triton) or llvm dialect
β inkwell β native code
Each numbered phase is a MAJOR-version milestone: completing Phase N ships v(N+1).0.0. Phase 1 is complete and we are now in Phase 2. A phase is divided into lettered sub-phases.
| Phase | Goal | Status |
|---|---|---|
| 1 | Core Language : types, control flow, LLVM backend, ownership and borrow checking, generics, traits and dispatch, closures, enums and pattern matching, error handling, modules and prelude, string interpolation | Complete |
| 2 | Tensors and MLIR : first-class tensor types lowered through MLIR Linalg, plus the pool allocator. Finishing it shipsv3.0.0 | In progress |
| 2A | Standard I/O and spec stragglers: print /println ,.is_nan() , codepoint string APIs,.enumerate() , borrowed slices&[T] , the iterator protocol,@derive(Debug, PartialEq) |
Complete |
| 2B | Tensor core: Tensor<T, [...]> , literal coercion, move semantics, DLPack, slicing, shape generics, named dims, dynamic shapes, reductions |
In progress |
| 2C | MLIR lowering: tensor arithmetic to Linalg, broadcasting, matmul behind @ , end-to-end HIR β MLIR β LLVM |
Planned |
| 2D | Pool allocator: pool blocks,PoolAware , LIFO release at scope exit |
Planned |
| 2E | Functional sugar: pipeline |> , composition>> , einstein notation, functional tensor ops |
Planned |
| 3 | Automatic differentiation: Enzyme MLIR pass, @grad(wrt: ...) ,.backward() /.zero_grad() , higher-order derivatives, SGD |
Planned |
| 4 | GPU acceleration: MLIR GPU dialects (nvgpu / rocdl / Triton), @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 ,JoinHandle ,join /race , executor for data- / I/O overlap |
Planned |
| 7 | Interop and advanced features: Python FFI via DLPack, spread operator, advanced pattern matching, custom attributes, defer |
Planned |
| 8 | Developer experience: Language Server Protocol, diagnostics polish, formatter, @test runner |
Planned |
| 9 | Package manager and distribution: neurpm , cross-OS installer / uninstaller / self-updater, signed release binaries, optimization passes (loop unrolling, AD-aware inlining, LTO) |
Planned |
Set LLVM_SYS_201_PREFIX for your platform before running any Cargo command
(see Installation for the correct path per OS).
cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --all -- --check
cargo fmt --all
On Windows, use PowerShell or a Developer Command Prompt. The env var must be set in the current session; prefix it inline if needed:
$env:LLVM_SYS_201_PREFIX = "C:\LLVM"
cargo build --workspace
Syntax highlighting for .nr files is included in neuro-language-support/.
cd neuro-language-support
npm install -g @vscode/vsce # once
vsce package # -> neuro-language-support-<version>.vsix
code --install-extension neuro-language-support-*.vsix --force
Reload the VS Code window afterwards (Developer: Reload Window). A grammar change
does not apply to already-open editors. During grammar work, symlinking the folder into
~/.vscode/extensions/ avoids repackaging: a window reload then picks up every edit.
| Extension | Purpose |
|---|---|
.nr |
Neuro source files |
.nrl |
Compiled library modules |
.nrm |
Serialized model/matrix data |
.nrp |
Package definitions |
See CONTRIBUTING.md for architecture guidelines, coding standards, and the pull request process. Confirmed open defects live in docs/BUGS.md. Fixing one is the best way to start.
The project is in early alpha, so breaking changes are expected. Contributions should focus on Phase 2 (Tensors and MLIR); the Quick Roadmap marks which phase is currently open.
AI development is stuck in a fragmented paradigm: developers iterate in an interpreted glue language (Python), while underlying libraries are written in unmanaged, safety-critical systems languages (C++/CUDA).
Neuro is built to unify this stack:
- True native performance. Compiled AOT via LLVM 20, with no heavy runtime interpreter and no global interpreter lock (GIL).Measured against C++ and Python on compute-bound programs.
- AI-First Type System: Native compile-time shape verification for tensors using MLIR (Phase 2), preventing runtime dimension mismatches before a single line of training executes.
- Immutability by Default: A modern
val/mutparadigm to ensure highly parallelized tensor computations are thread-safe by design.
Licensed under the Neuro Shared Source License v2.1.
Why not MIT/Apache 2.0 right now? Neuro is in a critical pre-stabilization phase. The license protects against three specific risks: commercial re-packaging of the compiler before the language spec is stable, AI-assisted reproduction of the compiler for a competing product, and misleading forks that fragment the early ecosystem. None of these restrictions affect normal use.
What you can do 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. programs you compile are wholly exempt from this license
- Build tools, plugins, and editor integrations that call into the compiler
- Contribute code back to the project
What requires a commercial license:
- Redistributing the Neuro compiler itself (or a fork of it) as part of a commercial product
See LICENSE for full terms.
Inspired by Rust (ownership, type system), Python (AI ecosystem simplicity), Swift (language ergonomics), and Mojo (AI-first design). Built with inkwell, logos, and the LLVM infrastructure.