Skip to content

Compiler Pipeline

hologram-compiler turns a hologram_graph::Graph into a .holo archive: a self-contained, content-addressed artifact the executor can load and run. The compiler is no_std + alloc by default, so the whole pipeline runs in wasm and on embedded targets; the std feature only adds tracing diagnostics.

The per-graph pipeline (Compiler::compile) runs in order:

  1. Desugar composite ops into their primitive-op pipelines (e.g. ClipMin∘Max)
  2. Algebraic elision — drop computation UOR’s algebra proves unnecessary (identity elements, involutions, dead nodes)
  3. Schedule — compute topological levels
  4. Per-node compile: emit a Term tree, build and validate a CompileUnit, run completeness
  5. Cache certificates by content fingerprint over (op_kind, witt_level, backend)
  6. Lower each node to a backend KernelCall
  7. Weight-layout monomorphism — pre-pack constant matmul weights into the panel layout (zero runtime copy)
  8. Emit the .holo archive (kernel calls, schedule, exec plan, weights, constants, ports, certificates)
  • Compiler — main entry point; owns the graph, target BackendKind, and WittLevel
  • CompilationOutput{ archive: Vec<u8>, stats: CompilationStats }
  • CompilationStats — node/level counts plus cache hit/miss and validated-unit tallies
  • BackendKindCpu, Avx2, Avx512, Neon, Metal, Wgpu
  • CompileError — the pipeline’s error type

WittLevel comes from prism::vocabulary.

Compile a programmatically built graph:

use hologram_compiler::{Compiler, BackendKind};
use prism::vocabulary::WittLevel;
let output = Compiler::new(graph, BackendKind::Cpu, WittLevel::W32).compile()?;
let archive: Vec<u8> = output.archive;

Or use the free compile function:

use hologram_compiler::{compile, BackendKind};
use prism::vocabulary::WittLevel;
let output = compile(graph, BackendKind::Cpu, WittLevel::W32)?;

All source frontends lower through the same boundary:

source text -> SourceDocument -> selected SourceProgram -> Graph -> Compiler

SourceDocument lets frontends extract one or more graph regions from a larger host-language file before the compiler selects a single SourceProgram for lowering. This keeps source-language spans and AST details out of the graph IR, archive, backend, and executor.

hologram_compiler::source::parse remains the compatibility entry point for native Hologram source. It accepts both the original line-oriented grammar (# comments and blank lines ignored) and the native frontend path:

input x :2x3
op relu x as=y
output y
use hologram_compiler::{compile_from_source, BackendKind};
use prism::vocabulary::WittLevel;
let src = "input x\nop relu x as=y\noutput y\n";
let output = compile_from_source(src, WittLevel::W32, BackendKind::Cpu)?;

source::parse returns Result<Graph, CompileError> if you want the graph without compiling.

Use the language-aware API when the source file may contain more than one graph region or when it is written in a host-language frontend:

use hologram_compiler::source::{self, SourceLanguage, SourceParseOptions};
let options = SourceParseOptions::new().graph("encoder");
let program = source::parse_ir_with_options(
py_source,
SourceLanguage::Python,
&options,
)?;
let graph = source::lower_ir(&program)?;

If graph selection is not needed, compile source directly with the language convenience API:

use hologram_compiler::source::SourceLanguage;
use hologram_compiler::{compile_from_source_language, BackendKind};
use prism::vocabulary::WittLevel;
let output = compile_from_source_language(
py_source,
SourceLanguage::Python,
WittLevel::W32,
BackendKind::Cpu,
)?;

The CLI detects source language by extension for .txt, .py, .ts, .tsx, and .rs. Pass --source-language <lang> only for unusual extensions or an explicit override. Pass --graph <name> when a file contains multiple graph regions.

Python and TypeScript SDK packages also expose native Hologram .txt compilation through the FFI. Use hg.compile_source_file("graph.txt") in Python, or compileSource(...) from @hologram/sdk with a native/WASM binding in TypeScript. The Node adapter adds compileSourceFile("graph.txt") for filesystem-backed source files.

The Python frontend is behind the frontend-python feature on hologram-compiler and hologram-cli. It parses Python source as an AST and extracts restricted Hologram builder functions; it does not import, evaluate, or execute user Python code. Unrelated Python code is ignored. If a file contains one inferred graph, it is selected automatically; if it contains multiple graph functions, pass --graph.

def ordinary_app_code():
return 42
def encoder(h):
x = h.input("x", dtype="f32", shape=[2, 3])
w = h.const("w", shape=[3, 2], values=[1, 2, 3, 4, 5, 6])
y = h.ops.matmul(x, w, shape=[2, 2])
h.output("y", y)
Terminal window
cargo run -p hologram-cli --features frontend-python -- compile \
--source graph.py \
--graph encoder \
--output model.holo

The accepted Python subset is currently h.input, h.const / h.constant, h.ops.<op>, and h.output with literal shape, dtype, constant values, and the same op attributes accepted by native Hologram source. Unsupported statements inside an inferred graph function fail loudly; ordinary Python functions with no Hologram builder calls are ignored.

The TypeScript frontend is behind the frontend-typescript feature on hologram-compiler and hologram-cli. It parses TypeScript source as an AST and extracts restricted Hologram builder functions; it does not import, evaluate, or execute user TypeScript code. Unrelated TypeScript code is ignored. If a file contains one inferred graph, it is selected automatically; if it contains multiple graph functions, pass --graph.

function ordinaryAppCode() {
return 42;
}
export function encoder(h: HologramBuilder) {
const x = h.input("x", { dtype: "f32", shape: [2, 3] });
const w = h.const("w", { shape: [3, 2], values: [1, 2, 3, 4, 5, 6] });
const y = h.ops.matmul(x, w, { shape: [2, 2] });
h.output("y", y);
}
Terminal window
cargo run -p hologram-cli --features frontend-typescript -- compile \
--source graph.ts \
--graph encoder \
--output model.holo

The accepted TypeScript subset is currently h.input, h.const / h.constant, h.ops.<op>, and h.output with object-literal shape, dtype, constant values, and the same op attributes accepted by native Hologram source. Unsupported statements inside an inferred graph function fail loudly; ordinary TypeScript functions with no Hologram builder calls are ignored.

The Rust frontend is behind the frontend-rust feature on hologram-compiler and hologram-cli. It parses Rust source with syn and extracts restricted Hologram builder functions; it does not compile, link, or execute user Rust code. Unrelated Rust code is ignored. If a file contains one inferred graph, it is selected automatically; if it contains multiple graph functions, pass --graph.

fn ordinary_app_code() -> i32 {
42
}
pub fn encoder(h: &mut HologramBuilder) {
let x = h.input("x", dtype("f32"), shape([2, 3]));
let w = h.constant("w", shape([3, 2]), values([1, 2, 3, 4, 5, 6]));
let y = h.ops().matmul(x, w, shape([2, 2]));
h.output("y", y);
}
Terminal window
cargo run -p hologram-cli --features frontend-rust -- compile \
--source graph.rs \
--graph encoder \
--output model.holo

The accepted Rust subset is currently h.input, h.constant / h.const_, h.ops().<op>, and h.output with helper-call shape, dtype, constant values, and the same op attributes accepted by native Hologram source. Unsupported statements inside an inferred graph function fail loudly; ordinary Rust functions with no Hologram builder calls are ignored.