diff --git a/CUDACore/src/device/intrinsics/synchronization.jl b/CUDACore/src/device/intrinsics/synchronization.jl index 572f6589d5..1d17f8f50d 100644 --- a/CUDACore/src/device/intrinsics/synchronization.jl +++ b/CUDACore/src/device/intrinsics/synchronization.jl @@ -72,11 +72,26 @@ export barrier_sync export cluster_arrive, cluster_arrive_relaxed, cluster_wait -@device_functions begin -cluster_arrive() = ccall("llvm.nvvm.barrier.cluster.arrive", llvmcall, Cvoid, ()) -cluster_arrive_relaxed() = ccall("llvm.nvvm.barrier.cluster.arrive.relaxed", llvmcall, Cvoid, ()) -cluster_wait() = ccall("llvm.nvvm.barrier.cluster.wait", llvmcall, Cvoid, ()) -end # @device_functions +# These intrinsics only exist in LLVM 17+, so `ccall(intr, llvmcall, ...)` cannot be +# used here: on older LLVM (Julia <= 1.11) the unknown name demotes to a runtime trap. +# A textual declaration passes through to the NVPTX back end on every version, but +# must spell out the attributes the loaded LLVM can't infer: `convergent`, plus +# `nomerge` to stop pre-17 SimplifyCFG from merging the calls across branches. +for (fn, barrier) in ["cluster_arrive" => "arrive", + "cluster_arrive_relaxed" => "arrive.relaxed", + "cluster_wait" => "wait"] + intr = "llvm.nvvm.barrier.cluster.$barrier" + mod = """ + declare void @$intr() #0 + define void @entry() #1 { + call void @$intr() + ret void + } + attributes #0 = { convergent nomerge nounwind } + attributes #1 = { alwaysinline }""" + @eval @device_function @inline $(Symbol(fn))() = + Base.llvmcall(($mod, "entry"), Cvoid, Tuple{}) +end ## memory barriers (membar) diff --git a/test/core/device/intrinsics/clusters.jl b/test/core/device/intrinsics/clusters.jl index 6c2a4ef1f5..23f50471d2 100644 --- a/test/core/device/intrinsics/clusters.jl +++ b/test/core/device/intrinsics/clusters.jl @@ -1,4 +1,17 @@ @testset "thread block clusters" begin + +# the barriers must survive to device IR on every Julia; on LLVM <= 16 they +# used to demote to a silent trap stub (runs on any hardware) +@testset "barrier codegen" begin + @test @filecheck CUDA.code_llvm(Tuple{}) do + @check "llvm.nvvm.barrier.cluster.arrive" + @check "llvm.nvvm.barrier.cluster.wait" + @check_not "gpu_report_exception" + cluster_arrive() + cluster_wait() + end +end + if capability(device()) >= v"9.0" && VERSION >= v"1.11-" ###########################################################################################