cheatah
Module

gpu::linalg::kernels

cheatah-gpu-linalg v0.4.4-alpha — Biome Standard 0.6.3-alpha

Functions

fn void gemm_emulated(void **b, unsigned n, const emu::DispatchShape &) #

CPU GEMM stand-in mirroring linalg.slang's register-tiled gemm result (the tiling is a device optimization; the product is the same): row-major C[M×N] = A[M×K]·B[K×N], dims = {M, N, K}.

The kernel's workgroup grid always covers all of C, so the stand-in iterates the dims directly (the DispatchShape is block-granular for this kernel).

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

n

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(M·N·K).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:matmul
fn void gemm_batched_emulated(void **b, unsigned n, const emu::DispatchShape &shape) #

CPU stand-in for gemm_batched: C[z] = A[z]·B[z] per batch layer z of the 3-D grid, dims = {M, N, K, B}.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

n

The binding count (the stand-in is a no-op when fewer than expected).

shape

The dispatch thread grid (its height/width/depth bound the loops).

Complexity

O(B·M·N·K).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:matmul_batched
fn void outer_emulated(void **b, unsigned n, const emu::DispatchShape &shape) #

CPU stand-in for outer: out[n×m] = a_i·b_j, dims = {n, m}.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

n

The binding count (the stand-in is a no-op when fewer than expected).

shape

The dispatch thread grid (its height/width/depth bound the loops).

Complexity

O(n·m).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:outer
fn void transpose_emulated(void **b, unsigned n, const emu::DispatchShape &shape) #

CPU stand-in for transpose: out[c×r] = in[r×c]ᵀ, dims = {r, c} — CONJUGATED for a complex element (the Hermitian adjoint), exactly like the device kernel's CONJ seam.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

n

The binding count (the stand-in is a no-op when fewer than expected).

shape

The dispatch thread grid (its height/width/depth bound the loops).

Complexity

O(r·c).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:transpose
fn void vdot_partial_emulated(void **b, unsigned nb, unsigned long width) #

CPU stand-in for the conjugating vdot_partial (complex elements): partial[g] = Σ conj(a[k])·b[k].

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

width

The 1-D dispatch width (how many partial threads are emulated).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:complex
fn void kron_emulated(void **b, unsigned n, const emu::DispatchShape &shape) #

CPU stand-in for kron: K[(ar·br)×(ac·bc)] = A⊗B, dims = {ar, ac, br, bc}.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

n

The binding count (the stand-in is a no-op when fewer than expected).

shape

The dispatch thread grid (its height/width/depth bound the loops).

Complexity

O(n⁴) in the output area.

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:kron
fn void dot_partial_emulated(void **b, unsigned nb, unsigned long width) #

CPU stand-in for dot_partial: thread g writes partial[g] = Σ a[k]·b[k], k = g, g+P, …; dims = {n, P}.

Bit-identical to the device kernel — the same strided association order.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

width

The 1-D dispatch width (how many partial threads are emulated).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:dot
fn void trace_partial_emulated(void **b, unsigned nb, unsigned long width) #

CPU stand-in for trace_partial: partial[g] = Σ a[k·(c+1)], k = g, g+P, …; dims = {m, c, P}.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

width

The 1-D dispatch width (how many partial threads are emulated).

Complexity

O(m).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:trace
fn void ew_binary_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for the ew_* binary family: out[i] = a[i] OP b[i], dims = {n}; the operator is a template parameter mirroring the per-operator kernel compilation.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:elementwise
fn void fill_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-ins for the stream kernels: fill (out[i] = s), copy (bandwidth probe), triad (a = b + s*c, bandwidth probe).

dims = {n} in the last binding, like their GPU forms.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:elementwise
fn void copy_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for copy (out[i] = in[i], the bandwidth probe); dims = {n} last.

Parameters
b

The bound buffer pointers {in, out, dims}.

nb

The binding count (no-op when fewer than expected).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

fn void triad_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for triad (a = x + s·y, the bandwidth probe); dims = {n} last.

Parameters
b

The bound buffer pointers {a, x, y, s, dims}.

nb

The binding count (no-op when fewer than expected).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

fn void ews_binary_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for the ews_* array⊗scalar family: dims = {n, swap}; swap = 1 computes s OP a.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:operators
fn void ew_unary_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for the ew_* unary family: out[i] = F(a[i]), dims = {n}.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:elementwise
fn void sum_partial_emulated(void **b, unsigned nb, unsigned long width) #

CPU stand-in for sum_partial: partial[g] = Σ a[k], k = g, g+P, …; dims = {n, P} — the same strided association order as the device kernel (bit-identical).

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

