Documentation

Hesper.WGSL.Monad

Shader Monad for Imperative Shader Construction #

The ShaderM monad provides an imperative interface for building WGSL compute shaders. It tracks:

Usage pattern:

def myShader : ShaderM Unit := do
  let gid ← globalId
  let idx := swizzleX gid

  -- Declare buffers
  input ← declareInputBuffer "input" (.array (.scalar .f32) 1024)
  output ← declareOutputBuffer "output" (.array (.scalar .f32) 1024)

  -- Read, compute, write
  val ← readBuffer input idx
  let result := val * litF32 2.0
  writeBuffer output idx result

Buffer access mode for storage buffers

Instances For
    Equations
    • One or more equations did not get rendered due to their size.
    Instances For

      Shader Construction State

      • stmts : List Stmt
      • varCounter : Nat
      • sharedVars : List (String × WGSLType)
      • needsSubgroups : Bool
      • maxnreg : Option Nat

        Optional __launch_bounds__ analogue: caps register allocation per thread. CUDA backend lowers to PTX .maxnreg. None = ptxas default (which may pick a higher count and reduce occupancy).

      • minnctapersm : Option Nat

        Optional minimum CTAs per SM hint. Combined with maxntid (derived from workgroup size), this is the full __launch_bounds__(threads, minCtas) equivalent — ptxas uses it to size register allocation.

      Instances For
        @[reducible, inline]

        The Shader Monad

        Equations
        Instances For

          Initial state for shader construction

          Equations
          Instances For

            Run a shader computation and extract the result and final state

            Equations
            Instances For

              Run a shader computation and extract only the final state

              Equations
              Instances For

                Emit a statement to the shader body

                Equations
                • One or more equations did not get rendered due to their size.
                Instances For

                  Generate a fresh variable name with given prefix

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For

                    Capture statements from a monadic action (for control flow)

                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For

                      Declare a private variable with fresh name

                      Equations
                      Instances For

                        Declare a named private variable

                        Equations
                        Instances For

                          Declare a mutable variable with fresh name, returning both name and typed expression. This avoids manually constructing Exp.var name and passing raw string literals.

                          Equations
                          • One or more equations did not get rendered due to their size.
                          Instances For

                            Bind a sub-expression to a named PTX register and return an Exp.var referring to it. Use this when an Exp is referenced multiple times inside an unrolled loop body or fan-out: without it, each reference is inlined as a fresh AST traversal and the CodeGen emits the same arithmetic at every use site (causing the 17× instruction inflation seen in V9 vs llama.cpp). Wrapping the value with let' materialises it as one PTX register that all uses share.

                            Example:

                            let kRowBase ← ShaderM.let' (.scalar .u32) (Exp.add base offset)
                            for pk in [0:4] do
                              -- `kRowBase` is a single Exp.var, so the four iterations all
                              -- read the same register instead of recomputing `base + offset`.
                              let idx := Exp.add kRowBase (Exp.litU32 (pk * 32))
                              ...
                            

                            Functionally equivalent to do let n ← var ty e; pure (Exp.var n), but the intent is clearer at the call site.

                            Equations
                            • One or more equations did not get rendered due to their size.
                            Instances For

                              Declare shared memory (workgroup-scoped) with fresh name

                              Equations
                              • One or more equations did not get rendered due to their size.
                              Instances For

                                Declare named shared memory

                                Equations
                                • One or more equations did not get rendered due to their size.
                                Instances For
                                  def Hesper.WGSL.Monad.ShaderM.assign {ty : WGSLType} (varName : String) (expr : Exp ty) :

                                  Assign expression to variable

                                  Equations
                                  Instances For

                                    Assign to array index

                                    Equations
                                    Instances For

                                      If-then-else statement

                                      Equations
                                      • One or more equations did not get rendered due to their size.
                                      Instances For

                                        While loop - implemented as for loop with always-true condition

                                        Equations
                                        Instances For

                                          For loop (start to end, incrementing by step) Builds proper WGSL for loop: for (var i: u32 = start; i < end; i = i + step)

                                          Equations
                                          • One or more equations did not get rendered due to their size.
                                          Instances For
                                            @[inline]

                                            Compile-time unrolled loop: emits n copies of the body inline, with i bound to a Lean Nat (0, 1, ..., n-1). Use when iteration count is statically known and the unroll is desired (eg. dot-product over a fixed dim count, sub-warp partition iters).

                                            The Nat i is a meta value — to use it in an Exp context, lift via Exp.litU32 i or simply (i : Exp _) (the Exp OfNat instance).

                                            Equivalent to writing for i in [0:n] do body i, but the helper name documents intent: "this is meta-time unrolled, not a runtime loop". Mirrors CUDA C++ #pragma unroll for (int i = 0; i < N; ++i).

                                            For runtime loops use ShaderM.loop (or its alias runtimeFor).

                                            Equations
                                            Instances For

                                              LICM helpers (loop invariant code motion) #

                                              Approximate "free variable" check: serialise an Exp via Exp.toWGSL and look for the variable name as a whole token (name not preceded/followed by an alphanumeric or underscore). This is correct for ShaderM-emitted names because they're unique fresh names like v3 / i7 — there's no risk of accidental match against a substring of another identifier.

                                              Why string-match rather than a structural traversal: Exp has 50+ constructors and many of them hold sub-Exps. A structural Exp.containsVar would be a lot of pattern matching that would have to stay in sync as new Exp cases are added. toWGSL is the existing single source of truth that walks every sub-Exp; reusing it for the free-var check costs O(n) extra string work per stmt but is robust to Exp evolution. In practice the runtime impact is negligible because LICM only runs at kernel-emission time, not on the GPU.

                                              Higher-order loop: pass loop variable as Exp. Now applies LICM: varDecls in the body whose init expression doesn't reference the loop variable (or any other inner-loop binding) are hoisted before the for-loop. This automates the manual let'-outside-the-loop pattern that V9 / earlier kernels used by hand.

                                              Usage: loop start end step fun i => do { ... use i ... }

                                              Equations
                                              • One or more equations did not get rendered due to their size.
                                              Instances For

                                                Variant of loop that applies LICM to hoist varDecls whose init is loop-invariant out of the for-loop. Use only when the body contains no shared-memory writes that other iterations read, no inter-iteration carries via externally-declared mutable vars beyond those captured by assign, and only varDecl (no if/inner for/barrier) sites that you want hoisted.

                                                Semantics-changing in subtle ways — verify bit-parity before merging a kernel that uses this.

                                                Equations
                                                • One or more equations did not get rendered due to their size.
                                                Instances For
                                                  @[inline]

                                                  Runtime loop alias for loop, named to pair with unrollFor so the meta-vs-runtime distinction is explicit at the call site:

                                                  ShaderM.unrollFor 8 fun i => ...               -- meta-time, 8 inline copies
                                                  ShaderM.runtimeFor 0 cacheLen 1 fun i => ...   -- runtime for-loop
                                                  

                                                  Mirrors CUDA C++ for (int i = 0; ...) (no #pragma unroll).

                                                  Equations
                                                  Instances For

                                                    Block scope: emits { ... body ... } so var declared inside the body is block-scoped in WGSL, allowing Naga/Tint/Vulkan-driver register allocator to reuse the physical register once the scope exits.

                                                    This is the analog of CUDA { ... } block scope for register-pressure reduction. For example, when a temporary is needed only inside a hot inner loop iteration, putting it in a scope instead of at function level lets the compiler reuse its register slot afterwards.

                                                    Usage:

                                                    ShaderM.scope do
                                                      let tmp ← ShaderM.var (.scalar .f32) (Exp.litF32 0.0)
                                                      -- ... use tmp ...
                                                      -- tmp's register is released at end of scope
                                                    

                                                    Note: Lean-side let bindings to tmp outside the do-block can still refer to the var name string, but reading from it via Exp.var after scope-exit is undefined behavior — the WGSL register is gone. Discipline: only use tmp inside the scope body.

                                                    Equations
                                                    Instances For
                                                      @[inline]

                                                      unrollFor + per-iter scope. Each of the n inline copies of the body lives in its own { ... } block, so any ShaderM.var declared inside is block-scoped and the WGSL→PTX backend can reuse the physical register across iters.

                                                      Collapses the V8/V9/V11 idiom

                                                      for i in [0:n] do ShaderM.scope do
                                                        ...
                                                      

                                                      into

                                                      ShaderM.unrollForScoped n fun i => do
                                                        ...
                                                      

                                                      Mirrors CUDA C++ #pragma unroll for (int i = ...) where each unrolled body is implicitly its own register-allocation scope.

                                                      Equations
                                                      Instances For

                                                        Warp-level barrier (CUDA __syncwarp()). PTX backend emits the cheap bar.warp.sync 0xFFFFFFFF; WGSL backend falls back to workgroupBarrier(). Use when only intra-warp ordering is needed — eg. between Phase 1 (KQ dot) and Phase 2a (cross-sub-warp max reduce) in the flash-attn vec kernel where all 32 lanes of a warp must finish writing before reading.

                                                        Equations
                                                        Instances For

                                                          Cap per-thread register usage at n. ptxas will spill to local memory if it would otherwise exceed this. Used for occupancy tuning — fewer registers per thread → more blocks per SM. CUDA-only (lowers to PTX .maxnreg). WGSL backend ignores.

                                                          Equations
                                                          • One or more equations did not get rendered due to their size.
                                                          Instances For

                                                            Promise that ≥ n CTAs will run per SM. Combined with the workgroup size (which gives ptxas .maxntid), this is the __launch_bounds__ equivalent — lets ptxas pick a register budget that fits N blocks.

                                                            Equations
                                                            • One or more equations did not get rendered due to their size.
                                                            Instances For

                                                              Pure: raw u64 pointer to element idx of a global buffer. elemSize is the byte size of one element (typically 4 for u32/f32). Used as the global-address operand for cpAsync. CUDA-only.

                                                              Equations
                                                              Instances For

                                                                Pure: raw u32 byte-address of element idx in a shared-memory array. elemSize must be 4, 8, or 16. Used as the smem-address operand for cpAsync. CUDA-only.

                                                                Equations
                                                                Instances For

                                                                  ── cp.async (sm_80+) ── Issue an async global→shared memory copy of bytes bytes (must be 4, 8, or 16). Non-blocking — completion synchronised via cpAsyncCommit + cpAsyncWait. Used by llama.cpp's MMQ pipeline to overlap the next K-iteration's load with the current K-iteration's compute. WGSL backend has no equivalent.

                                                                  Equations
                                                                  Instances For

                                                                    cp.async.ca cache-all variant — supports bytes ∈ {4, 8, 16}. Slower per byte than .cg for 16-byte transfers but the only option for narrower transfers.

                                                                    Equations
                                                                    Instances For

                                                                      cp.async.wait_group N — block this thread until all but the most recent N committed groups have completed. N=0 waits for all.

                                                                      Equations
                                                                      Instances For

                                                                        Thread index helpers (CUDA-style shortcuts) #

                                                                        These mirror CUDA's threadIdx.x, blockIdx.x, etc. for the common 1D case so kernel code reads close to the CUDA original. The vec3 versions (localId, workgroupId) are still available when 2D/3D index components are needed.

                                                                        @[inline]

                                                                        threadIdx.x — local invocation X coordinate (= "tid" in CUDA kernels).

                                                                        Equations
                                                                        Instances For
                                                                          @[inline]

                                                                          blockIdx.x — workgroup X coordinate.

                                                                          Equations
                                                                          Instances For

                                                                            Warp / sub-warp index decomposition #

                                                                            NVIDIA warps are 32 lanes. These helpers compute laneId (tid & 31) and warpId (tid >>> 5) once and return them as Exp values, so kernel code that uses them many times shares one PTX register. The inner expressions are simple enough that lean codegen folds the extraction efficiently — no let' needed at the use site.

                                                                            Sub-warp partition (used in V8/V11 attention vec kernels) splits a warp into N-lane groups via subWarpSplit n.

                                                                            @[inline]

                                                                            Lane index within the warp (0..31). Equivalent to CUDA's threadIdx.x & 31 when threads are 1D, or threadIdx.x % WARP_SIZE.

                                                                            Equations
                                                                            Instances For
                                                                              @[inline]

                                                                              Warp index within the workgroup. Equivalent to CUDA's threadIdx.x / WARP_SIZE (= >> 5). For 2D blocks where threadIdx.y selects warps, use tidY directly.

                                                                              Equations
                                                                              Instances For
                                                                                @[inline]

                                                                                Split a warp's lane into (subWarp, subLane) for nthreads_KQ-style sub-warp partitioning where each sub-warp handles a different K position in parallel. Returns (laneId / n, laneId % n).

                                                                                Example (V11 sub-warp partition with n = 8):

                                                                                let (sw, sl) ← ShaderM.subWarpSplit 8
                                                                                -- sw ∈ [0, 4), sl ∈ [0, 8)
                                                                                let kPos := warpBase + sw * 8 + iKQ0    -- this sub-warp's K
                                                                                let dimBase := sl * 32                  -- this lane's D slice
                                                                                

                                                                                Mirrors llama.cpp's (threadIdx.x & ~(nthreads_KQ-1), threadIdx.x % nthreads_KQ).

                                                                                Equations
                                                                                • One or more equations did not get rendered due to their size.
                                                                                Instances For

                                                                                  Warp-level reductions #

                                                                                  warpReduceSum n e reduces e across the n-lane group within the warp:

                                                                                  After the call, every lane in the n-lane group holds the same reduced value. Mirrors llama.cpp's warp_reduce_sum<nthreads> template.

                                                                                  Example (V11-like sub-warp dot product):

                                                                                  let partialVar ← ShaderM.mutVar (.scalar .f32) 0
                                                                                  ShaderM.unrollFor dimsPerLane fun k => partialVar +↦ q[k]! * kVec[k]!
                                                                                  let sum ← ShaderM.warpReduceSum 8 partialVar.read   -- 3 shfl
                                                                                  

                                                                                  Sum-reduce e across an n-lane group within the warp. Uses Exp.subgroupAdd when n = 32, otherwise emits log2(n) butterfly shuffles via Exp.subgroupShuffleXor.

                                                                                  Pre: n is a power of 2 and 1 ≤ n ≤ 32.

                                                                                  Each lane in the n-lane group receives the same sum. Cost: log2(n) shfl + n−1 add per lane (so a sub-warp reduce of 8 lanes is 3 shfl

                                                                                  • 3 add — half the cost of the full 32-lane reduce, useful when only 8-lane groups need to coordinate).
                                                                                  Equations
                                                                                  • One or more equations did not get rendered due to their size.
                                                                                  Instances For

                                                                                    Max-reduce variant: warpReduceMax n e. Same shfl-xor butterfly, using Exp.max instead of +. After the call, every lane in the group holds the same max.

                                                                                    Equations
                                                                                    • One or more equations did not get rendered due to their size.
                                                                                    Instances For

                                                                                      One step of online softmax (Milakov & Gimelshein 2018 / FlashAttention). Given the running max kqMax, running sum kqSum, and a new score kqScore, computes:

                                                                                      kqMaxNew  = max(kqMax, kqScore)
                                                                                      scale     = exp(kqMax - kqMaxNew)        -- multiplier for old VKQ accumulator
                                                                                      kqExp     = exp(kqScore - kqMaxNew)      -- per-thread weight for current K
                                                                                      kqSumNew  = kqSum * scale + kqExp
                                                                                      kqMax := kqMaxNew                        -- updated in-place
                                                                                      kqSum := kqSumNew                        -- updated in-place
                                                                                      

                                                                                      Returns (kqMaxNew, scale, kqExp). The caller rescales their VKQ accumulators by scale and accumulates kqExp * V for this K position.

                                                                                      kqMaxName/kqSumName are the names of the running registers so we can assign them in place. The new max is also returned as an Exp so the caller can use it without an extra Exp.var lookup.

                                                                                      Mirrors the inner-loop accumulation in llama.cpp's flash_attn_ext_vec (lines 273, 287-291 in fattn-vec.cuh).

                                                                                      Equations
                                                                                      • One or more equations did not get rendered due to their size.
                                                                                      Instances For

                                                                                        Read from a global storage buffer at index Note: You need to provide the element type explicitly

                                                                                        Equations
                                                                                        Instances For

                                                                                          Read a single byte (zero-extended to u32) from a buffer declared as array<u32, n>, addressed by byte index. Lowers to one ld.global.u8 on CUDA; emulated via u32-load+shift+mask on WGSL. Essential for Q6_K scale reads (avoids issuing a full u32 load per byte).

                                                                                          Equations
                                                                                          Instances For

                                                                                            Read a halfword (16 bits, zero-extended to u32) from a buffer declared as array<u32, n>, addressed by byte index. Lowers to ld.global.u16 on CUDA. Use for fp16 block scales.

                                                                                            Equations
                                                                                            Instances For

                                                                                              128-bit (4× u32) wide read from a buffer declared array<u32, n>, addressed by u32 index. The starting index must be 4-aligned and the buffer pointer 16-byte aligned (caller's responsibility — typical callers iterate by pk * 4).

                                                                                              On CUDA this lowers to a single ld.global.nc.v4.u32 instruction (one MIO op delivering 16 bytes), 4× more efficient than four scalar ld.global.u32 reads in MIO-pipe-saturated kernels (FlashAttn V11). On WGSL it emulates as four scalar reads.

                                                                                              Returns four Exp (.scalar .u32) referring to fresh declared vars. Each value can be used independently with Exp.unpack2x16float etc.

                                                                                              Equations
                                                                                              • One or more equations did not get rendered due to their size.
                                                                                              Instances For

                                                                                                128-bit (4× f32) wide read from shared memory. f32Idx must be 4-aligned. CUDA lowers to one ld.shared.v4.f32; WGSL emulates as four scalar reads.

                                                                                                Used to relieve MIO-pipe saturation on shared-memory traffic (FlashAttn V11 partial aggregation: 4× LDS instruction count reduction).

                                                                                                Equations
                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                Instances For

                                                                                                  Write to a global storage buffer at index

                                                                                                  Equations
                                                                                                  Instances For

                                                                                                    Read from workgroup shared memory at index

                                                                                                    Equations
                                                                                                    Instances For

                                                                                                      Write to workgroup shared memory at index

                                                                                                      Equations
                                                                                                      Instances For

                                                                                                        Declare an input buffer (read-only) with automatic binding assignment

                                                                                                        Equations
                                                                                                        • One or more equations did not get rendered due to their size.
                                                                                                        Instances For

                                                                                                          Declare an output buffer (read-write) with automatic binding assignment

                                                                                                          Equations
                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                          Instances For

                                                                                                            Declare a storage buffer with explicit access mode

                                                                                                            Equations
                                                                                                            • One or more equations did not get rendered due to their size.
                                                                                                            Instances For

                                                                                                              Declare a read-only storage buffer.

                                                                                                              Semantically equivalent to declareInputBuffer on WGSL, but on CUDA this emits ld.global.nc.* (the read-only L1/tex cache hint, aka __ldg). Use for weight matrices and other buffers the kernel never writes to. It is a logical error to call writeBuffer on the returned name.

                                                                                                              Equations
                                                                                                              • One or more equations did not get rendered due to their size.
                                                                                                              Instances For

                                                                                                                Declare a read-only buffer array binding: N separate runtime-sized storage buffers addressable by runtime layer index. The host side must pass a device-pointer-table — N × 8 bytes holding each layer's CUdeviceptr — as the kernel argument bound to name. Inside the kernel, read elements with readBufferArray name layerIdx elemIdx.

                                                                                                                This is the primitive that lets a single kernel iterate over all 42 transformer layers, collapsing 42 dispatches into 1. The existing per-layer kernels remain; use bufferArray only when a kernel actually wants to fuse across layers.

                                                                                                                Equations
                                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                                Instances For
                                                                                                                  def Hesper.WGSL.Monad.ShaderM.readBufferArray {elemTy : WGSLType} {n : Nat} (name : String) (bufIdx elemIdx : Exp (WGSLType.scalar ScalarType.u32)) :
                                                                                                                  ShaderM (Exp elemTy)

                                                                                                                  Read element elemIdx from the bufIdx-th buffer of a bufferArray. Emits a single-indirection load via the pointer table.

                                                                                                                  Equations
                                                                                                                  Instances For

                                                                                                                    Write value to arr[bufIdx][elemIdx] where arr is a bufferArray.

                                                                                                                    Equations
                                                                                                                    Instances For
                                                                                                                      def Hesper.WGSL.Monad.ShaderM.staticFor {α β : Type} (xs : List α) (f : αShaderM β) :

                                                                                                                      Compile-time loop for unrolling (Haskell-side loop, not WGSL loop)

                                                                                                                      Equations
                                                                                                                      Instances For

                                                                                                                        Declare an array of subgroup_matrix_left matrices with initialization

                                                                                                                        Equations
                                                                                                                        • One or more equations did not get rendered due to their size.
                                                                                                                        Instances For

                                                                                                                          Declare an array of subgroup_matrix_right matrices with initialization

                                                                                                                          Equations
                                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                                          Instances For

                                                                                                                            Declare an array of subgroup_matrix_result matrices with initialization

                                                                                                                            Equations
                                                                                                                            • One or more equations did not get rendered due to their size.
                                                                                                                            Instances For
                                                                                                                              def Hesper.WGSL.Monad.ShaderM.loadMatrixLeft {st : ScalarType} {m k : Nat} (arrayName : String) (index : Nat) (bufferName : String) (offset stride : Exp (WGSLType.scalar ScalarType.u32)) :

                                                                                                                              Load subgroup_matrix_left from buffer

                                                                                                                              Example: Ax[i] = subgroupMatrixLoad<subgroup_matrix_left<f32,8,8>>(&A, offset, false, stride)

                                                                                                                              Equations
                                                                                                                              • One or more equations did not get rendered due to their size.
                                                                                                                              Instances For
                                                                                                                                def Hesper.WGSL.Monad.ShaderM.loadMatrixRight {st : ScalarType} {k n : Nat} (arrayName : String) (index : Nat) (bufferName : String) (offset stride : Exp (WGSLType.scalar ScalarType.u32)) :

                                                                                                                                Load subgroup_matrix_right from buffer

                                                                                                                                Equations
                                                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                                                Instances For
                                                                                                                                  def Hesper.WGSL.Monad.ShaderM.loadMatrixRightT {st : ScalarType} {k n : Nat} (arrayName : String) (index : Nat) (bufferName : String) (offset : Exp (WGSLType.scalar ScalarType.u32)) (colMajor : Bool) (stride : Exp (WGSLType.scalar ScalarType.u32)) :

                                                                                                                                  loadMatrixRight with an explicit column-major flag — for loading a right (k×n) fragment DIRECTLY from a storage buffer laid out n-major (e.g. Bᵀ [N,K] row-major: element (k,n) at b[n·K+k] ⇒ colMajor=true, stride=K). Buffer-space subgroupMatrixLoad is supported by the pinned May Tint (verified; lowers to device simdgroup_load).

                                                                                                                                  Equations
                                                                                                                                  • One or more equations did not get rendered due to their size.
                                                                                                                                  Instances For
                                                                                                                                    def Hesper.WGSL.Monad.ShaderM.matrixMultiplyAccumulate {st : ScalarType} {m k n : Nat} (resultArrayName : String) (resultIndex : Nat) (leftArrayName : String) (leftIndex : Nat) (rightArrayName : String) (rightIndex : Nat) :

                                                                                                                                    Perform matrix multiply-accumulate: acc = a * b + acc

                                                                                                                                    Example: accxx[idx] = subgroupMatrixMultiplyAccumulate(Ax[i], Bx[j], accxx[idx])

                                                                                                                                    Equations
                                                                                                                                    • One or more equations did not get rendered due to their size.
                                                                                                                                    Instances For
                                                                                                                                      def Hesper.WGSL.Monad.ShaderM.matrixMultiplyAccumulateMixed {inSt outSt : ScalarType} {m k n : Nat} (resultArrayName : String) (resultIndex : Nat) (leftArrayName : String) (leftIndex : Nat) (rightArrayName : String) (rightIndex : Nat) :

                                                                                                                                      Mixed-precision variant of matrixMultiplyAccumulate: A and B use inSt, C / D use outSt. This matches NVIDIA cooperative matrix's native (f16, f16) → f32 config.

                                                                                                                                      Equations
                                                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                                                      Instances For
                                                                                                                                        def Hesper.WGSL.Monad.ShaderM.storeMatrixResult {st : ScalarType} {m n : Nat} (arrayName : String) (index : Nat) (bufferName : String) (offset stride : Exp (WGSLType.scalar ScalarType.u32)) :

                                                                                                                                        Store subgroup_matrix_result to buffer

                                                                                                                                        Example: subgroupMatrixStore(&C, offset, accxx[idx], false, stride)

                                                                                                                                        Equations
                                                                                                                                        • One or more equations did not get rendered due to their size.
                                                                                                                                        Instances For

                                                                                                                                          Fragment-as-local-variable helpers (real-CUDA-style WMMA) #

                                                                                                                                          The array-of-fragments helpers above (loadMatrixLeft, matrixMultiplyAccumulate, storeMatrixResult) match WGSL's array<subgroup_matrix_left, N> model — nice for blocked algorithms but awkward to lower to PTX since fragments live in registers, not memory. The helpers below match the more direct nvcuda::wmma::fragment a_frag; load_matrix_sync(a_frag, ...); style: each fragment is a single named variable, with no array indirection. This is the recommended path for new WMMA kernels — the array helpers remain for backward-compat and WGSL-targeted code.

                                                                                                                                          Declare a left fragment (subgroup_matrix_left<st, m, k>) bound to a name, initialized via a load from bufferName at byte-offset offset with row-major stride (in elements).

                                                                                                                                          Equations
                                                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                                                          Instances For

                                                                                                                                            Declare a right fragment, loaded col-major (the WGSL subgroupMatrixLoadRight instruction, which lowers to PTX wmma.load.b...col.f16).

                                                                                                                                            Equations
                                                                                                                                            • One or more equations did not get rendered due to their size.
                                                                                                                                            Instances For

                                                                                                                                              Declare a result fragment initialized to zero. Maps to PTX mov.f32 %f0..7, 0; for the f32 case (8 regs).

                                                                                                                                              Equations
                                                                                                                                              • One or more equations did not get rendered due to their size.
                                                                                                                                              Instances For

                                                                                                                                                cName ← cName * (a × b). Uses the existing Exp.subgroupMatrix- MultiplyAccumulate; lowers to one wmma.mma.sync instruction and rebinds cName to the result fragment.

                                                                                                                                                Equations
                                                                                                                                                • One or more equations did not get rendered due to their size.
                                                                                                                                                Instances For

                                                                                                                                                  Store a result fragment to a buffer at byte-offset offset with row-major stride (in elements).

                                                                                                                                                  Equations
                                                                                                                                                  • One or more equations did not get rendered due to their size.
                                                                                                                                                  Instances For

                                                                                                                                                    Static loop unrolling for matrix operations

                                                                                                                                                    Executes an action for each index in the range [0, count)

                                                                                                                                                    Equations
                                                                                                                                                    Instances For

                                                                                                                                                      Static nested loop for 2D iteration

                                                                                                                                                      Equations
                                                                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                                                                      Instances For

                                                                                                                                                        Typed mutable variables #

                                                                                                                                                        MutVar ty wraps a private (PTX-register / WGSL var) variable with its type carried in Lean. This closes the second cognitive gap from porting CUDA C++ — operator overloading in Step 1 still needed (Exp.var name : Exp _) type annotations everywhere. With MutVar, v.read + x and v +↦ x type-check directly because read returns a typed Exp ty.

                                                                                                                                                        Idiomatic use:

                                                                                                                                                        let acc ← ShaderM.mutVar (.scalar .f32) 0
                                                                                                                                                        for k in [0:8] do
                                                                                                                                                          acc +↦ qVec[k]! * kVec[k]!     -- in-place +=
                                                                                                                                                        let final := acc.read
                                                                                                                                                        

                                                                                                                                                        Mutable shader-side variable carrying its type in Lean. Construct via ShaderM.mutVar — never by hand (the contained name must be one emitted by ShaderM.var so PTX/WGSL codegen sees a declaration).

                                                                                                                                                        Instances For
                                                                                                                                                          Equations
                                                                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                                                                          Instances For
                                                                                                                                                            @[inline]

                                                                                                                                                            Read the current value as a typed Exp ty.

                                                                                                                                                            Equations
                                                                                                                                                            Instances For
                                                                                                                                                              @[inline]

                                                                                                                                                              Overwrite the variable with x.

                                                                                                                                                              Equations
                                                                                                                                                              Instances For
                                                                                                                                                                @[inline]
                                                                                                                                                                def Hesper.WGSL.Monad.MutVar.addAssign {ty : WGSLType} (v : MutVar ty) [HAdd (Exp ty) (Exp ty) (Exp ty)] (x : Exp ty) :

                                                                                                                                                                In-place add: v += x. Sugar for v.write (v.read + x).

                                                                                                                                                                Equations
                                                                                                                                                                Instances For
                                                                                                                                                                  @[inline]
                                                                                                                                                                  def Hesper.WGSL.Monad.MutVar.mulAssign {ty : WGSLType} (v : MutVar ty) [HMul (Exp ty) (Exp ty) (Exp ty)] (x : Exp ty) :

                                                                                                                                                                  In-place multiply: v *= x.

                                                                                                                                                                  Equations
                                                                                                                                                                  Instances For
                                                                                                                                                                    @[inline]
                                                                                                                                                                    def Hesper.WGSL.Monad.MutVar.subAssign {ty : WGSLType} (v : MutVar ty) [HSub (Exp ty) (Exp ty) (Exp ty)] (x : Exp ty) :

                                                                                                                                                                    In-place subtract: v -= x.

                                                                                                                                                                    Equations
                                                                                                                                                                    Instances For

                                                                                                                                                                      Mutating-add operator. v +↦ xMutVar.addAssign v x.

                                                                                                                                                                      Equations
                                                                                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                                                                                      Instances For

                                                                                                                                                                        Mutating-multiply operator.

                                                                                                                                                                        Equations
                                                                                                                                                                        • One or more equations did not get rendered due to their size.
                                                                                                                                                                        Instances For

                                                                                                                                                                          Mutating-write operator (≡ MutVar.write). v ↦= x.

                                                                                                                                                                          Equations
                                                                                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                                                                                          Instances For

                                                                                                                                                                            Declare a typed mutable variable. Use v.read / v.write / v +↦ x / v ↦= x. The successor to ShaderM.var.

                                                                                                                                                                            Example:

                                                                                                                                                                            let acc ← ShaderM.mutVar (.scalar .f32) 0
                                                                                                                                                                            for k in [0:dimsPerLane] do
                                                                                                                                                                              acc +↦ qVec[k]! * kVec[k]!
                                                                                                                                                                            
                                                                                                                                                                            Equations
                                                                                                                                                                            • One or more equations did not get rendered due to their size.
                                                                                                                                                                            Instances For

                                                                                                                                                                              Buffer pointers (Ptr ty) #

                                                                                                                                                                              Ptr ty is a (bufferName, offset) pair carrying its element type so the load / store calls don't need explicit (ty := ...) annotations each time. Mirrors CUDA C++ T *p arithmetic — particularly the common attention/matmul pattern:

                                                                                                                                                                              const float *K = K_base + kvHead * maxSeq * D;
                                                                                                                                                                              for (int k = 0; k < cacheLen; ++k) {
                                                                                                                                                                                  sum += *K * q;
                                                                                                                                                                                  K += D;
                                                                                                                                                                              }
                                                                                                                                                                              

                                                                                                                                                                              In ShaderM:

                                                                                                                                                                              let K ← ShaderM.ptr (.scalar .f32) "k_cache" (kvHead * maxSeqLen * D)
                                                                                                                                                                              ShaderM.runtimeFor 0 cacheLen 1 fun _ => do
                                                                                                                                                                                let v ← K.load
                                                                                                                                                                                acc +↦ v * q
                                                                                                                                                                                K := K.advance D    -- value-level advance (Ptr is immutable)
                                                                                                                                                                              

                                                                                                                                                                              For mutating advance inside a runtime loop, use MutPtr (declared below). For pure pointer arithmetic at meta-time, use Ptr.atOffset.

                                                                                                                                                                              Ptr is intentionally pure (no ShaderM effect). The constructor ShaderM.ptr only computes a let'-bound base offset for safety, which is the common case.

                                                                                                                                                                              Buffer pointer: typed (buffer name, current u32 offset, declared array size) triple.

                                                                                                                                                                              Ptr is value-level (no ShaderM effect needed for arithmetic). Use ShaderM.ptr to construct one with a let'-stored base.

                                                                                                                                                                              Instances For
                                                                                                                                                                                @[inline]

                                                                                                                                                                                Element-wise read at the current pointer offset. Mirrors CUDA *p.

                                                                                                                                                                                Equations
                                                                                                                                                                                Instances For
                                                                                                                                                                                  @[inline]
                                                                                                                                                                                  def Hesper.WGSL.Monad.Ptr.store {ty : WGSLType} (p : Ptr ty) (x : Exp ty) :

                                                                                                                                                                                  Element-wise write at the current pointer offset. Mirrors CUDA *p = x.

                                                                                                                                                                                  Equations
                                                                                                                                                                                  Instances For
                                                                                                                                                                                    @[inline]

                                                                                                                                                                                    Advance the pointer by delta elements, returning a new Ptr. Mirrors CUDA p + delta (or p += delta if you reassign). Pure — no shader-side effect.

                                                                                                                                                                                    Equations
                                                                                                                                                                                    Instances For
                                                                                                                                                                                      @[inline]

                                                                                                                                                                                      Read at p[k] without permanently advancing. Mirrors CUDA p[k]. Composes well with unrollFor:

                                                                                                                                                                                      ShaderM.unrollFor n fun k =>
                                                                                                                                                                                        let v ← (p.atOffset (Exp.litU32 k)).load
                                                                                                                                                                                        ...
                                                                                                                                                                                      
                                                                                                                                                                                      Equations
                                                                                                                                                                                      Instances For
                                                                                                                                                                                        def Hesper.WGSL.Monad.ShaderM.ptr (ty : WGSLType) (buf : String) (bufLen : Nat) (baseOffset : Exp (WGSLType.scalar ScalarType.u32)) :

                                                                                                                                                                                        Construct a Ptr with a base offset materialised in a register (via let'). Use when the base offset is computed once (eg. kvHead * maxSeqLen * D) and the resulting pointer is then walked many times in inner loops.

                                                                                                                                                                                        bufLen must match the array size declared via declareInputBuffer for buf.

                                                                                                                                                                                        Example:

                                                                                                                                                                                        let K ← ShaderM.ptr (.scalar .u32) "k_cache_f16" kvWords
                                                                                                                                                                                                  (kvHead * maxSeqLen * (D/2))
                                                                                                                                                                                        -- K.offset is a single PTX register; subsequent advance/atOffset
                                                                                                                                                                                        -- only emit `add` against this register.
                                                                                                                                                                                        
                                                                                                                                                                                        Equations
                                                                                                                                                                                        • One or more equations did not get rendered due to their size.
                                                                                                                                                                                        Instances For

                                                                                                                                                                                          Mutable pointer — like Ptr but offset is a var (read/write register) instead of an Exp, so advance actually updates the register in-place rather than constructing a new value.

                                                                                                                                                                                          Mirrors the CUDA outer-loop idiom

                                                                                                                                                                                          K += blockIdx.y * nthreads * nb11;          // initial
                                                                                                                                                                                          for (int k = ...; k < kmax; k += step,
                                                                                                                                                                                               K += step * nb11, V += step * nb21) {  // advance per iter
                                                                                                                                                                                              sum += vec_dot_KQ(K + i_KQ * nb11, ...);// inner per-iter offset
                                                                                                                                                                                          }
                                                                                                                                                                                          

                                                                                                                                                                                          Step 6's Ptr only handles the inner per-iter offset; MutPtr handles the outer per-iter pointer advance.

                                                                                                                                                                                          Instances For
                                                                                                                                                                                            Equations
                                                                                                                                                                                            • One or more equations did not get rendered due to their size.
                                                                                                                                                                                            Instances For
                                                                                                                                                                                              @[inline]

                                                                                                                                                                                              Current offset as an Exp.var so it can be used in index arithmetic without materialising another register.

                                                                                                                                                                                              Equations
                                                                                                                                                                                              Instances For
                                                                                                                                                                                                @[inline]

                                                                                                                                                                                                Read at the current offset.

                                                                                                                                                                                                Equations
                                                                                                                                                                                                Instances For
                                                                                                                                                                                                  @[inline]

                                                                                                                                                                                                  Read at p.offset + extra without advancing. Mirrors CUDA p[k] inside an unrolled inner loop.

                                                                                                                                                                                                  Equations
                                                                                                                                                                                                  Instances For
                                                                                                                                                                                                    @[inline]

                                                                                                                                                                                                    Advance the pointer by delta. The next load / loadAt reads from the new offset. Mirrors CUDA p += delta.

                                                                                                                                                                                                    Equations
                                                                                                                                                                                                    Instances For
                                                                                                                                                                                                      @[inline]
                                                                                                                                                                                                      def Hesper.WGSL.Monad.MutPtr.store {ty : WGSLType} (p : MutPtr ty) (value : Exp ty) :

                                                                                                                                                                                                      Store at the current offset.

                                                                                                                                                                                                      Equations
                                                                                                                                                                                                      Instances For
                                                                                                                                                                                                        @[inline]

                                                                                                                                                                                                        Snapshot to an immutable Ptr at the current offset. Useful when handing the pointer to a helper that doesn't need advance.

                                                                                                                                                                                                        Equations
                                                                                                                                                                                                        Instances For

                                                                                                                                                                                                          Construct a MutPtr whose offset register is initialised from baseOffset. The resulting pointer can be advanced in-place inside an outer loop, matching CUDA's K += stride idiom.

                                                                                                                                                                                                          Example (V11 outer K loop):

                                                                                                                                                                                                          let K ← ShaderM.mutPtr (.scalar .u32) "k_cache_f16" kvWords
                                                                                                                                                                                                                    (kvHead * maxSeqLen * (D/2) + laneId)
                                                                                                                                                                                                          ShaderM.runtimeFor splitStart splitEnd (Exp.litU32 wgSize) fun _ => do
                                                                                                                                                                                                            ...
                                                                                                                                                                                                            let kPacked ← K.loadAt (Exp.litU32 (pk * 32))
                                                                                                                                                                                                            ...
                                                                                                                                                                                                            K.advance (Exp.litU32 (wgSize * (D/2)))
                                                                                                                                                                                                          
                                                                                                                                                                                                          Equations
                                                                                                                                                                                                          • One or more equations did not get rendered due to their size.
                                                                                                                                                                                                          Instances For

                                                                                                                                                                                                            Typed register array — n named ShaderM vars that share a type and can be indexed by a meta-time Nat. Replaces the V8/V11 idiom

                                                                                                                                                                                                            let mut q0Vars : Array String := #[]
                                                                                                                                                                                                            for pk in [0:n] do
                                                                                                                                                                                                              let v ← ShaderM.var ty (init pk)
                                                                                                                                                                                                              q0Vars := q0Vars.push v
                                                                                                                                                                                                            -- later:
                                                                                                                                                                                                            let q0 : Exp _ := Exp.var q0Vars[pk]!
                                                                                                                                                                                                            

                                                                                                                                                                                                            with

                                                                                                                                                                                                            let q0 ← RegArray.mk ty n init
                                                                                                                                                                                                            -- later:
                                                                                                                                                                                                            let q0Exp := q0.get pk
                                                                                                                                                                                                            q0.set pk newVal
                                                                                                                                                                                                            

                                                                                                                                                                                                            The Array String field stays in Lean meta land — at codegen time it materialises as n separate varDecl stmts (one per slot). Mirrors CUDA's T arr[N]; register array.

                                                                                                                                                                                                            Instances For
                                                                                                                                                                                                              def Hesper.WGSL.Monad.instReprRegArray.repr {ty✝ : WGSLType} {n✝ : Nat} :
                                                                                                                                                                                                              RegArray ty✝ n✝NatStd.Format
                                                                                                                                                                                                              Equations
                                                                                                                                                                                                              • One or more equations did not get rendered due to their size.
                                                                                                                                                                                                              Instances For
                                                                                                                                                                                                                @[inline]
                                                                                                                                                                                                                def Hesper.WGSL.Monad.RegArray.get {ty : WGSLType} {n : Nat} (a : RegArray ty n) (i : Nat) :
                                                                                                                                                                                                                Exp ty

                                                                                                                                                                                                                Read slot i as an Exp. Returns Exp.litU32 0 if out-of-range (shouldn't happen in well-typed code; the bounds check is a safety net against meta-time index typos).

                                                                                                                                                                                                                Equations
                                                                                                                                                                                                                Instances For
                                                                                                                                                                                                                  @[inline]
                                                                                                                                                                                                                  def Hesper.WGSL.Monad.RegArray.set {ty : WGSLType} {n : Nat} (a : RegArray ty n) (i : Nat) (v : Exp ty) :

                                                                                                                                                                                                                  Assign a new value to slot i.

                                                                                                                                                                                                                  Equations
                                                                                                                                                                                                                  Instances For
                                                                                                                                                                                                                    def Hesper.WGSL.Monad.ShaderM.regArray (ty : WGSLType) (n : Nat) (init : NatExp ty) :

                                                                                                                                                                                                                    Construct a RegArray ty n by emitting n var declarations. init i produces the initial value for slot i.

                                                                                                                                                                                                                    Equations
                                                                                                                                                                                                                    • One or more equations did not get rendered due to their size.
                                                                                                                                                                                                                    Instances For