# CUDA: unsupported dynamic function invocation for closure

**URL:** <https://discourse.julialang.org/t/cuda-unsupported-dynamic-function-invocation-for-closure/115981>\
**Category:** GPU\
**Created:** [June 21, 2024, 4:00pm UTC](https://discourse.julialang.org/t/cuda-unsupported-dynamic-function-invocation-for-closure/115981 "2024-06-21T16:00:25Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)\
**Post date:** [June 21, 2024, 4:00pm UTC](https://discourse.julialang.org/t/cuda-unsupported-dynamic-function-invocation-for-closure/115981/1 "2024-06-21T16:00:25Z")

</div>

I have a function `f` that takes a scalar parameter and a vector. It works well for `CuVector`:

```julia
xs = CuVector{Float64}(rand(10))
f.(param, xs) # works well

```

However, if I create a closure out of `f` such that it holds `param`, then the closure generates an error:

```julia
g(x) = f(param, x)
g.(xs) # error

```

The error message looks like

```julia-repl
ERROR: InvalidIRError: compiling MethodInstance for (::GPUArrays.var"#34#36")(::CUDA.CuKernelContext, ::CuDeviceVector{…}, ::Base.Broadcast.Broadcasted{…}, ::Int64) resulted in invalid LLVM IR
Reason: unsupported dynamic function invocation (call to index)
Stacktrace:
 [1] #7
   @ ./REPL[11]:1
 [2] _broadcast_getindex_evalf
   @ ./broadcast.jl:709
 [3] _broadcast_getindex
   @ ./broadcast.jl:682
 [4] getindex
   @ ./broadcast.jl:636
 [5] #34
   @ ~/.julia/packages/GPUArrays/HjWFN/src/host/broadcast.jl:59
Hint: catch this exception as `err` and call `code_typed(err; interactive = true)` to introspect the erronous code with Cthulhu.jl
Stacktrace:
...

```

Is there a way to create a closure such that it works well with `CuArray`?

---

<div class="post-metadata">

**Author:** ![maleadt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maleadt/32/10097_2.png) [@maleadt](https://discourse.julialang.org/u/maleadt)\
**Post date:** [June 22, 2024, 7:52am UTC](https://discourse.julialang.org/t/cuda-unsupported-dynamic-function-invocation-for-closure/115981/2 "2024-06-22T07:52:06Z")

</div>

> [@wsshin](#):
>
> Is there a way to create a closure such that it works well with `CuArray`?

Closures are supported:

```julia
julia> using Metal

julia> f(a,b) = a+b
f (generic function with 1 method)

julia> xs = mtl([1])
1-element MtlVector{Int64, Private}:
 1

julia> const param = 2
2

julia> f.(param, xs)
1-element MtlVector{Int64, Private}:
 3

julia> g(x) = f(param, x)
g (generic function with 1 method)

julia> g.(xs)
1-element MtlVector{Int64, Private}:
 3

```

You are probably dealing with a badly typed `param` (e.g. non-const global or `Core.Box` cf. [performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/15276)).

---

<div class="post-metadata">

**Author:** ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)\
**Post date:** [June 22, 2024, 11:43pm UTC](https://discourse.julialang.org/t/cuda-unsupported-dynamic-function-invocation-for-closure/115981/3 "2024-06-22T23:43:05Z")

</div>

> [@maleadt](#):
>
> You are probably dealing with a badly typed `param` (e.g. non-const global or `Core.Box` cf. [performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/15276)).

Yes, my `param` is non-const global. What should I do in that case? I tried to define `g(x)` using the `let` block as

```julia
g(x) = let param=param
    f(param, x)
end

```

but had no success.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 23, 2024, 12:07am UTC](https://discourse.julialang.org/t/cuda-unsupported-dynamic-function-invocation-for-closure/115981/4 "2024-06-23T00:07:37Z")

</div>

> [@wsshin](#):
>
> Yes, my `param` is non-const global.

> [@wsshin](#):
>
> `g(x) = f(param, x)`

Then that’s not a closure at all, it’s not capturing a local variable (capturing meaning that the local variable can live on despite the local scope ending) but accessing a global variable that persists unconditionally.

> [@wsshin](#):
>
> ```julia
> g(x) = let param=param
> f(param, x)
> end
> 
> ```

`g` still accesses the global `param` here, and `f` just takes a local `param` as an input.

```julia
const g = let p=param
  g1(x) = f(p, x)
end

```

This puts a closure in a local scope that captures a local variable, and the returned closure is assigned to a `const` global variable.

If you don’t want to deal with scoping, you could also make a struct to hold values for callable instances:

```julia
struct G{P}<:Function p::P end
(_g::G)(x) = f(_g.p, x)

const g = G(param)

```
