Compilation¶
Source, bytecode, and native code¶
EGCL lowers supported Lisp forms to bytecode and executes them in T0. The runtime can compile hot functions to T1 baseline native code and then T2 optimized code. Forms that are not lowered can use the tree-walking evaluator. Native backend coverage varies by architecture.
Compilation is therefore not a single event. Reading and evaluating a defun,
writing a compiled file, and optimizing a hot loop are distinct operations.
Execution tiers describes the shared model;
the dictionary below specifies the user-visible operations.
Function compilation¶
compile¶
Function (compile name &optional definition) → result, warnings-p, failure-p
With a definition, accepts a function or a lambda expression and produces a
callable function. A non-nil name installs the function in that symbol's
function cell and is returned as the primary value. With nil as the name,
the primary value is the function itself. Without a definition, uses the
existing function named by name.
The current implementation returns nil for the warning and failure values
on success. It does not force installation of a T2 version.
File compilation¶
compile-file¶
Function (compile-file input-file &key output-file ...)
→ output-truename, warnings-p, failure-p
Writes a compiled-file artifact. For source names ending in .lisp or .lsp,
the default output pathname replaces that suffix with .fasl. The contents use
EGCL's BFASL format; the filename suffix is not the format identifier.
Use :output-file to choose the destination. The current implementation also
accepts a positional output pathname as an extension, but portable code should
use the keyword. An odd or malformed keyword tail signals a program error.
Acceptance of additional compiler keywords does not establish full support for
their ANSI-specified effects.
(multiple-value-bind (output warnings-p failure-p)
(compile-file "example.lisp" :output-file "example.fasl")
(declare (ignore warnings-p))
(unless failure-p (load output)))
compile-file-pathname¶
Function (compile-file-pathname input-file &key output-file ...) → pathname
Computes the compiled output pathname without compiling. Use it rather than
constructing a .bfasl name yourself. A saved core, even if renamed .fasl, is
not a compiled file and must not be passed to load.
ASDF uses compilation and loading to build systems. The ASDF guide gives a minimal system with explicit source registration. Compiled files should be rebuilt when changing incompatible runtime versions; they are not a promise of indefinite binary compatibility.
Declarations and optimization¶
Common Lisp declarations describe the program, but accepted declarations are not a guarantee of a particular machine-code transformation. In particular, declaring fixnum types is not a promise that every operation is unboxed or that all runtime checks disappear.
T2 uses speculative guards and can reconstruct lower-tier state when a guard fails. Deoptimization must preserve both completed side effects and the next Lisp operation to execute. Raising compilation thresholds changes when work is compiled, not the intended semantics of the source.
Observing compilation¶
egcl-ext:function-tier¶
Function (egcl-ext:function-tier function) → integer or nil
Accepts a function designator. Returns 0, 1, or 2 for the installed tier,
or nil if the designator is not recognized as a tiered function. Polls for
completed background compilation before reading the tier.
Invocation and loop counters¶
Functions
(egcl-ext:function-invoke-count function)
(egcl-ext:function-back-edge-count function)
(egcl-ext:function-osr-count function)
(egcl-ext:deopt-count)
The first two report invocation and back-edge counts, or nil for an
unrecognized designator. function-osr-count reports successful native OSR
entries on the current thread for a non-nil function-name symbol; it returns
nil for other designators. deopt-count is a process-wide count.
These are observations; use them for diagnostics, not application decisions.
A function's installed tier does not identify the tier of an active OSR loop. For that purpose inspect OSR activity and execution behavior, rather than concluding from a T0 label that no native code ran.
egcl-ext:bail-report¶
Function (egcl-ext:bail-report) → number of distinct reasons
Prints collected bytecode-lowering decline reasons and counts. Enable collection
by starting the process with EGCL_BAIL_TRACE=1. With collection disabled and
no recorded failures, there is nothing to report.
Experimental compiler controls¶
Set these variables before starting the process. They are debugging controls, not a portable Common Lisp interface, and many are read once.
| Variable | Use |
|---|---|
EGCL_BACKEND=tree-walker |
Compare against the tree-walking execution path |
EGCL_LAZY_COMPILE=0 |
Request eager bytecode compilation rather than lazy compilation |
EGCL_T1_THRESHOLD |
Override the T1 invocation threshold |
EGCL_T2_THRESHOLD |
Compatibility override for the T2 invocation threshold |
EGCL_OSR_THRESHOLD |
Override named-loop OSR threshold; default 100,000 back edges |
EGCL_BAIL_TRACE=1 |
Collect bytecode-lowering decline reasons |
A threshold does not expand the target backend's supported instruction set. See Platform support and Profiling and efficiency.
Implementation reference: CLI compiler integration.