width

The 1-D dispatch width (how many partial threads are emulated).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:elementwise
fn void dot_partial2_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for the TWO-STAGE dot_partial2/vdot_partial2: reproduces the kernel's exact association order — per-thread strided accumulation, then the fixed groupshared tree.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(n) accumulation + O(G·256) tree folds.

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:dot
fn void sum_partial2_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for the TWO-STAGE sum_partial2 (same contract over one input).

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(n) accumulation + O(G·256) tree folds.

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:elementwise
fn void finalize_partials_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for finalize_partials: the same single-group strided + tree fold into out[0].

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(G) + a fixed 256-wide tree.

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:dot
fn void axpy_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for the fused axpy: out[i] = α·x[i] + y[i], dims = {n}.

Parameters
b

The bound buffer pointers, in the kernel's binding order (dims last unless noted).

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(n).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:elementwise
fn T conv_act_f(T z, std::uint32_t act) #

The conv epilogues' scalar activation (matches the Slang cba_act table exactly): 0 = identity, 1 = relu, 2 = tanh, 3 = sigmoid.

Parameters
z

The pre-activation value.

act

The activation code (0–3; validated by the dispatching routine).

Returns

f(z) for the selected activation.

Complexity

O(1).

Host allocation

none.

GPU allocation

none.

Unit testgpu:conv
fn T conv_act_df(T a, std::uint32_t act) #

The conv epilogues' scalar derivative FROM THE OUTPUT a = f(z) (matches cag_dact): identity' = 1, relu' = [a > 0], tanh' = 1 − a², sigmoid' = a(1 − a).

Parameters
a

The activation OUTPUT f(z) (not the pre-activation).

act

The activation code (0–3; validated by the dispatching routine).

Returns

f′(z) expressed in terms of a.

Complexity

O(1).

Host allocation

none.

GPU allocation

none.

Unit testgpu:conv
fn void im2col2d_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for im2col2d: col[((c·KH+kh)·KW+kw)·B·OO + b·OO + oh·OW + ow] = x in-bounds, 0 for padding (FULL overwrite); dims = {B, C, H, W, KH, KW, OH, OW, stride, pad}.

The same per-element gather as the device kernel, iterated over the col linear index.

Parameters
b

The bound buffer pointers {x, col, dims}.

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(B·C·KH·KW·OH·OW).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:conv
fn void col2im2d_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for col2im2d: dx[i] = Σ over its ≤ KH·KW contributing dcol cells, kh-major — the gather-form adjoint, bit-identical to the reference scatter-add's association order.

Same dims as im2col2d.

Parameters
b

The bound buffer pointers {dcol, dx, dims}.

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(B·C·H·W·KH·KW) bound checks (≤ KH·KW adds per input cell).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:conv
fn void conv_bias_act_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for conv_bias_act: a[(b·F+f)·OO + o] = act(yc[f·B·OO + b·OO + o] + bias[f]); dims = {B, F, OO, act}.

Parameters
b

The bound buffer pointers {yc, bias, a, dims}.

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(B·F·OO).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:conv
fn void conv_act_grad_emulated(void **b, unsigned nb, unsigned long) #

CPU stand-in for conv_act_grad: dyc[f·B·OO + b·OO + o] = d[(b·F+f)·OO + o] · act'(a[(b·F+f)·OO + o]) with the derivative FROM THE OUTPUT; dims = {B, F, OO, act}.

Parameters
b

The bound buffer pointers {d, a, dyc, dims}.

nb

The binding count (the stand-in is a no-op when fewer than expected).

Complexity

O(B·F·OO).

Host allocation

none — writes in place through the bound buffers.

GPU allocation

none.

Unit testgpu:conv
fn void register_emulated_kernels() #

