How Pyvorin compiles Python to native code
Pyvorin is not a JIT that guesses at runtime. It is an ahead-of-time compiler that analyses your source, proves type safety where possible and lowers the result to LLVM IR. Here is the full pipeline, from source to execution.
The compilation pipeline
Every function Pyvorin targets passes through five stages. If any stage rejects the code, Pyvorin either falls back to CPython or raises a strict-mode error.
AST Parse
Source is parsed with the standard ast module. Pyvorin walks the tree and
builds an internal representation annotated with source locations.
Type Inference
A Hindley-Milner-style solver propagates types through the graph. Where types are ambiguous, Pyvorin uses hints or inserts runtime guards.
Lower to LLVM IR
Typed AST nodes are translated into LLVM intermediate representation. Loop unrolling, vectorisation and inlining are applied by the LLVM opt pipeline.
Native Codegen
LLVM llc and the platform assembler emit a shared object. The binary is
cached on disk keyed by source hash and target architecture.
Load & Execute
The .so is loaded with ctypes. Arguments are marshalled from
Python objects to native types and results are returned back.
AST analysis & supported-subset detection
Pyvorin does not attempt to compile arbitrary Python. Instead it maintains a whitelist of
AST node types - For, ListComp, BinOp, Call
to known pure functions - and rejects anything outside that list.
The analyser also checks for side effects, mutable globals and calls into unsupported C extensions. If a function is rejected, the reason is recorded and reported.
This conservative approach is what makes the "honest benchmark" promise possible: we only measure what we can actually compile.
[PARSE] main.py:12 func 'aggregate_sales'
[TYPE] main.py:14 inferred List<float>
[TYPE] main.py:15 inferred float
[LOWER] main.py:12 lowering to LLVM IR...
[OPT] main.py:12 vectorised loop @ 256-bit
[CODEGEN] main.py:12 wrote /cache/aggregate_sales_x86.so
[LOAD] main.py:12 loaded in 0.3 ms
[OK] main.py:12 native execution
Type inference example
def total(prices: list[float]) -> float:
s = 0.0
for p in prices:
s += p * 1.2 # inferred float
return s
prices
List<float>
s
float
p
float
Type inference
Pyvorin uses a constraint-based type solver. It starts from explicit annotations, propagates through assignments and arithmetic, and unifies across function boundaries.
Where types cannot be proven statically, Pyvorin inserts lightweight runtime guards. If a guard fails, execution falls back to CPython for that call - never corrupting data or producing incorrect results.
The more type information you provide, the more aggressively Pyvorin can optimise. Even without annotations, best-effort inference covers most common numeric and string patterns.
Strict mode toggle behaviour
Strict mode changes what happens when Pyvorin encounters unsupported code. Choose the behaviour that matches your risk tolerance.
Strict mode ON
- Compilation fails immediately if any construct is unsupported.
- Guarantees every accelerated function is 100 % native.
- Recommended for CI pipelines and performance-critical production code.
- Error messages include line numbers, node types and suggested fixes.
Strict mode OFF
- Pyvorin compiles what it can and routes the rest to CPython automatically.
- Fallback is always logged with a reason code and line number.
- Best for exploratory development and gradual adoption.
- You can inspect the report and rewrite hotspots later.
Fallback tiers & reason codes
When Pyvorin cannot compile a function, it records exactly why. Reason codes let you programmatically decide whether to rewrite, annotate or accept the fallback.
UNSUPPORTED_AST_NODE, TYPE_INFERENCE_FAILED
The compiler could not handle a specific language construct or could not prove types. Execution falls back to CPython with zero behavioural change.
RUNTIME_TYPE_MISMATCH, BOUNDS_CHECK_FAILURE
Compilation succeeded but a runtime guard detected a violated assumption. The function re-executes under CPython for that call only; subsequent calls may still use the native path.
EXTERNAL_C_EXTENSION, NETWORK_DEPENDENCY
The code depends on a C extension or network resource that cannot be lowered to LLVM. Fallback is permanent for that function until the dependency is removed or abstracted.
Correctness checks
Every release of Pyvorin runs a correctness suite that compares native output against CPython output for thousands of randomly generated programs. If results differ, the build is rejected.
The suite covers integer overflow, float precision edge cases, string encoding, empty containers, NaN propagation and exception timing. We do not ship until the native path is provably equivalent.
Benchmark methodology
Our canonical benchmark suite runs on bare-metal servers after a thermal soak period. Each benchmark executes for a minimum wall-clock time to eliminate startup noise. Outliers beyond 3σ are discarded.
Speed-up figures are reported as the ratio of CPython median time to Pyvorin median time. We quote conservative ranges - for example 100×–1,000×+ for ETL filter/map - because real performance depends on data size, hardware and how much of the workload falls inside the supported subset.
Ready to go deeper?
Read the full documentation, explore supported workloads or run the benchmark suite yourself.