Skip to content
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
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ SPIRVIntrinsics = {path = "lib/intrinsics"}
Adapt = "4"
GPUArrays = "12.1"
GPUCompiler = "2.18"
GPUToolbox = "3.4"
GPUToolbox = "3.5"
KernelAbstractions = "0.10"
KernelInterface = "0.4"
LLVM = "10"
Expand All @@ -48,7 +48,7 @@ Random = "1"
Random123 = "1.7.1"
RandomNumbers = "1.6.0"
Reexport = "1"
SPIRVIntrinsics = "1.5.1"
SPIRVIntrinsics = "1.6"
SPIRV_LLVM_Backend_jll = "23"
SPIRV_Tools_jll = "2025.1"
UnsafeAtomics = "0.4"
Expand Down
6 changes: 2 additions & 4 deletions lib/intrinsics/Project.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
name = "SPIRVIntrinsics"
uuid = "71d1d633-e7e8-4a92-83a1-de8814b09ba8"
authors = ["Tim Besard <tim.besard@gmail.com>"]
version = "1.5.1"
version = "1.6.0"

[deps]
ExprTools = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
GPUToolbox = "096a3bc2-3ced-46d0-87f4-dd12716f4bfc"
LLVM = "929cbde3-209d-540e-8aea-75f648917ca0"
UnsafeAtomics = "013be700-e6cd-48c3-b4a1-df204f14c38f"
Expand All @@ -22,9 +21,8 @@ SPIRVIntrinsicsSIMDSpecialFunctionsExt = ["SIMD", "SpecialFunctions"]
SPIRVIntrinsicsSpecialFunctionsExt = "SpecialFunctions"

[compat]
ExprTools = "0.1"
GPUCompiler = "2.13"
GPUToolbox = "0.2, 0.3, 1, 2, 3"
GPUToolbox = "3.5"
LLVM = "10"
SIMD = "3.6"
SpecialFunctions = "1.3, 2"
Expand Down
3 changes: 1 addition & 2 deletions lib/intrinsics/src/SPIRVIntrinsics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ module SPIRVIntrinsics
using LLVM, LLVM.IR, LLVM.Build, LLVM.Interop
using Core: LLVMPtr

import ExprTools

import UnsafeAtomics

import GPUToolbox
using GPUToolbox: u32

include("pointer.jl")
Expand Down
33 changes: 4 additions & 29 deletions lib/intrinsics/src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,37 +103,12 @@ Base.Experimental.@MethodTable(method_table)

const HAS_CONSISTENT_OVERLAY = VERSION >= v"1.12.0-DEV.745" || v"1.11-rc1" <= VERSION < v"1.12-"

# `method_table` resolves in the caller's module, so that back ends that use these macros
# define their overrides in their own method table
macro device_override(ex)
# `method_table` is not interpolated so that the local backend method_table is used
if HAS_CONSISTENT_OVERLAY
# this requires that the overlay method f′ is consistent with f, i.e.,
# - if f(x) returns a value, f′(x) must return the identical value.
# - if f(x) throws an exception, f′(x) must also throw an exception
# (although the exceptions do not need to be identical).
# in return, calls that only reach overlays through their error paths (e.g.
# `checked_add` via `throw_overflowerr_binaryop`) remain eligible for concrete
# evaluation, which e.g. keyword-argument handling relies on.
esc(quote
Base.Experimental.@consistent_overlay(method_table, $ex)
end)
else
esc(quote
Base.Experimental.@overlay(method_table, $ex)
end)
end
esc(GPUToolbox.Overlays.device_override(__module__, GlobalRef(__module__, :method_table), ex))
end

macro device_function(ex)
ex = macroexpand(__module__, ex)
def = ExprTools.splitdef(ex)

# generate a function that errors
def[:body] = quote
error("This function is not intended for use on the CPU")
end

