diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 368af65fad..641cfeae07 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -239,7 +239,7 @@ steps: using CUDA @assert !CUDA.functional() @assert !isdefined(CUDACore, :libcudart) - CUDA.set_runtime_version!(v"11.6")' + CUDA.set_runtime_version!(v"12.0")' julia --project -e ' using CUDA @assert !CUDA.functional() diff --git a/CUDACore/Project.toml b/CUDACore/Project.toml index 8b9b3fe284..ff56e1aded 100644 --- a/CUDACore/Project.toml +++ b/CUDACore/Project.toml @@ -54,7 +54,7 @@ ChainRulesCore = "1" EnzymeCore = "0.8.2" ExprTools = "0.1" GPUArrays = "11.5.4" -GPUCompiler = "2" +GPUCompiler = "2.1" GPUToolbox = "3" KernelAbstractions = "0.9.38" LLVM = "9.6" diff --git a/CUDACore/src/compiler/compilation.jl b/CUDACore/src/compiler/compilation.jl index ec033a6593..07a3d5514e 100644 --- a/CUDACore/src/compiler/compilation.jl +++ b/CUDACore/src/compiler/compilation.jl @@ -17,6 +17,9 @@ end const CUDACompilerConfig = CompilerConfig{PTXCompilerTarget, CUDACompilerParams} const AnyCUDAJob = CompilerJob{PTXCompilerTarget, <:AbstractCUDACompilerParams} +# CUDA 12.0 is the oldest supported toolkit, and Maxwell is the oldest supported GPU. +const minreq = (; ptx=v"8.0", sm=sm"50") + GPUCompiler.runtime_module(@nospecialize(job::AnyCUDAJob)) = CUDACore # filter out functions from libdevice and cudadevrt @@ -56,6 +59,23 @@ function GPUCompiler.finish_module!(@nospecialize(job::AnyCUDAJob), Tuple{CompilerJob{PTXCompilerTarget}, LLVM.Module, LLVM.Function}, job, mod, entry) + # Make the compilation target available to device code. GPUCompiler used to provide + # these globals, but target-specific properties are owned by the back-end now. + feature_set = job.config.target.feature_set === :arch ? ArchFeatures : + job.config.target.feature_set === :family ? FamilyFeatures : + BaselineFeatures + for (name, value) in ["sm_major" => job.config.target.cap.major, + "sm_minor" => job.config.target.cap.minor, + "sm_features" => UInt32(feature_set), + "ptx_major" => job.config.target.ptx.major, + "ptx_minor" => job.config.target.ptx.minor] + if haskey(globals(mod), name) + gv = globals(mod)[name] + initializer!(gv, ConstantInt(LLVM.Int32Type(), value)) + linkage!(gv, LLVM.API.LLVMPrivateLinkage) + end + end + # if this kernel uses our RNG, we should prime the shared state. # XXX: these transformations should really happen at the Julia IR level... if haskey(globals(mod), "global_random_keys") @@ -196,7 +216,7 @@ function compiler_config(dev; kwargs...) end function default_ptx_versions(llvm_support, ptxas_support) - requested_ptx = v"6.2" + requested_ptx = minreq.ptx llvm_ptxs = filter(>=(requested_ptx), llvm_support.ptx) ptxas_ptxs = filter(>=(requested_ptx), ptxas_support.ptx) isempty(llvm_ptxs) && @@ -235,13 +255,15 @@ end # determine the PTX ISA to use. if ptx !== nothing # explicit request: take it exactly, validating against the toolchain + ptx >= minreq.ptx || + error("CUDA.jl requires PTX ISA $(minreq.ptx) or higher") ptx in llvm_support.ptx || error("Requested PTX ISA $ptx is not supported by LLVM $(nvptx_llvm_version)") ptx in ptxas_support.ptx || error("Requested PTX ISA $ptx is not supported by ptxas $(compiler_version())") llvm_ptx = ptxas_ptx = ptx else - # default: pick the newest PTX ISA supported by the toolchain (>=v6.2) + # default: pick the newest supported PTX ISA at or above our minimum llvm_ptx, ptxas_ptx = default_ptx_versions(llvm_support, ptxas_support) end @@ -255,6 +277,8 @@ end ptx_sms = ptx_sm_support(ptxas_ptx) if arch !== nothing # explicit request: take it as-is, validating against the PTX ISA + base_version(arch) >= base_version(minreq.sm) || + error("CUDA.jl requires compute capability $(cpu_name(minreq.sm)) or higher") arch in ptx_sms || error("$(cpu_name(arch)) is not supported by PTX ISA $(ptxas_ptx)") ptxas_sm = arch @@ -262,7 +286,9 @@ end # pick the most specific capability the selected PTX ISA supports whose cubin # would actually load on the current device. For baseline that's the onion model; # `:arch` requires an exact CC match, `:family` a same-family match. - ptxas_candidates = filter(sm -> runs_on(sm, capability(dev)), ptx_sms) + ptxas_candidates = filter(ptx_sms) do sm + base_version(sm) >= base_version(minreq.sm) && runs_on(sm, capability(dev)) + end isempty(ptxas_candidates) && error("Compute capability $(capability(dev)) is not supported by ptxas " * "$(compiler_version()) at PTX ISA $(ptxas_ptx)") @@ -275,7 +301,8 @@ end # Exact `ptxas_sm` unavailable in LLVM. Fall back to baseline LLVM at a # lower base, since arch/family features don't carry across versions. baseline_candidates = filter(llvm_support.sm) do sm - sm.feature_set === :baseline && base_version(sm) <= base_version(ptxas_sm) + sm.feature_set === :baseline && + base_version(minreq.sm) <= base_version(sm) <= base_version(ptxas_sm) end isempty(baseline_candidates) && error("Compute capability $(cpu_name(ptxas_sm)) is not supported by LLVM $(nvptx_llvm_version)") diff --git a/CUDACore/src/device/intrinsics/atomics.jl b/CUDACore/src/device/intrinsics/atomics.jl index 7087b853f1..eacf31ab13 100644 --- a/CUDACore/src/device/intrinsics/atomics.jl +++ b/CUDACore/src/device/intrinsics/atomics.jl @@ -164,8 +164,11 @@ for A in (AS.Generic, AS.Global, AS.Shared), T in (:Int16, :UInt16) end intr = "atom$scope.cas.b16 \$0, [\$1], \$2, \$3;" - @eval @device_function @inline atomic_cas!(ptr::LLVMPtr{$T,$A}, cmp::$T, val::$T) = - @asmcall($intr, "=h,l,h,h", true, $T, Tuple{Core.LLVMPtr{$T,$A},$T,$T}, ptr, cmp, val) + @eval @device_function @inline function atomic_cas!(ptr::LLVMPtr{$T,$A}, cmp::$T, val::$T) + require_sm_70() + @asmcall($intr, "=h,l,h,h", true, $T, + Tuple{Core.LLVMPtr{$T,$A},$T,$T}, ptr, cmp, val) + end end @@ -448,36 +451,12 @@ for (op,impl,typ) in [(:(+), :(atomic_add!), [:UInt32,:Int32,:UInt64,:Int64,:Flo $impl(pointer(A, I), val) end -# native atomics that are not supported on all devices -@inline function atomic_arrayset(A::AbstractArray{T}, I::Integer, op::typeof(+), - val::T) where {T <: Union{Float64}} - ptr = pointer(A, I) - if compute_capability() >= sv"6.0" - atomic_add!(ptr, val) - else - atomic_op!(ptr, op, val) - end -end - -@inline function atomic_arrayset(A::AbstractArray{Float16}, I::Integer, op::typeof(+), - val::Float16) - ptr = pointer(A, I) - if compute_capability() >= sv"7.0" - atomic_add!(ptr, val) - else - atomic_op!(ptr, op, val) - end -end +# native atomics that the back-end expands on older devices +@inline atomic_arrayset(A::AbstractArray{T}, I::Integer, ::typeof(+), val::T) where + {T <: Union{Float16,Float64}} = atomic_add!(pointer(A, I), val) @static if VERSION >= v"1.11" - @inline function atomic_arrayset(A::AbstractArray{BFloat16}, I::Integer, op::typeof(+), - val::BFloat16) - ptr = pointer(A, I) - if compute_capability() >= sv"9.0" - atomic_add!(ptr, val) - else - atomic_op!(ptr, op, val) - end - end + @inline atomic_arrayset(A::AbstractArray{BFloat16}, I::Integer, ::typeof(+), + val::BFloat16) = atomic_add!(pointer(A, I), val) end # fallback using compare-and-swap diff --git a/CUDACore/src/device/intrinsics/math.jl b/CUDACore/src/device/intrinsics/math.jl index dd0ad837db..107958f9b3 100644 --- a/CUDACore/src/device/intrinsics/math.jl +++ b/CUDACore/src/device/intrinsics/math.jl @@ -311,33 +311,49 @@ function dp4a end @static if LLVM.version() >= v"21" # LLVM 21 added @llvm.nvvm.idp4a.[us].[us]; prefer the intrinsic over inline PTX so # the instruction participates in optimization and instruction selection. - @device_function dp4a(a::Int32, b::Int32, c::Int32) = + @device_function function dp4a(a::Int32, b::Int32, c::Int32) + require_sm_61() ccall("llvm.nvvm.idp4a.s.s", llvmcall, Int32, (Int32, Int32, Int32), a, b, c) + end - @device_function dp4a(a::Int32, b::UInt32, c::Int32) = + @device_function function dp4a(a::Int32, b::UInt32, c::Int32) + require_sm_61() ccall("llvm.nvvm.idp4a.s.u", llvmcall, Int32, (Int32, UInt32, Int32), a, b, c) + end - @device_function dp4a(a::UInt32, b::Int32, c::Int32) = + @device_function function dp4a(a::UInt32, b::Int32, c::Int32) + require_sm_61() ccall("llvm.nvvm.idp4a.u.s", llvmcall, Int32, (UInt32, Int32, Int32), a, b, c) + end - @device_function dp4a(a::UInt32, b::UInt32, c::UInt32) = + @device_function function dp4a(a::UInt32, b::UInt32, c::UInt32) + require_sm_61() ccall("llvm.nvvm.idp4a.u.u", llvmcall, UInt32, (UInt32, UInt32, UInt32), a, b, c) + end else - @device_function dp4a(a::Int32, b::Int32, c::Int32) = + @device_function function dp4a(a::Int32, b::Int32, c::Int32) + require_sm_61() @asmcall("dp4a.s32.s32 \$0, \$1, \$2, \$3;", "=r,r,r,r", false, Int32, Tuple{Int32, Int32, Int32}, a, b, c) + end - @device_function dp4a(a::Int32, b::UInt32, c::Int32) = + @device_function function dp4a(a::Int32, b::UInt32, c::Int32) + require_sm_61() @asmcall("dp4a.s32.u32 \$0, \$1, \$2, \$3;", "=r,r,r,r", false, Int32, Tuple{Int32, UInt32, Int32}, a, b, c) + end - @device_function dp4a(a::UInt32, b::Int32, c::Int32) = + @device_function function dp4a(a::UInt32, b::Int32, c::Int32) + require_sm_61() @asmcall("dp4a.u32.s32 \$0, \$1, \$2, \$3;", "=r,r,r,r", false, Int32, Tuple{UInt32, Int32, Int32}, a, b, c) + end - @device_function dp4a(a::UInt32, b::UInt32, c::UInt32) = + @device_function function dp4a(a::UInt32, b::UInt32, c::UInt32) + require_sm_61() @asmcall("dp4a.u32.u32 \$0, \$1, \$2, \$3;", "=r,r,r,r", false, UInt32, Tuple{UInt32, UInt32, UInt32}, a, b, c) + end end diff --git a/CUDACore/src/device/intrinsics/misc.jl b/CUDACore/src/device/intrinsics/misc.jl index a3519df6db..41c56e4eb7 100644 --- a/CUDACore/src/device/intrinsics/misc.jl +++ b/CUDACore/src/device/intrinsics/misc.jl @@ -31,9 +31,10 @@ end Puts a thread for a given amount `t`(in nanoseconds). !!! note - Requires CUDA >= 10.0 and sm_6.2 + Requires compute capability 7.0. """ @inline function nanosleep(t::Unsigned) + require_sm_70() @asmcall("nanosleep.u32 \$0;", "r", true, Cvoid, Tuple{UInt32}, convert(UInt32, t)) end diff --git a/CUDACore/src/device/intrinsics/shared_memory.jl b/CUDACore/src/device/intrinsics/shared_memory.jl index 5d27514e16..b158e75103 100644 --- a/CUDACore/src/device/intrinsics/shared_memory.jl +++ b/CUDACore/src/device/intrinsics/shared_memory.jl @@ -84,6 +84,7 @@ end end @inline function map_shared_rank(ptr_shared::LLVMPtr{T,AS.Shared}, rank::Integer) where {T} + require_sm_90() # This requires LLVM >=20 (i.e. Julia >= 1.13) ptr7 = @asmcall( "mapa.shared::cluster.u64 \$0, \$1, \$2;", diff --git a/CUDACore/src/device/intrinsics/synchronization.jl b/CUDACore/src/device/intrinsics/synchronization.jl index 1d17f8f50d..2f1a49f728 100644 --- a/CUDACore/src/device/intrinsics/synchronization.jl +++ b/CUDACore/src/device/intrinsics/synchronization.jl @@ -55,7 +55,7 @@ visible to those threads in the warp. The default value for `mask` selects all t the warp. !!! note - Requires CUDA >= 9.0 and sm_6.2 + Requires PTX ISA 6.0 and sm_30. """ @inline sync_warp(mask=FULL_MASK) = ccall("llvm.nvvm.bar.warp.sync", llvmcall, Cvoid, (UInt32,), mask) @@ -89,8 +89,10 @@ for (fn, barrier) in ["cluster_arrive" => "arrive", } attributes #0 = { convergent nomerge nounwind } attributes #1 = { alwaysinline }""" - @eval @device_function @inline $(Symbol(fn))() = + @eval @device_function @inline function $(Symbol(fn))() + require_sm_90() Base.llvmcall(($mod, "entry"), Cvoid, Tuple{}) + end end ## memory barriers (membar) diff --git a/CUDACore/src/device/intrinsics/version.jl b/CUDACore/src/device/intrinsics/version.jl index ea66448bda..73d4c36871 100644 --- a/CUDACore/src/device/intrinsics/version.jl +++ b/CUDACore/src/device/intrinsics/version.jl @@ -2,6 +2,13 @@ export compute_capability, ptx_isa_version, target_feature_set +# Wire-format encoding of the feature set, stamped into the `sm_features` LLVM global. +@enum TargetFeatureSet::UInt32 begin + BaselineFeatures = 0 + FamilyFeatures = 1 + ArchFeatures = 2 +end + for var in ["sm_major", "sm_minor", "sm_features", "ptx_major", "ptx_minor"] @eval @device_function @inline $(Symbol(var))() = Base.llvmcall( @@ -17,16 +24,22 @@ end @device_function @inline compute_capability() = SimpleVersion(sm_major(), sm_minor()) @device_function @inline ptx_isa_version() = SimpleVersion(ptx_major(), ptx_minor()) +for cap in (sv"6.1", sv"7.0", sv"7.2", sv"8.0", sv"9.0") + local requirement = Symbol("require_sm_", cap.major, cap.minor) + local message = "requires compute capability $(cap.major).$(cap.minor) or higher" + @eval @device_function @inline $requirement() = + GPUCompiler.@static_assert compute_capability() >= $cap $message +end + # Feature set encoded in the `.target` directive: one of `:baseline`, `:family`, `:arch`. # (NVIDIA's PTX ISA reference: ".target specifies the set of features in the target -# architecture for which the current PTX code was generated.") GPUCompiler stamps the -# encoding in via the `sm_features` LLVM global, using `GPUCompiler.TargetFeatureSet`; +# architecture for which the current PTX code was generated.") CUDA's compiler stamps the +# encoding in via the `sm_features` LLVM global, using `TargetFeatureSet`; # the integer load + chained compare folds away after LLVM inlines the constant, so # user code like `if target_feature_set() === :arch ... end` resolves to a single # branch in the PTX output. @device_function @inline function target_feature_set() f = sm_features() - return f == UInt32(GPUCompiler.ArchFeatures) ? :arch : - f == UInt32(GPUCompiler.FamilyFeatures) ? :family : :baseline + return f == UInt32(ArchFeatures) ? :arch : + f == UInt32(FamilyFeatures) ? :family : :baseline end - diff --git a/CUDACore/src/device/intrinsics/wmma.jl b/CUDACore/src/device/intrinsics/wmma.jl index 1963d9ee4a..06c21b5ae1 100644 --- a/CUDACore/src/device/intrinsics/wmma.jl +++ b/CUDACore/src/device/intrinsics/wmma.jl @@ -2,7 +2,7 @@ export WMMA module WMMA import ..LLVM -using ..CUDACore: AS, @device_function +using ..CUDACore: AS, @device_function, require_sm_70, require_sm_72, require_sm_80 using Core: LLVMPtr using BFloat16s: BFloat16 @@ -212,12 +212,23 @@ for ops in all_ldst_ops, ccall_name = "$llvm_intr" ptr_ty = :(LLVMPtr{$arr_ty, $addr_space_int}) + req = elem_type == "bf16" ? :(require_sm_80()) : + elem_type in ("u8", "s8", "s32") ? :(require_sm_72()) : :(require_sm_70()) if sz == 1 - @eval @device_function $func_name(src_addr, stride) = tuple(ccall($ccall_name, llvmcall, $frag_ty, ($ptr_ty, Int32), src_addr, stride)) + @eval @device_function function $func_name(src_addr, stride) + $req + tuple(ccall($ccall_name, llvmcall, $frag_ty, + ($ptr_ty, Int32), src_addr, stride)) + end else struct_ty = Symbol("LLVMStruct$sz") - @eval @device_function $func_name(src_addr, stride) = convert(NTuple{$sz, $frag_ty}, ccall($ccall_name, llvmcall, $struct_ty{$frag_ty}, ($ptr_ty, Int32), src_addr, stride)) + @eval @device_function function $func_name(src_addr, stride) + $req + convert(NTuple{$sz, $frag_ty}, + ccall($ccall_name, llvmcall, $struct_ty{$frag_ty}, + ($ptr_ty, Int32), src_addr, stride)) + end end @eval export $func_name @eval @doc (@doc llvm_wmma_load) $func_name @@ -283,8 +294,13 @@ export llvm_wmma_store frag_vars = ntuple(i -> :(data[$i]), sz) ptr_ty = :(LLVMPtr{$arr_ty, $addr_space_int}) + req = elem_type == "s32" ? :(require_sm_72()) : :(require_sm_70()) - @eval @device_function $func_name(dst_addr, data, stride) = ccall($ccall_name, llvmcall, Nothing, ($ptr_ty, $(frag_types...), Int32), dst_addr, $(frag_vars...), stride) + @eval @device_function function $func_name(dst_addr, data, stride) + $req + ccall($ccall_name, llvmcall, Nothing, + ($ptr_ty, $(frag_types...), Int32), dst_addr, $(frag_vars...), stride) + end @eval export $func_name @eval @doc (@doc llvm_wmma_store) $func_name end @@ -359,12 +375,25 @@ for ops in all_wmma_ops, a_vars = ntuple(i -> :(a[$i]), a_sz) b_vars = ntuple(i -> :(b[$i]), b_sz) c_vars = ntuple(i -> :(c[$i]), c_sz) + req = a_elem_type == "bf16" ? :(require_sm_80()) : + a_elem_type in ("u8", "s8") ? :(require_sm_72()) : :(require_sm_70()) if d_sz == 1 - @eval @device_function $func_name(a, b, c) = tuple(ccall($ccall_name, llvmcall, $d_frag_ty, ($(a_types...), $(b_types...), $(c_types...)), $(a_vars...), $(b_vars...), $(c_vars...))) + @eval @device_function function $func_name(a, b, c) + $req + tuple(ccall($ccall_name, llvmcall, $d_frag_ty, + ($(a_types...), $(b_types...), $(c_types...)), + $(a_vars...), $(b_vars...), $(c_vars...))) + end else struct_ty = Symbol("LLVMStruct$d_sz") - @eval @device_function $func_name(a, b, c) = convert(NTuple{$d_sz, $d_frag_ty}, ccall($ccall_name, llvmcall, $struct_ty{$d_frag_ty}, ($(a_types...), $(b_types...), $(c_types...)), $(a_vars...), $(b_vars...), $(c_vars...))) + @eval @device_function function $func_name(a, b, c) + $req + convert(NTuple{$d_sz, $d_frag_ty}, + ccall($ccall_name, llvmcall, $struct_ty{$d_frag_ty}, + ($(a_types...), $(b_types...), $(c_types...)), + $(a_vars...), $(b_vars...), $(c_vars...))) + end end @eval export $func_name @eval @doc (@doc llvm_wmma_mma) $func_name diff --git a/test/core/device/intrinsics.jl b/test/core/device/intrinsics.jl index 504ef8c3b5..dee47b451e 100644 --- a/test/core/device/intrinsics.jl +++ b/test/core/device/intrinsics.jl @@ -41,6 +41,7 @@ end ############################################################################################ + @testset "assertion" begin function kernel(i) @cuassert i > 0 @@ -51,6 +52,59 @@ end @cuda kernel(1) end +@testset "target requirements" begin + out = CUDA.zeros(UInt32, 1) + + function dp4a_kernel(out) + @inbounds out[] = CUDA.dp4a(Int32(1), Int32(2), Int32(3)) + return + end + @test_throws "requires compute capability 6.1" @cuda launch=false arch=sm"60" dp4a_kernel(out) + + nanosleep_kernel() = nanosleep(UInt32(1)) + @test_throws "requires compute capability 7.0" @cuda launch=false arch=sm"61" nanosleep_kernel() + + out16 = CUDA.zeros(UInt16, 1) + function atomic_cas_kernel(out) + CUDA.atomic_cas!(pointer(out), UInt16(0), UInt16(1)) + return + end + @test_throws "requires compute capability 7.0" @cuda launch=false arch=sm"61" atomic_cas_kernel(out16) + + outf16 = CUDA.zeros(Float16, 16 * 16) + function wmma_kernel(out) + CUDA.WMMA.llvm_wmma_load_a_col_m16n16k16_global_stride_f16( + pointer(out), Int32(16)) + return + end + @test_throws "requires compute capability 7.0" @cuda launch=false arch=sm"61" wmma_kernel(outf16) + + outi8 = CUDA.zeros(Int8, 16 * 16) + function wmma_int_kernel(out) + CUDA.WMMA.llvm_wmma_load_a_col_m16n16k16_global_stride_s8( + pointer(out), Int32(16)) + return + end + @test_throws "requires compute capability 7.2" @cuda launch=false arch=sm"70" wmma_int_kernel(outi8) + + outbf16 = CUDA.zeros(CUDACore.BFloat16, 16 * 16) + function wmma_bf16_kernel(out) + CUDA.WMMA.llvm_wmma_load_a_col_m16n16k16_global_stride_bf16( + pointer(out), Int32(16)) + return + end + @test_throws "requires compute capability 8.0" @cuda launch=false arch=sm"72" wmma_bf16_kernel(outbf16) + + cluster_kernel() = cluster_arrive() + @test_throws "requires compute capability 9.0" @cuda launch=false arch=sm"80" cluster_kernel() + + function distributed_shared_kernel() + CuDistributedSharedArray(CuStaticSharedArray(UInt32, 1), 1) + return + end + @test_throws "requires compute capability 9.0" @cuda launch=false arch=sm"80" distributed_shared_kernel() +end + ############################################################################################ @@ -337,4 +391,3 @@ capability(device()) >= v"9" || # JuliaGPU/CUDA.jl#1846 end ############################################################################################ - diff --git a/test/core/device/intrinsics/wmma.jl b/test/core/device/intrinsics/wmma.jl index 3281c56157..4a758f060d 100644 --- a/test/core/device/intrinsics/wmma.jl +++ b/test/core/device/intrinsics/wmma.jl @@ -47,7 +47,7 @@ end end # Skip integer WMMA on older devices - if capability(device()) < v"7.5" && (startswith(elem_type, "s") || + if capability(device()) < v"7.2" && (startswith(elem_type, "s") || startswith(elem_type, "u")) continue end @@ -118,7 +118,7 @@ end end # Skip integer WMMA on older devices - if capability(device()) < v"7.5" && (startswith(elem_type, "s") || + if capability(device()) < v"7.2" && (startswith(elem_type, "s") || startswith(elem_type, "u")) continue end @@ -182,7 +182,7 @@ end c_elem_type in ops[3] # Skip integer WMMA on older devices - if capability(device()) < v"7.5" && (startswith(ab_elem_type, "s") || + if capability(device()) < v"7.2" && (startswith(ab_elem_type, "s") || startswith(ab_elem_type, "u")) continue end diff --git a/test/core/execution.jl b/test/core/execution.jl index 83901410e7..94c34ea545 100644 --- a/test/core/execution.jl +++ b/test/core/execution.jl @@ -61,10 +61,9 @@ end end @cuda threads=2 dummy() - # sm_10 isn't supported by LLVM - @test_throws "not supported by LLVM" @cuda launch=false arch=sm"10" dummy() - # sm_20 is, but not by any CUDA version we support - @test_throws "Failed to compile PTX code" @cuda launch=false arch=sm"20" dummy() + # Older targets may be known to LLVM/PTX, but not to any CUDA version we support. + @test_throws "requires compute capability sm_50" @cuda launch=false arch=sm"10" dummy() + @test_throws "requires compute capability sm_50" @cuda launch=false arch=sm"20" dummy() # there isn't any capability other than the device's that's guaruanteed to work dev_cap = capability(device()) dev_sm = SMVersion(dev_cap.major, dev_cap.minor) @@ -85,10 +84,11 @@ end # explicit `ptx=` is taken as an exact request (codegen-test affordance), so the # `.version` line should match what was asked for, independently of what LLVM and # ptxas would natively pick. - @test @filecheck CUDA.code_ptx((); ptx=v"6.3") do - @check ".version 6.3" + @test @filecheck CUDA.code_ptx((); ptx=v"8.0") do + @check ".version 8.0" dummy() end + @test_throws "requires PTX ISA 8.0" @cuda launch=false ptx=v"7.8" dummy() # explicit `ptx=` is validated against BOTH LLVM and ptxas (not just LLVM as it # used to be); a clearly out-of-range value must error at config time. @@ -143,16 +143,24 @@ end else UInt32(0) end + cc = compute_capability() + ptx = ptx_isa_version() + @inbounds out[2] = cc.major + @inbounds out[3] = cc.minor + @inbounds out[4] = ptx.major + @inbounds out[5] = ptx.minor return end - out = CuArray{UInt32}([typemax(UInt32)]) + out = CUDA.fill(typemax(UInt32), 5) @cuda threads=1 read_feature_set!(out) # arch features come through `target_feature_set()` only when the back-end LLVM # natively supports the variant; otherwise we fell back to baseline and the # global reflects that. arch_in_llvm = sm_a in CUDACore.llvm_compat().sm expected = dev_cap >= v"9.0" && arch_in_llvm ? UInt32(2) : UInt32(0) - @test Array(out)[1] == expected + target = CUDACore.compiler_config(device()).target + @test Array(out) == UInt32[expected, target.cap.major, target.cap.minor, + target.ptx.major, target.ptx.minor] end