NIR (Morph Intermediate Representation)
NIR is the compiler's internal representation between the AST and final code generation.
Pipeline Position
Source → Lexer → Parser → AST → Semantic Analysis → NIR → { LLVM / native codegen | container bytecode (VCON stack) }
NIR sits between semantic analysis and backend-specific lowering. The LLVM pipeline lowers NIR to native code; the VCON stack lowers NIR toward bytecode/container artifacts when you use morph vcon … (target-dependent).
Who owns NIR behavior?
Most NIR lowers, optimizers, and backend-facing hooks are not handwritten as one giant switch in src/. They are registered from morphs/<Package>/:
feature.tomlsections name components (for examplecomponent = "nir.core.input_lowering",component_class = "…") and point atsourcefiles.- The package
morph.toml[build]list (nir_sources,codegen_sources, …) ensures those translation units compile into the package morph library. - Backend emit often appears as a route subsection (for example
[core.print.route.hostllvm]) withprovider_id,artifact_kind, and a dedicated Emit.cpp.
So when you debug or extend a NIR node kind, start from the owning package and its manifests—see how that node is spelled in Ops (nir_kind in [operation.*]) or in a Core built-in feature. For the full picture of manifests vs ABI, read Plugin-governed pipeline.
Viewing NIR
morph nir file.mx
What NIR Contains
- Functions — Typed, validated method representations
- Types — Resolved type information
- Constants — Evaluated constant expressions
- Instructions — Simplified operations (no sugar syntax)
Why NIR?
| Benefit | Description |
|---|---|
| Shared | Both LLVM and VCON paths consume NIR |
| Optimizable | Optimizations applied at NIR level benefit both paths |
| Portable | Language-level IR independent of target platform |
| Debuggable | Human-readable with morph nir command |
Next Steps
- Plugin-governed pipeline — manifests, phases, and backend routes
- Feature manifests —
feature.tomlshapes and[build]wiring - Optimizations — Compiler optimization passes