docs / GPU Programming / Functions in Kernels

Functions in kernels

A kernel body may call ordinary Miri functions, as long as they are device-representable: scalar parameters and return type, no I/O, no allocation, no recursion. The compiler checks all of this at the call site — a violation is a compile error naming the offending function, not a runtime surprise.

fn dbl(x float) float: x * 2.0

fn main()
    gpu let src = [1.0, 2.0, 3.0]
    gpu var dst = [0.0, 0.0, 0.0]
    forall i in 0..3
        dst[i] = dbl(src[i])       // compiled into the kernel

Residency-polymorphic functions

A function whose buffer access happens only inside a forall accepts both host and gpu-resident arguments — the launch specializes to wherever the data lives:

use system.gpu
use system.collections.array

fn scale(a out Array<int,8>)
    forall i in 0..a.length()
        a[i] = a[i] * 2

fn main()
    gpu var data = [1, 2, 3, 4, 5, 6, 7, 8]
    scale(data)
    let host = data
    println(f"{host[0]} {host[1]} {host[2]} {host[3]} {host[4]} {host[5]} {host[6]} {host[7]}")

Output: 2 4 6 8 10 12 14 16. scale mutates the device buffer in place — no copy in, no copy out. A function that touches a buffer in host context (say, return a[0]) stays host-only, and passing it a gpu-resident buffer is a compile error. The residency rules cannot be smuggled around through a call boundary.