diff --git a/src/interface.jl b/src/interface.jl index 2620d23b..c91c2c10 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -615,7 +615,13 @@ function inference_params(@nospecialize(job::CompilerJob)) end # the optimization parameters to use when constructing the GPUInterpreter -optimization_params(@nospecialize(job::CompilerJob)) = CC.OptimizationParams() +# +# Emit `:invoke`s targeting the exact inferred specialization instead of the +# compileable (vararg-widened) signature: GPU back-ends cannot dispatch at run +# time, and widened signatures may have no inferred code in our cache (e.g. +# `Base._throw_boundserror_indices(A, i1, I...)` from bounds checks). +optimization_params(@nospecialize(job::CompilerJob)) = + CC.OptimizationParams(; compilesig_invokes=false) # how much debuginfo to emit function llvm_debug_info(@nospecialize(job::CompilerJob)) diff --git a/test/gcn.jl b/test/gcn.jl index e67e5e33..9396ade5 100644 --- a/test/gcn.jl +++ b/test/gcn.jl @@ -493,9 +493,10 @@ end @test @filecheck begin @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" - # box: a jl_box_float32 call <1.14; 1.14+ inlines it into the devirt'd ctor - @check cond=(VERSION < v"1.14-") "jl_box_float32" - @check cond=(VERSION >= v"1.14-") "gpu_gc_pool_alloc" + # box: a jl_box_float32 call on 1.10, which ignores compilesig_invokes; + # 1.11+ devirtualizes the ctor, boxing through the GC pool allocator instead + @check cond=(VERSION < v"1.11-") "jl_box_float32" + @check cond=(VERSION >= v"1.11-") "gpu_gc_pool_alloc" GCN.code_llvm(mod.kernel, Tuple{Float32,Ptr{Float32}}; dump_module=true) end GCN.code_native(devnull, mod.kernel, Tuple{Float32,Ptr{Float32}}) diff --git a/test/native.jl b/test/native.jl index 76358481..fbb19b97 100644 --- a/test/native.jl +++ b/test/native.jl @@ -1437,8 +1437,8 @@ end (occursin(GPUCompiler.RUNTIME_FUNCTION, msg) || occursin(GPUCompiler.UNKNOWN_FUNCTION, msg) || occursin(GPUCompiler.DYNAMIC_CALL, msg)) && - occursin("[1] println", msg) && - occursin("[2] foobar", msg) + occursin(r"\[\d+\] println", msg) && + occursin(r"\[\d+\] foobar", msg) end end @@ -1561,26 +1561,40 @@ end kernel(a, b) = (unsafe_store!(b, nospecialize_child(a)); return) end - @test_throws_message(InvalidIRError, - Native.code_execution(mod.kernel, Tuple{Int,Ptr{Int}})) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.DYNAMIC_CALL, msg) && - occursin("call to nospecialize_child", msg) && - occursin("[1] kernel", msg) + if VERSION >= v"1.11-" + # with compilesig_invokes=false, the call targets the exact specialization + # instead of a (possibly uncached) vararg-widened compileable signature, + # so no dynamic call remains + @test @filecheck begin + @check_label "define {{.*}} @{{(julia|j)_kernel_[0-9]+}}" + @check_not "jl_invoke" + @check_not "apply_generic" + Native.code_llvm(mod.kernel, Tuple{Int,Ptr{Int}}; dump_module=true) + end + Native.code_execution(mod.kernel, Tuple{Int,Ptr{Int}}) + else + # 1.10 ignores compilesig_invokes and emits a dynamic invoke + @test_throws_message(InvalidIRError, + Native.code_execution(mod.kernel, Tuple{Int,Ptr{Int}})) do msg + occursin("invalid LLVM IR", msg) && + occursin(GPUCompiler.DYNAMIC_CALL, msg) && + occursin("call to nospecialize_child", msg) && + occursin(r"\[\d+\] kernel", msg) + end end end @testset "dynamic call (apply)" begin mod = @eval module $(gensym()) - func() = println(1) + func(a) = (print(Base.inferencebarrier(a)); return) end @test_throws_message(InvalidIRError, - Native.code_execution(mod.func, Tuple{})) do msg + Native.code_execution(mod.func, Tuple{Int})) do msg occursin("invalid LLVM IR", msg) && occursin(GPUCompiler.DYNAMIC_CALL, msg) && occursin("call to print", msg) && - occursin("[2] func", msg) + occursin(r"\[\d+\] func", msg) end end diff --git a/test/ptx.jl b/test/ptx.jl index 3ab82d07..e3394107 100644 --- a/test/ptx.jl +++ b/test/ptx.jl @@ -493,9 +493,10 @@ end @test @filecheck begin @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" - # box: a jl_box_float32 call <1.14; 1.14+ inlines it into the devirt'd ctor - @check cond=(VERSION < v"1.14-") "jl_box_float32" - @check cond=(VERSION >= v"1.14-") "gpu_gc_pool_alloc" + # box: a jl_box_float32 call on 1.10, which ignores compilesig_invokes; + # 1.11+ devirtualizes the ctor, boxing through the GC pool allocator instead + @check cond=(VERSION < v"1.11-") "jl_box_float32" + @check cond=(VERSION >= v"1.11-") "gpu_gc_pool_alloc" PTX.code_llvm(mod.kernel, Tuple{Float32,Ptr{Float32}}; dump_module=true) end PTX.code_native(devnull, mod.kernel, Tuple{Float32,Ptr{Float32}})