Skip to content

adding attempt to force inbounds at the kernel level #429

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions src/KernelAbstractions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,44 @@ synchronize(backend)
```
"""
macro kernel(expr)
__kernel(expr, #=generate_cpu=#true)
__kernel(expr, #=generate_cpu=#true, #=force_inbounds=#false)
end

"""
@kernel cpu=false function f(args) end
@kernel config function f(args) end

Disable code-generation of the CPU function. This relaxes semantics such that
KernelAbstractions primitives can be used in non-kernel functions.
This allows for two different configurations:

1. `cpu={true, false}`: Disables code-generation of the CPU function. This relaxes semantics such that KernelAbstractions primitives can be used in non-kernel functions.
2. `inbounds={false, true}`: Enables a forced `@inbounds` macro around the function definition in the case the user is using too many `@inbounds` already in their kernel. Note that this can lead to incorrect results, crashes, etc and is fundamentally unsafe. Be careful!

- [`@context`](@ref)

!!! warn
This is an experimental feature.
"""
macro kernel(config, expr)
if config isa Expr && config.head == :(=) &&
config.args[1] == :cpu && config.args[2] isa Bool
generate_cpu = config.args[2]
macro kernel(ex...)
if length(ex) == 1
__kernel(ex[1], true, false)
else
error("Configuration should be of form `cpu=false` got $config")
generate_cpu = true
force_inbounds = false
for i = 1:length(ex)-1
if ex[i] isa Expr && ex[i].head == :(=) &&
ex[i].args[1] == :cpu && ex[i].args[2] isa Bool
generate_cpu = ex[i].args[2]
elseif ex[i] isa Expr && ex[i].head == :(=) &&
ex[i].args[1] == :inbounds && ex[i].args[2] isa Bool
force_inbounds = ex[i].args[2]
else
error("Configuration should be of form:\n"*
"* `cpu=true`\n"*
"* `inbounds=false`\n"*
"got `", ex[i], "`")
end
end
__kernel(ex[end], generate_cpu, force_inbounds)
end
__kernel(expr, generate_cpu)
end

"""
Expand Down
8 changes: 7 additions & 1 deletion src/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ function find_return(stmt)
end

# XXX: Proper errors
function __kernel(expr, generate_cpu=true)
function __kernel(expr, generate_cpu=true, force_inbounds=false)
def = splitdef(expr)
name = def[:name]
args = def[:args]
if force_inbounds
body_qt = quote
@inbounds $(def[:body])
end
def[:body] = body_qt
end

find_return(expr) && error("Return statement not permitted in a kernel function $name")

Expand Down
16 changes: 16 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ kern_static(CPU(static=true), (1,))(A, ndrange=length(A))
end
@test_throws ErrorException("This kernel is unavailable for backend CPU") my_no_cpu_kernel(CPU())

# testing multiple configurations at the same time
@kernel cpu=false inbounds=false function my_no_cpu_kernel2(a)
end
@test_throws ErrorException("This kernel is unavailable for backend CPU") my_no_cpu_kernel2(CPU())

if Base.JLOptions().check_bounds == 0 || Base.JLOptions().check_bounds == 1
# testing bounds errors
@kernel inbounds=false my_bounded_kernel(a) = a[1]
@test_throws BoundsError(Int64[],(1,)) my_bounded_kernel(CPU())(Int[], ndrange=1)
end

if Base.JLOptions().check_bounds == 0 || Base.JLOptions().check_bounds == 2
@kernel inbounds=true my_inbounds_kernel(a) = a[1]
@test nothing == my_inbounds_kernel(CPU())(Int[], ndrange=1)
end

struct NewBackend <: KernelAbstractions.GPU end
@testset "Default host implementation" begin
backend = NewBackend()
Expand Down