Skip to content

Examples

Each folder is one program that shows one thing. examples/run_all.py runs all of them on the three paths (plain CPython, the Python backend, and LLVM native) and diffs the output. A difference is a compiler bug.

Where a folder holds both <name>.py and <name>.ppy, the .ppy is what ppy convert wrote, and examples/verify_conversions.py regenerates it to check that it still does.

Basics

Example What it shows
Basics Three small functions show fixed-width integer markers, a purity contract, and a per-function optimization level.
Arbitrary precision Integers stay Python integers: when a native multiply overflows a 64-bit word, the call goes back to CPython and still returns the exact answer.
Effects and contracts This example shows what @ppy.pure refuses, and how a value from a dynamic boundary gets back into typed code.
Classes Ordinary classes work when their fields are known statically, and a misspelled method is a compile-time error (E1202).
Native data This example shows which Python values cross the boundary as machine values, and which stay boxed.
Narrowing This example shows each form the checker narrows on, one function each.
Numerics PPy gives the same answers as CPython for overflow, floor division, and the sign of the remainder, cases where several other native compilers differ.
Value classes An all-scalar @dataclass has no boxed form in native code.
Tuples A tuple of known length and scalar elements is passed and returned unboxed.
Dynamic boundaries ppy.dynamic is the escape hatch for code strict PPy rejects, and this example shows what it costs.
Containers Element types inferred from first use, and the difference between mutating a container the function made and one it was given.
Exceptions Exception behavior is part of the contract: divide(1, 0) raises ZeroDivisionError and at([10, 20, 30], 9) raises IndexError at the same point, with the same type, whichever path runs them.
Strings String code checks in strict mode and is proven pure, but it stays on CPython, and the compiler says so.

Native code

Example What it shows
Buffers and JIT Borrowed memory, reassociation, and specialization each set how fast a numeric function runs, and each is chosen once in a signature or a decorator.
Algorithms Eight compute kernels measured against the same eight in C, and six judge problems timed the way a judge times them.
Threads A native function releases the GIL, so compute in it scales across threads.
Native memory Typed pointers, memory a function owns, a C function bound from libm, and a function exported as a C symbol.
Lanes and the machine This example shows ppy.simd, a few scalars operated on at once, and ppy.cpu, the machine as a facade with no instruction named.
Atomics and threads ppy.atomic and ppy.concurrent give you shared memory one operation at a time, and threads with what keeps them apart, over memory the program owns.
Parallel ranges for i in parallel.range(n) says the iterations may run at once.
Derivatives This example takes derivatives with ppy.grad and ppy.value_and_grad, which follow one rule table on every path, so the nine digits this program prints are the same nine everywhere.
Coroutines An echo server and its client in one program, written with ppy.aio.
Generics Generic functions use the Python 3.12 type-parameter syntax, and PPy infers the type arguments at each call and checks them against their bounds.
The toolbox One small program, run through each tool that looks inside its build: the IR at each stage, the source backends, the optimization report, the sanitizers, and profile-guided optimization.
Regular expressions A pattern compiled from a bytes literal is matched natively over a byte buffer.
Collections Five problems written with ppy.Vec, ppy.Deque, ppy.Heap, ppy.LinkedList, ppy.HashMap, and ppy.TreeSet, with no pointers in sight.

Accelerators

Example What it shows
GPU kernels A saxpy and a block reduction with shared memory and a warp shuffle, written once in ppy.cuda.
Tile kernels These GPU kernels work on tiles rather than threads: you write what a program does to a tile, and the compiler writes the threads, the shared memory, and the shuffles.
XLA @xla.jit compiles a function of floats, ints, and bools to StableHLO and runs each call on an XLA device.
Multi-GPU JAX training This trainer runs a data-parallel MLP over a mesh of every accelerator in the machine, and holds the result to a single-device run.

Libraries

Example What it shows
NumPy fusion An elementwise NumPy expression becomes one loop with no temporaries.
Pydantic Pydantic models are typed by the plugin and still validated by pydantic at run time.
Parallel fused kernels @ppy.parallel splits a fused NumPy loop across the worker pool, and the output is bit-identical to the serial kernel and to NumPy.
PyTorch ATen regions A function whose body is entirely curated tensor operations compiles into one C++ region that calls ATen directly: one Python round trip per call instead of one per operator.
GPT-2 XL: one region per block This example compiles each GPT-2 XL transformer block into one ATen region and measures it against PyTorch eager and torch.compile.
Training a torch MLP An ordinary PyTorch training script, converted by ppy convert with no hand editing.
Training a JAX MLP The same trainer as 21_training_torch with JAX, converted by ppy convert with no hand editing.
JAX export Build-time export of a @jax.jit function to StableHLO.
Serving over Uvicorn A raw ASGI callable and a converted FastAPI application, both served on Uvicorn through the same plugin.
Flax An MLP regression trained with Flax (linen) and optax, converted from ordinary Python and checked under strict = true with nothing extra installed or configured.
A trainer under torchrun and accelerate launch A plain PyTorch trainer whose kernels are .ppy modules, started by python, torchrun, or accelerate launch.
Columnar expressions Expressions over pandas Series converge onto the columnar dialect of the IR and fuse into one kernel over the columns' memory, nulls included.

Conversion and projects

Example What it shows
Inventory Untyped Python that converts cleanly, with no hand editing afterwards.
Inference Three modules with no type annotations, and the three .ppy files ppy convert wrote from them.
Interop A plain .py file importing a .ppy module, with no build step.
A multi-module project Two modules analyzed as one call graph and built as one program.
Migration A small legacy telemetry script, run through ppy migrate instead of ppy convert.