# CUDA + StaticArrays weird dynamic function invocation

**URL:** https://discourse.julialang.org/t/cuda-staticarrays-weird-dynamic-function-invocation/109881
**Category:** GPU
**Tags:** gpu, cuda, staticarrays
**Created:** [February 7, 2024, 4:02pm UTC](https://discourse.julialang.org/t/cuda-staticarrays-weird-dynamic-function-invocation/109881 "2024-02-07T16:02:11Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![trahflow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/trahflow/32/30585_2.png) [@trahflow](https://discourse.julialang.org/u/trahflow)
#### Post date: [February 7, 2024, 4:02pm UTC](https://discourse.julialang.org/t/cuda-staticarrays-weird-dynamic-function-invocation/109881/1 "2024-02-07T16:02:11Z")

</div>

Hi,  
I have a weird issue that is somewhat related to [this thread](https://discourse.julialang.org/t/problems-with-linearalgebra-functions-within-kernelabstractions-and-cuda/97566/6).

When using `StaticArrays` within a `CUDA` kernel, it seems to be necessary to add `@inbounds` before converting arrays/views to static arrays, otherwise this leads to a an unsupported dynamic function call error due to [these lines in StaticArrays.jl](https://github.com/JuliaArrays/StaticArrays.jl/blob/ff8ed9b64f41833fe22af81bd2859d5a0b9c3d18/src/convert.jl#L195-L205).  
Throwing `@inbounds` before the converts/Sarray-constructors elides the boundscheck and thus these lines are never hit.

At least in theory.  
In the following I have a small example function that compiles and runs fine if executed from the REPL.  
If this same function is called from with a test (standard `Test.jl`), then the kernel compilation fails with the same error

```julia
Reason: unsupported dynamic function invocation (call to dimension_mismatch_fail(SA::Type, a::AbstractArray) @ StaticArrays ~/julia-depots/gpu/packages/StaticArrays/oOCPP/src/convert.jl:195)

```

**even though** the `@inbounds` statements are there.

I’m a bit out of ideas now… Is this due to the inbounds marker not being propagated due to different inlining behaviour in tests/non-tests?  
I tried various things including setting the [always\_inline](https://cuda.juliagpu.org/stable/api/compiler/#CUDA.cufunction) parameter for cufunction, but nothing helped. I might be hunting a red herring here…

Here’s a MWE:

> **dummy MWE**
>
> ```julia
> using CUDA
> using StaticArrays
> 
> function staticarrays()
> function canonical_kernel(::Val{N}, out, array3, matrix, vector) where {N}
> idx = (blockIdx().x - 1) * blockDim().x + threadIdx().x
> rotation = view(array3, :, :, idx)
> column = view(matrix, :, idx)
> for i in 1:N 
> val = vector[i]
> for j in 1:N
> val += rotation[i, j] * column[j]
> end
> CUDA.@atomic out[i] += val
> end
> nothing
> end
> 
> function sa_kernel(::Val{N}, out, array3, matrix, vector) where {N}
> idx = (blockIdx().x - Int32(1)) * blockDim().x + threadIdx().x
> column = view(matrix, :, idx)
> rotation = view(array3, :, :, idx)
> @inbounds column_static = SVector{N}(column) # @inbounds is required!
> @inbounds rotation_static = SMatrix{N, N}(rotation) # @inbounds is required!
> val = rotation_static * column_static + vector
> for i in 1:N 
> val_i = val[i]
> CUDA.@atomic out[i] += val_i
> end
> nothing
> end
> 
> N = 3
> S = 10
> svector = @SVector randn(Float32, N)
> vector = cu(svector)
> matrix = CUDA.randn(N, S)
> array3 = CUDA.randn(N, N, S)
> out_sa = fill!(similar(matrix, N), 0)
> out_canonical = fill!(similar(matrix, N), 0)
> 
> canonical_args = (Val(N), out_canonical, array3, matrix, vector)
> sa_args = (Val(N), out_sa, array3, matrix, svector)
> 
> let kernel = @cuda launch=false sa_kernel(sa_args...)
> available_threads = launch_configuration(kernel.fun).threads
> 
> threads = min(S, available_threads)
> blocks = cld(S, threads)
> 
> kernel(sa_args...; threads, blocks)
> end
> 
> let kernel = @cuda launch=false canonical_kernel(canonical_args...)
> available_threads = launch_configuration(kernel.fun).threads
> 
> threads = min(S, available_threads)
> blocks = cld(S, threads)
> 
> kernel(canonical_args...; threads, blocks)
> end
> 
> out_sa, out_canonical
> end
> 
> ```

As I’ve said, the example works if I call `staticarrays()` from the REPL, but it fails with above error if the same function is called within a `Tests.jl @testset`.

Aside from this issue, what’s the general view on CUDA + StaticArrays? Is it recommended not to use SA within a kernel?

---

<div class="post-metadata">

### Author: ![trahflow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/trahflow/32/30585_2.png) [@trahflow](https://discourse.julialang.org/u/trahflow)
#### Post date: [February 8, 2024, 11:23am UTC](https://discourse.julialang.org/t/cuda-staticarrays-weird-dynamic-function-invocation/109881/2 "2024-02-08T11:23:51Z")

</div>

I’ve just quickly made that MWE a package to make this very easy to reproduce:  
[CUSA.jl](https://github.com/trahflow/CUSA.jl)

**what works:**

```julia-repl
julia> using CUSA

julia> staticarrays()
(Float32[14.372921, -0.6995831, 6.592437], Float32[14.372921, -0.69958264, 6.5924377])

```

**what doesn’t:**

```julia-repl
(CUSA) pkg> test
     Testing CUSA

.
.
.

CUDA + Staticarrays: Error During Test at /home/le58wel/Repos/CUSA/test/runtests.jl:4
  Got exception outside of a @test
  InvalidIRError: compiling MethodInstance for (::CUSA.var"#sa_kernel#2")(::Val{3}, ::CUDA.CuDeviceVector{Float32, 1}, ::CUDA.CuDeviceArray{Float32, 3, 1}, ::CUDA.CuDeviceMatrix{Float32, 1}, ::StaticArraysCore.SVector{3, Float32}) resulted in invalid LLVM IR
  Reason: unsupported call to an unknown function (call to julia.new_gc_frame)
  Reason: unsupported call to an unknown function (call to julia.push_gc_frame)
  Reason: unsupported call to an unknown function (call to julia.get_gc_frame_slot)
  Reason: unsupported dynamic function invocation (call to dimension_mismatch_fail(SA::Type, a::AbstractArray) @ StaticArrays ~/julia-depots/gpu/packages/StaticArrays/oOCPP/src/convert.jl:195)

```

Any help or thoughts appreciated!

---

<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: [February 12, 2024, 12:07pm UTC](https://discourse.julialang.org/t/cuda-staticarrays-weird-dynamic-function-invocation/109881/3 "2024-02-12T12:07:29Z")

</div>

> [@trahflow](#):
>
> **even though** the `@inbounds` statements are there.

`Pkg.test` runs with `--check-bounds=yes`, forcing bounds checks even if `@inbounds` is present.
