Skip to content
Draft
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
6 changes: 5 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869"
SparseMatricesCSR = "a0a7dd2c-ebf4-11e9-1f05-cf50bc540ca1"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"

[sources]
KernelAbstractions = {rev = "main", url = "https://github.com/JuliaGPU/KernelAbstractions.jl"}
AcceleratedKernels = {rev = "main", url = "https://github.com/JuliaGPU/AcceleratedKernels.jl"}

[extensions]
AMDGPUChainRulesCoreExt = "ChainRulesCore"
AMDGPUEnzymeCoreExt = "EnzymeCore"
Expand All @@ -62,7 +66,7 @@ ExprTools = "0.1"
GPUArrays = "11.3.1"
GPUCompiler = "2.2.3"
GPUToolbox = "3"
KernelAbstractions = "0.9.2"
KernelAbstractions = "0.9, 0.10"
LLVM = "9"
PrecompileTools = "1"
Preferences = "1"
Expand Down
2 changes: 1 addition & 1 deletion src/AMDGPU.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ import .Device: ROCDeviceArray, AS, HostCall, HostCallHolder, hostcall!
import .Device: @ROCDynamicLocalArray, @ROCStaticLocalArray
import .Device: workitemIdx, workgroupIdx, workgroupDim, gridItemDim, gridGroupDim
import .Device: threadIdx, blockIdx, blockDim
import .Device: sync_workgroup, sync_workgroup_count, sync_workgroup_and, sync_workgroup_or
import .Device: sync_workgroup, sync_wavefront, sync_workgroup_count, sync_workgroup_and, sync_workgroup_or
import .Device: @rocprint, @rocprintln, @rocprintf

export ROCDeviceArray, @ROCDynamicLocalArray, @ROCStaticLocalArray
Expand Down
97 changes: 77 additions & 20 deletions src/ROCKernels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ module ROCKernels
export ROCBackend

import AMDGPU
import AMDGPU: rocconvert, hipfunction
import AMDGPU.Device: @device_override
using AMDGPU: GPUArrays, rocSPARSE
using AMDGPU: GPUArrays, rocSPARSE, HIP, Device

import Adapt
import KernelAbstractions as KA
import KernelAbstractions.KernelInterface as KI
import LLVM

