From ac08d21335bf37f5b078800d9b0282aba03d5e7e Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 5 Oct 2026 21:56:06 +0200 Subject: [PATCH] Upgrade to UnsafeAtomics 0.4 UnsafeAtomics 0.4 emits every atomic and fence in device code with the scope it is given, and GPUCompiler 2.12 renames its `device` scope to AMDGPU's `agent`. Our fence overlays are therefore redundant, and the scope constants become UnsafeAtomics' public `device` and `workgroup`. They stay defined, as AcceleratedKernels' AMDGPU extension uses `syncscope_agent`. The Atomix override for `+` and `-` remains, since Atomix always uses the system scope, which keeps hardware FP atomics from being selected. --- Project.toml | 4 ++-- src/AMDGPU.jl | 6 +++--- src/device/gcn/synchronization.jl | 14 -------------- test/core/codegen.jl | 23 +++++++++++++++++++++++ 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/Project.toml b/Project.toml index ddf3cde39..cfee41f25 100644 --- a/Project.toml +++ b/Project.toml @@ -60,7 +60,7 @@ ChainRulesCore = "1" EnzymeCore = "0.8" ExprTools = "0.1" GPUArrays = "11.5.14" -GPUCompiler = "2.9" +GPUCompiler = "2.12" GPUToolbox = "3" KernelAbstractions = "0.9.2" LLVM = "10" @@ -80,5 +80,5 @@ SparseMatricesCSR = "0.6.9" SpecialFunctions = "2" StaticArraysCore = "1" Statistics = "1" -UnsafeAtomics = "0.3" +UnsafeAtomics = "0.4" julia = "1.10" diff --git a/src/AMDGPU.jl b/src/AMDGPU.jl index b609462a6..b9a5e5932 100644 --- a/src/AMDGPU.jl +++ b/src/AMDGPU.jl @@ -79,9 +79,9 @@ include("memory.jl") Base.Experimental.@MethodTable(method_table) -#needs to be before Device since sync uses this -const syncscope_agent = UnsafeAtomics.Internal.LLVMSyncScope{:agent}() -const syncscope_workgroup = UnsafeAtomics.Internal.LLVMSyncScope{:workgroup}() +# Needs to be before Device since sync uses this. GPUCompiler emits `device` as LLVM's `agent`. +const syncscope_agent = UnsafeAtomics.device +const syncscope_workgroup = UnsafeAtomics.workgroup # Referenced by the generated `kernel_state()`, and generators run in the world they are # defined in, so this has to precede the device code. diff --git a/src/device/gcn/synchronization.jl b/src/device/gcn/synchronization.jl index 8378b3707..a9d663807 100644 --- a/src/device/gcn/synchronization.jl +++ b/src/device/gcn/synchronization.jl @@ -1,18 +1,4 @@ -@llvmgenerated builder function _fence(::Val{ordering}, ::Val{scope})::Nothing where {ordering, scope} - fence!(builder, parse(LLVM.AtomicOrdering.T, String(ordering)); scope=String(scope)) - nothing -end - -for ord in UnsafeAtomics.Internal.orderings - for sync in (AMDGPU.syncscope_agent, AMDGPU.syncscope_workgroup) - ordering = Val(UnsafeAtomics.Internal.llvm_ordering(ord)) - scope = Val(UnsafeAtomics.Internal.llvm_syncscope(sync)) - @eval @device_function UnsafeAtomics.fence(::$(typeof(ord)), ::$(typeof(sync))) = - _fence($ordering, $scope) - end -end - """ sync_workgroup() diff --git a/test/core/codegen.jl b/test/core/codegen.jl index 002614939..b9f468ffb 100644 --- a/test/core/codegen.jl +++ b/test/core/codegen.jl @@ -15,6 +15,29 @@ using KernelAbstractions: @atomic iob = IOBuffer() AMDGPU.code_gcn(iob, synckern, Tuple{}; kernel=true) @test occursin("s_barrier", String(take!(iob))) + + AMDGPU.code_llvm(iob, synckern, Tuple{}; kernel=true) + @test count("fence syncscope(\"workgroup\") seq_cst", String(take!(iob))) == 2 +end + +@testset "Synchronization scopes" begin + # UnsafeAtomics' `device` scope has to reach LLVM as AMDGPU's `agent` + function atomic_add_ker!(x) + @inbounds @atomic x[1] += 1f0 + return + end + function agent_fence_ker() + AMDGPU.UnsafeAtomics.fence(AMDGPU.UnsafeAtomics.seq_cst, AMDGPU.syncscope_agent) + return + end + + iob = IOBuffer() + tt = Tuple{AMDGPU.Device.ROCDeviceVector{Float32, AMDGPU.Device.AS.Global}} + AMDGPU.code_llvm(iob, atomic_add_ker!, tt; kernel=true) + @test occursin(r"atomicrmw fadd .* syncscope\(\"agent\"\) seq_cst", String(take!(iob))) + + AMDGPU.code_llvm(iob, agent_fence_ker, Tuple{}; kernel=true) + @test occursin("fence syncscope(\"agent\") seq_cst", String(take!(iob))) end @testset "Trapping" begin