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.