using StaticArraysCore: MArray
Expand All @@ -21,6 +23,8 @@ obtain it from an array with `KernelAbstractions.get_backend(::ROCArray)`.
"""
struct ROCBackend <: KA.GPU end

KA.versioninfo(io::IO, ::ROCBackend) = AMDGPU.versioninfo(io)

KA.functional(::ROCBackend) = AMDGPU.functional()
KA.ndevices(::ROCBackend) = AMDGPU.HIP.ndevices()
KA.device(::ROCBackend) = AMDGPU.device_id()
Expand Down Expand Up @@ -135,34 +139,78 @@ function KA.mkcontext(kernel::KA.Kernel{ROCBackend}, I, _ndrange, iterspace, ::D
metadata = KA.CompilerMetadata{KA.ndrange(kernel), Dynamic}(I, _ndrange, iterspace)
end

# Indexing.
KI.argconvert(::ROCBackend, arg) = rocconvert(arg)

@device_override @inline function KA.__index_Local_Linear(ctx)
return AMDGPU.Device.threadIdx().x
function KI.kernel_function(::ROCBackend, f::F, tt::TT=Tuple{}; name=nothing, kwargs...) where {F,TT}
kern = hipfunction(f, tt; name, kwargs...)
KI.Kernel{ROCBackend, typeof(kern)}(ROCBackend(), kern)
end

@device_override @inline function KA.__index_Group_Linear(ctx)
return AMDGPU.Device.blockIdx().x
function (obj::KI.Kernel{ROCBackend})(args...; numworkgroups = 1, workgroupsize = 1)
KI.check_launch_args(numworkgroups, workgroupsize)

obj.kern(args...; groupsize = workgroupsize, gridsize = numworkgroups)
return nothing
end

@device_override @inline function KA.__index_Global_Linear(ctx)
I = @inbounds KA.expand(KA.__iterspace(ctx), AMDGPU.Device.blockIdx().x, AMDGPU.Device.threadIdx().x)
# TODO: This is unfortunate, can we get the linear index cheaper
@inbounds LinearIndices(KA.__ndrange(ctx))[I]

function KI.kernel_max_work_group_size(kikern::KI.Kernel{<:ROCBackend}; max_work_items::Int=Int(typemax(Int32)))::Int
(; groupsize) = AMDGPU.launch_configuration(kikern.kern; max_block_size = max_work_items)

return Int(min(max_work_items, groupsize))
end
function KI.max_work_group_size(::ROCBackend)::Int
Int(HIP.attribute(AMDGPU.HIP.device(), AMDGPU.HIP.hipDeviceAttributeMaxThreadsPerBlock))
end
function KI.sub_group_size(::ROCBackend)::Int
HIP.wavefrontsize(HIP.device())
end
function KI.multiprocessor_count(::ROCBackend)::Int
Int(HIP.attribute(AMDGPU.HIP.device(), AMDGPU.HIP.hipDeviceAttributeMultiprocessorCount))
end

KI.shfl_down_types(::ROCBackend) = DataType[Bool,
UInt8, UInt16, UInt32, UInt64, UInt128,
Int8, Int16, Int32, Int64, Int128,
Float16, Float32, Float64,
ComplexF16, ComplexF32, ComplexF64]

# Indexing.
## COV_EXCL_START
@device_override @inline function KI.get_local_id()
return (; x = Int(AMDGPU.Device.workitemIdx().x), y = Int(AMDGPU.Device.workitemIdx().y), z = Int(AMDGPU.Device.workitemIdx().z))
end

@device_override @inline function KA.__index_Local_Cartesian(ctx)
@inbounds KA.workitems(KA.__iterspace(ctx))[AMDGPU.Device.threadIdx().x]
@device_override @inline function KI.get_group_id()
return (; x = Int(AMDGPU.Device.workgroupIdx().x), y = Int(AMDGPU.Device.workgroupIdx().y), z = Int(AMDGPU.Device.workgroupIdx().z))
end

@device_override @inline function KA.__index_Group_Cartesian(ctx)
@inbounds KA.blocks(KA.__iterspace(ctx))[AMDGPU.Device.blockIdx().x]
@device_override @inline function KI.get_global_id()
return (; x = Int((AMDGPU.Device.workgroupIdx().x-1)*AMDGPU.Device.blockDim().x + AMDGPU.Device.workitemIdx().x), y = Int((AMDGPU.Device.workgroupIdx().y-1)*AMDGPU.Device.blockDim().y + AMDGPU.Device.workitemIdx().y), z = Int((AMDGPU.Device.workgroupIdx().z-1)*AMDGPU.Device.blockDim().z + AMDGPU.Device.workitemIdx().z))
end

@device_override @inline function KA.__index_Global_Cartesian(ctx)
return @inbounds KA.expand(KA.__iterspace(ctx), AMDGPU.Device.blockIdx().x, AMDGPU.Device.threadIdx().x)
@device_override @inline function KI.get_local_size()
return (; x = Int(AMDGPU.Device.workgroupDim().x), y = Int(AMDGPU.Device.workgroupDim().y), z = Int(AMDGPU.Device.workgroupDim().z))
end

@device_override @inline function KI.get_num_groups()
return (; x = Int(AMDGPU.Device.gridGroupDim().x), y = Int(AMDGPU.Device.gridGroupDim().y), z = Int(AMDGPU.Device.gridGroupDim().z))
end

@device_override @inline function KI.get_global_size()
return (; x = Int(AMDGPU.Device.gridItemDim().x), y = Int(AMDGPU.Device.gridItemDim().y), z = Int(AMDGPU.Device.gridItemDim().z))
end

@device_override KI.get_sub_group_size() = UInt32(Device.wavefrontsize())

@device_override KI.get_max_sub_group_size() = UInt32(Device.wavefrontsize())

@device_override KI.get_num_sub_groups() = UInt32(prod(Device.blockDim()) ÷ Device.wavefrontsize())

@device_override KI.get_sub_group_id() = UInt32(((Device.threadIdx().x - 1) + Device.blockDim().x * (Device.threadIdx().y - 1) + Device.blockDim().x * Device.blockDim().y * (Device.threadIdx().z - 1)) ÷ Device.wavefrontsize()) + 0x1

@device_override KI.get_sub_group_local_id() = UInt32(Device.activelane() + 0x1)

@device_override @inline function KA.__validindex(ctx)
if KA.__dynamic_checkbounds(ctx)
I = @inbounds KA.expand(KA.__iterspace(ctx), AMDGPU.Device.blockIdx().x, AMDGPU.Device.threadIdx().x)
Expand All @@ -174,8 +222,8 @@ end

# Shared memory.

@device_override @inline function KA.SharedMemory(::Type{T}, ::Val{Dims}, ::Val{Id}) where {T, Dims, Id}
ptr = AMDGPU.Device.alloc_special(Val(Id), T, Val(AMDGPU.AS.Local), Val(prod(Dims)))
@device_override @inline function KI.localmemory(::Type{T}, ::Val{Dims}) where {T, Dims}
ptr = AMDGPU.Device.alloc_special(Val(:shmem), T, Val(AMDGPU.AS.Local), Val(prod(Dims)))
AMDGPU.ROCDeviceArray(Dims, ptr)
end

Expand All @@ -185,12 +233,21 @@ end

# Other.

@device_override @inline function KA.__synchronize()
@device_override @inline function KI.barrier()
AMDGPU.Device.sync_workgroup()
end

@device_override @inline function KA.__print(args...)
@device_override @inline function KI.sub_group_barrier()
AMDGPU.Device.sync_wavefront()
end

@device_override function KI.shfl_down(val::T, offset::Integer) where T
@inline AMDGPU.Device.shfl_down(val, Cint(offset))
end

@device_override @inline function KI._print(args...)
# TODO
end
## COV_EXCL_STOP

end
8 changes: 4 additions & 4 deletions src/device/gcn/memory_static.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@generated function alloc_special(
::Val{id}, ::Type{T}, ::Val{as}, ::Val{len}, ::Val{zeroinit} = Val{false}(),
) where {id,T,as,len,zeroinit}
@dispose ctx=Context() begin
Context() do ctx
eltyp = convert(LLVMType, T)

# old versions of GPUArrays invoke _shmem with an integer id; make sure those are unique
Expand All @@ -24,8 +24,8 @@
gv = GlobalVariable(mod, gv_typ, string(id), as)
if len > 0
if as == AS.Local
linkage!(gv, LLVM.API.LLVMExternalLinkage)
# NOTE: Backend doesn't support initializer for local AS
linkage!(gv, LLVM.API.LLVMInternalLinkage)
initializer!(gv, UndefValue(gv_typ))
elseif as == AS.Private
linkage!(gv, LLVM.API.LLVMInternalLinkage)
initializer!(gv, null(gv_typ))
Expand All @@ -38,7 +38,7 @@
alignment!(gv, Base.max(32, Base.datatype_alignment(T)))

# generate IR
@dispose builder=IRBuilder() begin
IRBuilder() do builder
entry = BasicBlock(llvm_f, "entry")
position!(builder, entry)

Expand Down
11 changes: 11 additions & 0 deletions src/device/gcn/synchronization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ Waits until all wavefronts in a workgroup have reached this call and that their
UnsafeAtomics.fence(UnsafeAtomics.seq_cst, AMDGPU.syncscope_workgroup)
end

"""
sync_wavefront()

