Composable kernel abstraction for kernel fusion.
This module provides a high-level abstraction for composable GPU kernels. Instead of writing imperative procedures, we treat kernels as composable functions (Input → Output), enabling kernel fusion optimizations.
Key benefits:
- Compose operations with monadic bind (>>=) and sequencing (>>)
- Fuse multiple operations into single shader pass
- Reduce global memory traffic
- Type-safe workgroup size tracking
Example: -- Fuse: Load → Multiply → Add → ReLU → Store into single pass fusedKernel : Kernel 256 1 1 (Exp (.scalar .u32)) Unit fusedKernel = loadVec inputPtr |> andThen (mapK (· * Exp.litF32 2.0)) |> andThen (mapK (· + Exp.litF32 1.0)) |> andThen (mapK relu) |> andThen (storeVec outputPtr)
ShaderM monad - builds up statement lists while computing a value. This is a state monad that accumulates statements.
Equations
Instances For
A composable kernel function running on a specific workgroup size.
Type parameters: wX, wY, wZ: Workgroup dimensions (natural numbers) i: Input type (e.g., Exp (.scalar .f32), or tuples) o: Output type
This abstraction allows us to compose operations and perform kernel fusion. Multiple operations can be fused into a single shader pass, reducing global memory roundtrips.
- unKernel : i → ShaderM o
Instances For
Identity kernel: passes input through unchanged
Equations
- Hesper.WGSL.Kernel.id = { unKernel := fun (x : α) => pure x }
Instances For
Compose two kernels: g ∘ f means "f first, then g" The composition is performed in the ShaderM monad, so side effects (like memory operations) are properly sequenced.
Instances For
Infix operator for kernel composition (like >>> in Haskell Category)
Equations
- One or more equations did not get rendered due to their size.
Instances For
Lift a pure DSL expression transformation into a Kernel.
This allows you to turn any pure expression transformation (like (· * 2.0) or (· + 1.0)) into a composable kernel.
Example: mapK (· * Exp.litF32 2.0) -- Multiply by 2 mapK (· + Exp.litF32 1.0) -- Add 1 mapK relu -- Apply ReLU
These can be composed: mapK (· * 2.0) |> mapK (· + 1.0) |> mapK relu
Equations
- Hesper.WGSL.mapK f = { unKernel := fun (x : Hesper.WGSL.Exp ty) => pure (f x) }
Instances For
Emit a statement (side effect) in a kernel. This adds the statement to the accumulated list.
Equations
Instances For
Load operation: reads from a buffer at given index.
Input: index expression Output: loaded value
Note: The buffer must be an array type. The size parameter n is for type checking.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Store operation: writes to a buffer at given index.
Input: (index, value) pair Output: unit (side effect only)
Equations
- One or more equations did not get rendered due to their size.
Instances For
Pair an expression with an index for storage
Equations
- Hesper.WGSL.pairWithIndex idx = { unKernel := fun (val : Hesper.WGSL.Exp ty) => pure (idx, val) }
Instances For
Execute a kernel and extract the generated statements.
This runs the kernel computation and returns both the result value and the list of statements that were generated.
Equations
Instances For
Execute a kernel and return only the statements (for side-effect kernels)
Equations
- Hesper.WGSL.execKernel k input = match Hesper.WGSL.runKernel k input with | (fst, stmts) => stmts