esc(quote
$(ExprTools.combinedef(def))
@device_override $ex
end)
esc(GPUToolbox.Overlays.device_function(__module__, GlobalRef(__module__, :method_table), ex))
end
13 changes: 7 additions & 6 deletions src/compiler/compilation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ function GPUCompiler.finish_module!(@nospecialize(job::OpenCLCompilerJob),
ft = typeof(f)
tt = Tuple{}

# create a deferred compilation job for `initialize_rng_state`
src = methodinstance(ft, tt, GPUCompiler.tls_world_age())
# create a deferred compilation job for `initialize_rng_state`. it is an overlay, so
# look it up in the job's method tables.
src = GPUCompiler.generic_methodinstance(
ft, tt, job.world; method_table_view=GPUCompiler.method_table_view(job))
cfg = CompilerConfig(job.config; kernel=false, name=nothing)
job = CompilerJob(src, cfg, job.world)
id = length(GPUCompiler.deferred_codegen_jobs) + 1
Expand All @@ -123,10 +125,9 @@ function GPUCompiler.finish_module!(@nospecialize(job::OpenCLCompilerJob),
end
fptr = call!(builder, deferred_codegen_ft, deferred_codegen, [ConstantInt(id)])

# call the `initialize_rng_state` function
rt = Core.Compiler.return_type(f, tt)
llvm_rt = convert(LLVMType, rt)
llvm_ft = LLVM.FunctionType(llvm_rt)
# call the `initialize_rng_state` function, which returns nothing. inferring its
# return type natively would leave host code for it in sysimages.
llvm_ft = LLVM.FunctionType(LLVM.VoidType())
fptr = inttoptr!(builder, fptr, LLVM.PointerType(llvm_ft))
call!(builder, llvm_ft, fptr)
br!(builder, top_bb)
Expand Down
10 changes: 6 additions & 4 deletions src/device/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,24 @@ end
end

# local memory with the actual seed, set by `initialize_rng_state` or overridden by `seed!`
@inline function global_random_keys()
@device_function @inline function global_random_keys()
ptr = random_keys()::LLVMPtr{UInt32, AS.Workgroup}
return CLDeviceArray{UInt32, 1, AS.Workgroup}((rng_nslots(),), ptr)
end

# local memory with per-slot counters, incremented when generating numbers
@inline function global_random_counters()
@device_function @inline function global_random_counters()
ptr = random_counters()::LLVMPtr{UInt32, AS.Workgroup}
return CLDeviceArray{UInt32, 1, AS.Workgroup}((rng_nslots(),), ptr)
end

# initialization function, called automatically at the start of each kernel
function initialize_rng_state()
# initialization function, called automatically at the start of each kernel.
# it must return nothing, as the kernel calls it as a void function.
@device_function function initialize_rng_state()
slot = rng_slot()
@inbounds global_random_keys()[slot] = kernel_state().random_seed
@inbounds global_random_counters()[slot] = 0
return
end

# generators
Expand Down
8 changes: 4 additions & 4 deletions src/device/runtime.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const EXCEPTION_FRAME_SIZE = sizeof(ExceptionFrame_st)

# the mailbox address as carried by the kernel state; null when the device has no
# host-accessible memory to put a mailbox in (see `allocate_exception_mailbox`).
@inline exception_info() = reinterpret(ExceptionInfo, kernel_state().exception_info)
@device_function @inline exception_info() = reinterpret(ExceptionInfo, kernel_state().exception_info)
@inline has_exception_info(info::ExceptionInfo) = info != reinterpret(ExceptionInfo, 0)

# Claims must cover all work-groups and queues on the device. SPIRVIntrinsics' public
Expand Down Expand Up @@ -176,7 +176,7 @@ macro gputhrow(name::String, reason::String)
end
end

function signal_exception()
@device_function function signal_exception()
info = exception_info()
# All faulting work-items signal, including level 0 kernels that do not claim a record.
# Kernel completion makes both the status and any recorded details visible to the host.
Expand Down Expand Up @@ -230,7 +230,7 @@ struct KernelState
launch_id::UInt64
end

@inline @generated kernel_state() = GPUCompiler.kernel_state_value(KernelState)
@device_function @inline @generated kernel_state() = GPUCompiler.kernel_state_value(KernelState)

## intrinsics for adding and accessing additional kernel arguments

Expand All @@ -255,5 +255,5 @@ end
end

for name in [:random_keys, :random_counters]
@eval @inline $name() = additional_arg_value(LLVMPtr{UInt32, AS.Workgroup}, Val($(QuoteNode(name))))
@eval @device_function @inline $name() = additional_arg_value(LLVMPtr{UInt32, AS.Workgroup}, Val($(QuoteNode(name))))
end
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
GPUArrays = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7"
GPUCompiler = "61eb1bfa-7361-4325-ad38-22787b887f55"
GPUToolbox = "096a3bc2-3ced-46d0-87f4-dd12716f4bfc"
IOCapture = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
Expand Down
7 changes: 7 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ if isdefined(Test, :detect_closure_boxes)
end
end

# sysimage builds compile methods for the host, which must not reach device-only code
testsuite["host leaks"] = quote
import GPUToolbox, SPIRVIntrinsics
@test isempty(GPUToolbox.Overlays.host_leaks(OpenCL))
@test isempty(GPUToolbox.Overlays.host_leaks(SPIRVIntrinsics))
end

## filter
filter_tests!(testsuite, args)

Expand Down
Loading