Lanes and the machine: ppy.simd and ppy.cpu¶
This page covers two namespaces beside ppy.native: ppy.simd for vector
lanes and ppy.cpu for the machine you run on. Each has a reference
implementation under CPython and a lowering to a dialect of the IR
(The IR), so a program using them runs the same on
every path.
ppy.simd¶
ppy.simd operates on a few scalars at once. simd.Vector[T, N] is N
lanes of T, where T is int, float, bool, ppy.i8, or ppy.u8.
Building and reading vectors¶
splat[T, N](x)fills one.load[T, N](p)reads one from anative.ptr[T].store(v, p)writes it back.extract(v, i)andinsert(v, i, x)reach one lane. The index is guarded.shuffle(a, b, mask)builds a vector from the lanes of two by a constant mask.
Reductions¶
reduce_add, reduce_min, and reduce_max fold a vector to a scalar in lane
order, first to last. A floating-point sum is therefore the same number
everywhere, and a NaN lane is passed over or kept as Python's min would.
Operators¶
+ - *work lane by lane on numbers. Integer lanes wrap at their width./works on float lanes.& | ^work on integer and bool lanes.- The comparisons give a
Vector[bool, N], andselect(mask, a, b)chooses by it.
Limits¶
A vector lives in a local. It does not cross the Python boundary. E1640
names a misuse.
ppy.cpu¶
ppy.cpu is the machine as a facade, with no instruction named.
cpu.features()is what this machine has, in LLVM's spelling (avx2,fma,neon,sse4.2). The compiler folds"avx2" in cpu.features()to a constant for the machine compiling.cpu.vector_width[T]()is how manyTa vector register holds here, also a constant.cpu.prefetch(p, write=False, locality=3)andcpu.pause()are hints and change no value.@cpu.target("avx2", "fma")compiles a function with those features on. The boundary binds it only on a machine that has them all and runs its Python definition elsewhere, so a program stays correct on each machine it reaches.
E1643 names a misuse.
Examples: SIMD and the CPU.