Register every emulated stand-in with the software Metal device, both element types (the device kernels lack a Metal f64 — Metal has no double — but the emulator provides it, which is how cheatah's default double element is exercised on this backend).

Idempotent: registering a name again just overwrites it with the same pointer.

Constants & variables

var std::uint32_t kLocal1d #

Threads per workgroup of every 1-D kernel — matches [numthreads(256,1,1)] in linalg.slang.

var std::uint32_t kLocal2d #

Threads per workgroup axis of every 2-D kernel — matches [numthreads(16,16,1)].

var std::uint32_t kMaxReduce #

The partial-sum width cap: a reduction dispatches P = min(n, kMaxReduce) threads, each writing one deterministic partial the routine sums on the host.

var std::uint32_t kGemmBlock #

The register-tiled GEMM's C-block edge: one 16x16-thread workgroup computes a 64x64 tile (4x4 register microtile per thread) — matches gemm in linalg.slang.

var std::uint32_t kGemmFastBlock #

The fast GEMM path's C-block edge (one 16×16-thread workgroup per 128×128 tile, 8×8 microtile per thread) and its K-slab width.

var std::uint32_t kGemmFastK #

The fast GEMM path's K-slab width (the double-buffered groupshared depth).

var const char * gemm_fast_name #

The kernel name a routine dispatches for element type T.

Specialized per supported element; the primary is left null so an unsupported element fails loudly at the GpuElement constraint, never as a null-named dispatch. GEMM has TWO paths: gemm_fast (128×128 blocks, double-buffered, vec4 loads, ZERO bounds checks — real elements with M%128==0 && N%128==0 && K%8==0 only) and gemm_edge (64×64, guarded, any shape, all elements). The routine gates on shape.

var const char * gemm_fast_name< float > #

The f32 entry.

var const char * gemm_fast_name< double > #

The f64 entry.

var const char * gemm_fast64_name #

The 64-row fast sibling (f32 only): M%64, N%128, K%16 — training-shaped batch-64 rectangles.

var const char * gemm_fast64_name< float > #

The f32 entry.

var const char * gemm_edge_name #

The guarded 64x64 edge-GEMM kernel name (any shape, every element type).

var const char * gemm_edge_name< float > #

The f32 entry.

var const char * gemm_edge_name< double > #

The f64 entry.

var const char * gemm_edge_name< std::complex< float > > #

The c64 entry.

var const char * gemm_edge_name< std::complex< double > > #

The c128 entry.

var const char * gemm_batched_name #

Batched GEMM kernel name per element type (grid z = batch; dims = {M, N, K, B}).

var const char * gemm_batched_name< float > #

The f32 entry.

var const char * gemm_batched_name< double > #

The f64 entry.

var const char * gemm_batched_name< std::complex< float > > #

The c64 entry.

var const char * gemm_batched_name< std::complex< double > > #

The c128 entry.

var const char * outer_name #

Outer product kernel name per element type (see linalg.slang outer).

var const char * outer_name< float > #

The f32 entry.

var const char * outer_name< double > #

The f64 entry.

var const char * outer_name< std::complex< float > > #

The c64 entry.

var const char * outer_name< std::complex< double > > #

The c128 entry.

var const char * transpose_name #

Transpose kernel name per element type (the real-element conj_transpose).

var const char * transpose_name< float > #

The f32 entry.

var const char * transpose_name< double > #

The f64 entry.

var const char * transpose_name< std::complex< float > > #

The c64 entry.

var const char * transpose_name< std::complex< double > > #

The c128 entry.

var const char * kron_name #

Kronecker product kernel name per element type.

var const char * kron_name< float > #

The f32 entry.

var const char * kron_name< double > #

The f64 entry.

var const char * kron_name< std::complex< float > > #

The c64 entry.

var const char * kron_name< std::complex< double > > #

The c128 entry.

var const char * dot_name #

Dot-product partial-sum kernel name per element type (serves dot, vdot and inner — identical for the real elements this library supports).

var const char * dot_name< float > #

The f32 entry.

var const char * dot_name< double > #

The f64 entry.

var const char * dot_name< std::complex< float > > #

The c64 entry.

var const char * dot_name< std::complex< double > > #

The c128 entry.

var const char * vdot_name #

Conjugating dot (vdot) kernel name — COMPLEX elements only (real vdot is bilinear and shares the dot kernel).

var const char * vdot_name< std::complex< float > > #

The c64 entry.

var const char * vdot_name< std::complex< double > > #

The c128 entry.

var const char * trace_name #

Trace partial-sum kernel name per element type.

var const char * trace_name< float > #

The f32 entry.

var const char * trace_name< double > #

The f64 entry.

var const char * trace_name< std::complex< float > > #

The c64 entry.

var const char * trace_name< std::complex< double > > #

The c128 entry.

var const char * dot2_name #

Two-stage dot partial kernel names (G workgroups x 256, groupshared tree-reduce — the large-n path; the routine picks stage-1 vs stage-2 by size).

var const char * dot2_name< float > #

The f32 entry.

var const char * dot2_name< double > #

The f64 entry.

var const char * dot2_name< std::complex< float > > #

The c64 entry.

var const char * dot2_name< std::complex< double > > #

The c128 entry.

var const char * vdot2_name #

Two-stage conjugating vdot partial kernel name — complex elements only.

var const char * vdot2_name< std::complex< float > > #

The c64 entry.

var const char * vdot2_name< std::complex< double > > #

The c128 entry.

var const char * sum2_name #

Two-stage sum partial kernel name (the large-n reduction path).

var const char * sum2_name< float > #

The f32 entry.

var const char * sum2_name< double > #

The f64 entry.

var const char * finalize_name #

On-device partial finalizer (one 256-thread group tree-sums G partials into out[0]).

var const char * finalize_name< float > #

The f32 entry.

var const char * finalize_name< double > #

The f64 entry.

var const char * finalize_name< std::complex< float > > #

The c64 entry.

var const char * finalize_name< std::complex< double > > #

The c128 entry.

var std::size_t kTwoStageMin #

The two-stage reduction geometry: n above this uses the G-group tree kernels; G is capped.

var std::uint32_t kMaxGroups #

The cap on tree-reducing workgroups G in the two-stage reduction geometry.

var const char * sum_name #

Sum partial-sum kernel name per element type (the deterministic reduction contract).

var const char * sum_name< float > #

The f32 entry.

var const char * sum_name< double > #

The f64 entry.

var const char * axpy_name #

Fused axpy (out = α·x + y) kernel name per element type.

var const char * axpy_name< float > #

The f32 entry.

var const char * axpy_name< double > #

The f64 entry.

var const char * im2col2d_name #

Batched 2-D im2col gather kernel name per element type (real elements — the conv-support tier; dims = {B, C, H, W, KH, KW, OH, OW, stride, pad}).

var const char * im2col2d_name< float > #

The f32 entry.

var const char * im2col2d_name< double > #

The f64 entry.

var const char * col2im2d_name #

Batched 2-D col2im kernel name per element type (the gather-form adjoint; same dims).

var const char * col2im2d_name< float > #

The f32 entry.

var const char * col2im2d_name< double > #

The f64 entry.

var const char * conv_bias_act_name #

Fused conv forward epilogue (bias + activation + layout transpose) kernel name per element type; dims = {B, F, OO, act} with act 0 = identity, 1 = relu, 2 = tanh, 3 = sigmoid.

var const char * conv_bias_act_name< float > #

The f32 entry.

var const char * conv_bias_act_name< double > #

The f64 entry.

var const char * conv_act_grad_name #

Fused conv backward epilogue (chain rule from the output + layout transpose) kernel name per element type; same dims as conv_bias_act.

var const char * conv_act_grad_name< float > #

The f32 entry.

var const char * conv_act_grad_name< double > #

The f64 entry.

var const char *const * ew_names #

The array⊗array binary kernel-name table for element T, indexed by EwOp.

var const char * ew_names_f32[4] #

The f32 array⊗array table (EwOp order).

var const char * ew_names_f64[4] #

The f64 array⊗array table (EwOp order).

var const char *const * ew_names< float > #

The f32 entry.

var const char *const * ew_names< double > #

The f64 entry.

var const char * ews_names_f32[4] #

The f32 array⊗scalar table (EwOp order).

var const char * ews_names_f64[4] #

The f64 array⊗scalar table (EwOp order).

var const char *const * ews_names #

The array⊗scalar binary kernel-name table for element T, indexed by EwOp.

var const char *const * ews_names< float > #

The f32 entry.

var const char *const * ews_names< double > #

The f64 entry.

var const char * fill_name #

Constant-fill (out[i] = s) — the factories' device-side zeros/ones/full (no host staging vector, no PCIe upload).

Real elements only, mirroring the ews family.

var const char * fill_name< float > #

The f32 entry.

var const char * fill_name< double > #

The f64 entry.

var const char * ewu_names_f32[5] #

The f32 unary table (EwFn order).

var const char * ewu_names_f64[5] #

The f64 unary table (EwFn order; exp/log dispatch is host-evaluated — see elementwise.hpp).

var const char *const * ewu_names #

The unary kernel-name table for element T, indexed by EwFn.

var const char *const * ewu_names< float > #

The f32 entry.

var const char *const * ewu_names< double > #

The f64 entry.

var bool is_cplx_v #

is_cplx_v<T>: local complex detection for the stand-ins (mirrors the kernels' CONJ seam).

var bool is_cplx_v< std::complex< U > > #

The complex case.

Types

enum std::uint32_t EwOp #

Elementwise binary kernel names per element type, indexed by the shared operator enum: the array⊗array family (ew_*) and the array⊗scalar family (ews_*, with the swap flag for the reversed s−a / s÷a forms).

One table per family keeps every dispatch a straight lookup.

enum std::uint32_t EwFn #

Elementwise unary kernel names per element type, indexed by the shared enum.