Skip to content
CryoCryo home
CompilerOverview

Compiler Architecture

The cryo binary is the compiler, the package manager, the test runner, and the dependency resolver. It is self-hosted: every line of Cryo you compile is compiled by a compiler written in Cryo, and the standard library it links against is written in Cryo too.

The pipeline

A build runs a multi-pass pipeline driven from compiler/src/compiler/instance.cryo:

Source
  -> Lex
  -> Parse
  -> Module Resolution
  -> Declaration Collection
  -> Type Resolution
  -> Type Lowering
  -> Specialisation (monomorphisation)
  -> Semantic Analysis
  -> Move Check
  -> Drop Insertion
  -> IR Generation (LLVM 20)
  -> Linking (clang)
  -> Native binary

Two properties of this ordering are worth calling out, because they are visible in the language:

  • Declaration collection runs before any body is type-checked. Every function signature in the compilation unit is gathered in a dedicated pass, so call ordering in source is irrelevant and there is no forward-declaration requirement.
  • Specialisation runs before semantic analysis. Generics are monomorphised into concrete instantiations first, so the analyser only ever sees fully concrete types. This is why a where bound is checked against each concrete instantiation and why layout directives such as ![repr(...)] are honoured per instantiation.

Where each stage lives

StageSource
Lexingcompiler/src/compiler/lex/
Parsingcompiler/src/compiler/parser/
ASTcompiler/src/compiler/AST/
Type system, monomorphisationcompiler/src/compiler/types/
Passes (sema, move, drop, specialisation, type lowering, header import)compiler/src/compiler/passes/
LLVM IR generationcompiler/src/compiler/codegen/
Diagnosticscompiler/src/compiler/diag/
CLIcompiler/src/CLI/

No separate runtime library

Every intrinsic in stdlib/core/intrinsics.cryo, plus format(), is emitted directly as LLVM IR by compiler/src/compiler/codegen/intrinsics_codegen.cryo. There is no runtime library to link beside your program — what a hosted build links is libcryo.a (the standard library), the C runtime, and the panic handler. A no_runtime build drops even those; see Project Configuration.

The self-hosting gate

Each release is built by the previous release. make selfhost-check runs a 3-round, 6-stage build and asserts the emitted LLVM IR is byte-identical between rounds — that is, the compiler compiled by stage N produces exactly the same output as the compiler compiled by stage N+1. A non-identical stage means a miscompilation somewhere in the pipeline, and the check gates every push to main.

The pinned compiler used to bootstrap lives at bin/cryo and is committed to the repository, so a clean checkout can rebuild the compiler with no external Cryo toolchain.

Reading further

  • Command-Line Interface — every subcommand and build flag.
  • Project Configuration — the cryoconfig format, build profiles, and the build directory layout.
  • Grammar — the complete EBNF grammar the parser implements.
  • ABI — SysV-amd64 lowering, eightbyte classification, and the calling convention for both extern "C" and Cryo-internal calls.
  • Symbol Mangling — how declarations map onto emitted symbol names, and how cryo demangle reverses it.
  • Test Framework — how cryo test discovers, forks, and reports tests.