Waits until all wavefronts in a workgroup have reached this call and that their memory accesses are visible to other threads in the workgroup.
"""
@inline function sync_wavefront()
# This is a no-op https://github.com/llvm/llvm-project/blob/88b77d5eaa66747538a12c9876eeffdce31ddb71/openmp/device/src/Synchronization.cpp#L136-L140
ccall("llvm.amdgcn.wave.barrier", llvmcall, Cvoid, ())
end


"""
sync_workgroup_count(predicate::Cint)::Cint

Expand Down
2 changes: 1 addition & 1 deletion test/kernelabstractions_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ AMDGPU.allowscalar(false)
@testset "kernelabstractions" begin

# TODO fix Printing
skip_tests = ["Printing", "sparse"]
skip_tests = ["Printing", "sparse", "CPU synchronization", "fallback test: callable types",]
if Sys.iswindows()
# TODO
# We do not support hostcalls on Windows yet.
Expand Down
6 changes: 6 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
@static if VERSION < v"1.11" && get(ENV, "BUILDKITE_PIPELINE_NAME", "AMDGPU.jl") == "AMDGPU.jl"
using Pkg
Pkg.add(url="https://github.com/JuliaGPU/AcceleratedKernels.jl", rev="main")
Pkg.add(url="https://github.com/JuliaGPU/KernelAbstractions.jl", rev="main")
end

using AMDGPU
using AMDGPU: Device, Runtime, @allowscalar
import AMDGPU.Device: HostCallHolder, hostcall!
Expand Down