The compilation pipeline
Every phase a PHP file passes through on the way to a native binary, in order, with the timing label each phase reports.
A compile is a fixed sequence of phases. Each one transforms the program and
hands it to the next. The phase names below match the labels printed by
--timings, so you can map a slow compile
directly back to a stage here.
Phase order
PHP source
-> read read the source file from disk
-> tokenize Lexer: text -> tokens
-> parse Parser: tokens -> AST (Pratt expression parsing)
-> magic-constants lower __FILE__, __DIR__, __LINE__, __FUNCTION__, ...
-> (conditional) apply compiler ifdef branches from --define
-> autoload-build discover autoload rules
-> resolve resolve include/require and declarations
-> pdo-prelude inject the PDO prelude when used
-> tz-prelude inject the timezone-introspection prelude when used
-> list-id-prelude inject the DateTimeZone identifier-list prelude when used
-> var-export-prelude inject the var_export prelude when used
-> image-prelude inject the image (GD/Exif/Imagick) prelude when used
-> web-prelude inject the web runtime prelude with --web
-> name-resolve apply namespace/use rules, canonicalize names
-> autoload-run run autoload insertion
-> opt-fold AST constant folding
-> typecheck Type checker / warnings
-> exports-scan collect #[Export] functions (cdylib)
-> opt-prop AST constant propagation
-> opt-post prune constant control flow
-> opt-norm control-flow normalization
-> dce AST dead-code elimination
-> ir-lower AST -> EIR lowering + EIR validation
-> ir-opt EIR optimization passes (fixed-point driver)
-> ir-print print EIR and stop (with --emit-ir)
-> runtime-cache build/reuse the prebuilt runtime object
-> codegen-ir EIR -> target assembly
-> write-asm write the generated assembly
-> source-map write the .map sidecar (with --source-map)
-> assemble assembler: assembly -> object file
-> link linker: object files -> binary
Front end: source to checked AST
- read / tokenize / parse — the Lexer turns source text into tokens and the Parser builds the abstract syntax tree.
- magic-constants — magic constants such as
__DIR__and__LINE__are substituted before any later pass sees them. - conditional compilation —
ifdefbranches are resolved using the symbols passed with--define. - resolve / prelude injection / name-resolve —
include/requireare resolved, declarations are discovered, demand-loaded PHP preludes for PDO, timezone introspection,DateTimeZone::listIdentifiers(),var_export(), and image processing are injected only when referenced, the web runtime prelude is injected with--web, and namespace/userules rewrite references to fully-qualified names. Autoloading is wired in around these steps. - typecheck — the Type Checker infers and validates types and emits warnings.
Middle: AST optimization
The AST optimizer runs PHP-preserving rewrites that are naturally expressed over syntax: opt-fold (constant folding), opt-prop (constant propagation), opt-post (constant control-flow pruning), opt-norm (control-flow normalization), and dce (dead-code elimination). See The Optimizer. These always run; they are not behind a flag.
Back end: EIR and code generation
- ir-lower — the checked AST is lowered into EIR, elephc’s PHP-shaped intermediate representation, then validated once for structural, type, dominance, ownership, and effect invariants. See The EIR Design.
- ir-opt — the EIR optimization passes
run a fixed-point driver over each function: identity arithmetic folding,
local peephole rewrites, constant folding, common-subexpression elimination,
loop-invariant code motion, CFG-aware dead-instruction elimination, dead-store
elimination, and branch simplification. In
debug/test builds the function is re-validated after every pass. This phase
can be turned off with
--no-ir-opt. - ir-print — only present with
--emit-ir; formats the optimized or unoptimized EIR textual form, prints it to stdout, and stops before runtime preparation or code generation. - runtime-cache — the hand-written runtime is assembled once and cached in
~/.cache/elephc/, then reused across compiles. See The Runtime. - codegen-ir — EIR is lowered to target assembly through the default backend. See The Code Generator.
Tail: assemble and link
The generated assembly is written out, assembled into an object file, and linked together with the cached runtime object (and any extra libraries) into the final binary.
Inspecting intermediate stages
You do not have to run the whole pipeline. Several flags stop early or dump an intermediate artifact:
--checkruns the front end only.--emit-irprints EIR (afterir-opt) and stops.--emit-asmwrites assembly without linking.--timingsprints how long each phase took.