From bcdbe8ae7c08c21dfaca29e5fd4ce3fce68a0969 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 27 Apr 2020 14:16:26 +0200 Subject: [PATCH] Make the native target extendable, and use it to cover error tests. --- src/native.jl | 11 +--- test/gcn.jl | 137 ---------------------------------------- test/native.jl | 167 +++++++++++++++++++++++++++++++++++++++++++++++-- test/ptx.jl | 136 ---------------------------------------- 4 files changed, 165 insertions(+), 286 deletions(-) diff --git a/src/native.jl b/src/native.jl index b430c19e..4174245b 100644 --- a/src/native.jl +++ b/src/native.jl @@ -22,20 +22,13 @@ function llvm_machine(target::NativeCompilerTarget) return tm end -module NativeRuntime - malloc(sz) = return - report_oom(sz) = return -end - -runtime_module(target::NativeCompilerTarget) = NativeRuntime - ## job export NativeCompilerJob Base.@kwdef struct NativeCompilerJob <: AbstractCompilerJob - target::NativeCompilerTarget + target::AbstractCompilerTarget source::FunctionSpec end @@ -50,6 +43,6 @@ function Base.show(io::IO, job::NativeCompilerJob) print(io, " for $(target(job).cpu) $(target(job).features)") end -runtime_slug(job::NativeCompilerJob) = "native_$(target(job).cpu)-$(hash(target(job).features))" +runtime_slug(job::NativeCompilerJob) = "native_$(Base.parent(target(job)).cpu)-$(hash(Base.parent(target(job)).features))" add_lowering_passes!(::NativeCompilerJob, pm::LLVM.PassManager) = return diff --git a/test/gcn.jl b/test/gcn.jl index c298330f..82023dc3 100644 --- a/test/gcn.jl +++ b/test/gcn.jl @@ -232,143 +232,6 @@ end end - -############################################################################################ - -@testset "errors" begin - -# some validation happens in the emit_function hook, which is called by gcn_code_llvm - -@testset "base intrinsics" begin - foobar(i) = sin(i) - - # NOTE: we don't use test_logs in order to test all of the warning (exception, backtrace) - logs, _ = Test.collect_test_logs(min_level=Info) do - withenv("JULIA_DEBUG" => nothing) do - gcn_code_llvm(devnull, foobar, Tuple{Int}) - end - end - @test length(logs) == 1 - record = logs[1] - @test record.level == Base.CoreLogging.Warn - @test record.message == "calls to Base intrinsics might be GPU incompatible" - @test haskey(record.kwargs, :exception) - err,bt = record.kwargs[:exception] - err_msg = sprint(showerror, err) - @test occursin(Regex("You called sin(.+) in Base.Math .+, maybe you intended to call sin(.+) in $TestRuntime .+ instead?"), err_msg) - bt_msg = sprint(Base.show_backtrace, bt) - @test occursin("[1] sin", bt_msg) - @test occursin(r"\[2\] .+foobar", bt_msg) -end - -# some validation happens in `compile` - -@eval Main begin -struct CleverType{T} - x::T -end -Base.unsafe_trunc(::Type{Int}, x::CleverType) = unsafe_trunc(Int, x.x) -end - -@testset "non-isbits arguments" begin - foobar(i) = (sink(unsafe_trunc(Int,i)); return) - - @test_throws_message(KernelError, - gcn_code_llvm(foobar, Tuple{BigInt}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("BigInt", msg) - end - - # test that we can handle abstract types - @test_throws_message(KernelError, - gcn_code_llvm(foobar, Tuple{Any}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("Any", msg) - end - - @test_throws_message(KernelError, - gcn_code_llvm(foobar, Tuple{Union{Int32, Int64}}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("Union{Int32, Int64}", msg) - end - - @test_throws_message(KernelError, - gcn_code_llvm(foobar, Tuple{Union{Int32, Int64}}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("Union{Int32, Int64}", msg) - end - - # test that we get information about fields and reason why something is not isbits - @test_throws_message(KernelError, - gcn_code_llvm(foobar, Tuple{CleverType{BigInt}}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("CleverType", msg) && - occursin("BigInt", msg) - end -end - -@testset "invalid LLVM IR" begin - foobar(i) = println(i) - - @test_throws_message(InvalidIRError, - gcn_code_llvm(foobar, Tuple{Int}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.RUNTIME_FUNCTION, msg) && - occursin("[1] println", msg) && - occursin(r"\[2\] .+foobar", msg) - end -end - -@testset "invalid LLVM IR (ccall)" begin - foobar(p) = (unsafe_store!(p, ccall(:time, Cint, ())); nothing) - - @test_throws_message(InvalidIRError, - gcn_code_llvm(foobar, Tuple{Ptr{Int}}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.POINTER_FUNCTION, msg) && - occursin(r"\[1\] .+foobar", msg) - end -end - -@testset "delayed bindings" begin - kernel() = (undefined; return) - - @test_throws_message(InvalidIRError, - gcn_code_llvm(kernel, Tuple{}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.DELAYED_BINDING, msg) && - occursin("use of 'undefined'", msg) && - occursin(r"\[1\] .+kernel", msg) - end -end - -@testset "dynamic call (invoke)" begin - @eval @noinline nospecialize_child(@nospecialize(i)) = i - kernel(a, b) = (unsafe_store!(b, nospecialize_child(a)); return) - - @test_throws_message(InvalidIRError, - gcn_code_llvm(kernel, Tuple{Int,Ptr{Int}}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.DYNAMIC_CALL, msg) && - occursin("call to nospecialize_child", msg) && - occursin(r"\[1\] .+kernel", msg) - end -end - -@testset "dynamic call (apply)" begin - func() = pointer(1) - - @test_throws_message(InvalidIRError, - gcn_code_llvm(func, Tuple{}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.DYNAMIC_CALL, msg) && - occursin("call to pointer", msg) && - occursin("[1] func", msg) - end -end - -end - ############################################################################################ end diff --git a/test/native.jl b/test/native.jl index 6565b487..9185b9e6 100644 --- a/test/native.jl +++ b/test/native.jl @@ -1,5 +1,29 @@ @testset "native" begin +# create a native test compiler, and generate reflection methods for it + +struct NativeTestCompilerTarget <: CompositeCompilerTarget + parent::NativeCompilerTarget + + NativeTestCompilerTarget() = new(NativeCompilerTarget()) +end + +Base.parent(target::NativeTestCompilerTarget) = target.parent + +struct NativeTestCompilerJob <: CompositeCompilerJob + parent::AbstractCompilerJob +end + +GPUCompiler.runtime_module(target::NativeTestCompilerTarget) = TestRuntime + +NativeTestCompilerJob(target::AbstractCompilerTarget, source::FunctionSpec; kwargs...) = + NativeTestCompilerJob(NativeCompilerJob(target, source; kwargs...)) + +Base.similar(job::NativeTestCompilerJob, source::FunctionSpec; kwargs...) = + NativeTestCompilerJob(similar(job.parent, source; kwargs...)) + +Base.parent(job::NativeTestCompilerJob) = job.parent + for method in (:code_typed, :code_warntype, :code_llvm, :code_native) # only code_typed doesn't take a io argument args = method == :code_typed ? (:job,) : (:io, :job) @@ -7,11 +31,10 @@ for method in (:code_typed, :code_warntype, :code_llvm, :code_native) @eval begin function $native_method(io::IO, @nospecialize(func), @nospecialize(types); - kernel::Bool=false, minthreads=nothing, maxthreads=nothing, - blocks_per_sm=nothing, maxregs=nothing, kwargs...) + kernel::Bool=false, kwargs...) source = FunctionSpec(func, Base.to_tuple_type(types), kernel) - target = NativeCompilerTarget() - job = NativeCompilerJob(target=target, source=source) + target = NativeTestCompilerTarget() + job = NativeTestCompilerJob(target, source) GPUCompiler.$method($(args...); kwargs...) end $native_method(@nospecialize(func), @nospecialize(types); kwargs...) = @@ -145,4 +168,140 @@ end ############################################################################################ +@testset "errors" begin + +# some validation happens in the emit_function hook, which is called by code_llvm + +@testset "base intrinsics" begin + foobar(i) = sin(i) + + # NOTE: we don't use test_logs in order to test all of the warning (exception, backtrace) + logs, _ = Test.collect_test_logs(min_level=Info) do + withenv("JULIA_DEBUG" => nothing) do + native_code_llvm(devnull, foobar, Tuple{Int}) + end + end + @test length(logs) == 1 + record = logs[1] + @test record.level == Base.CoreLogging.Warn + @test record.message == "calls to Base intrinsics might be GPU incompatible" + @test haskey(record.kwargs, :exception) + err,bt = record.kwargs[:exception] + err_msg = sprint(showerror, err) + @test occursin(Regex("You called sin(.+) in Base.Math .+, maybe you intended to call sin(.+) in $TestRuntime .+ instead?"), err_msg) + bt_msg = sprint(Base.show_backtrace, bt) + @test occursin("[1] sin", bt_msg) + @test occursin(r"\[2\] .+foobar", bt_msg) +end + +# some validation happens in `compile` + +@eval Main begin +struct CleverType{T} + x::T +end +Base.unsafe_trunc(::Type{Int}, x::CleverType) = unsafe_trunc(Int, x.x) +end + +@testset "non-isbits arguments" begin + foobar(i) = (sink(unsafe_trunc(Int,i)); return) + + @test_throws_message(KernelError, + native_code_llvm(foobar, Tuple{BigInt}; strict=true)) do msg + occursin("passing and using non-bitstype argument", msg) && + occursin("BigInt", msg) + end + + # test that we can handle abstract types + @test_throws_message(KernelError, + native_code_llvm(foobar, Tuple{Any}; strict=true)) do msg + occursin("passing and using non-bitstype argument", msg) && + occursin("Any", msg) + end + + @test_throws_message(KernelError, + native_code_llvm(foobar, Tuple{Union{Int32, Int64}}; strict=true)) do msg + occursin("passing and using non-bitstype argument", msg) && + occursin("Union{Int32, Int64}", msg) + end + + @test_throws_message(KernelError, + native_code_llvm(foobar, Tuple{Union{Int32, Int64}}; strict=true)) do msg + occursin("passing and using non-bitstype argument", msg) && + occursin("Union{Int32, Int64}", msg) + end + + # test that we get information about fields and reason why something is not isbits + @test_throws_message(KernelError, + native_code_llvm(foobar, Tuple{CleverType{BigInt}}; strict=true)) do msg + occursin("passing and using non-bitstype argument", msg) && + occursin("CleverType", msg) && + occursin("BigInt", msg) + end +end + +@testset "invalid LLVM IR" begin + foobar(i) = println(i) + + @test_throws_message(InvalidIRError, + native_code_llvm(foobar, Tuple{Int}; strict=true)) do msg + occursin("invalid LLVM IR", msg) && + occursin(GPUCompiler.RUNTIME_FUNCTION, msg) && + occursin("[1] println", msg) && + occursin(r"\[2\] .+foobar", msg) + end +end + +@testset "invalid LLVM IR (ccall)" begin + foobar(p) = (unsafe_store!(p, ccall(:time, Cint, ())); nothing) + + @test_throws_message(InvalidIRError, + native_code_llvm(foobar, Tuple{Ptr{Int}}; strict=true)) do msg + occursin("invalid LLVM IR", msg) && + occursin(GPUCompiler.POINTER_FUNCTION, msg) && + occursin(r"\[1\] .+foobar", msg) + end +end + +@testset "delayed bindings" begin + kernel() = (undefined; return) + + @test_throws_message(InvalidIRError, + native_code_llvm(kernel, Tuple{}; strict=true)) do msg + occursin("invalid LLVM IR", msg) && + occursin(GPUCompiler.DELAYED_BINDING, msg) && + occursin("use of 'undefined'", msg) && + occursin(r"\[1\] .+kernel", msg) + end +end + +@testset "dynamic call (invoke)" begin + @eval @noinline nospecialize_child(@nospecialize(i)) = i + kernel(a, b) = (unsafe_store!(b, nospecialize_child(a)); return) + + @test_throws_message(InvalidIRError, + native_code_llvm(kernel, Tuple{Int,Ptr{Int}}; strict=true)) do msg + occursin("invalid LLVM IR", msg) && + occursin(GPUCompiler.DYNAMIC_CALL, msg) && + occursin("call to nospecialize_child", msg) && + occursin(r"\[1\] .+kernel", msg) + end +end + +@testset "dynamic call (apply)" begin + func() = pointer(1) + + @test_throws_message(InvalidIRError, + native_code_llvm(func, Tuple{}; strict=true)) do msg + occursin("invalid LLVM IR", msg) && + occursin(GPUCompiler.DYNAMIC_CALL, msg) && + occursin("call to pointer", msg) && + occursin("[1] func", msg) + end +end + +end + +############################################################################################ + end diff --git a/test/ptx.jl b/test/ptx.jl index 5cd44868..9b6c8645 100644 --- a/test/ptx.jl +++ b/test/ptx.jl @@ -302,142 +302,6 @@ end end -############################################################################################ - -@testset "errors" begin - -# some validation happens in the emit_function hook, which is called by ptx_code_llvm - -@testset "base intrinsics" begin - foobar(i) = sin(i) - - # NOTE: we don't use test_logs in order to test all of the warning (exception, backtrace) - logs, _ = Test.collect_test_logs(min_level=Info) do - withenv("JULIA_DEBUG" => nothing) do - ptx_code_llvm(devnull, foobar, Tuple{Int}) - end - end - @test length(logs) == 1 - record = logs[1] - @test record.level == Base.CoreLogging.Warn - @test record.message == "calls to Base intrinsics might be GPU incompatible" - @test haskey(record.kwargs, :exception) - err,bt = record.kwargs[:exception] - err_msg = sprint(showerror, err) - @test occursin(Regex("You called sin(.+) in Base.Math .+, maybe you intended to call sin(.+) in $TestRuntime .+ instead?"), err_msg) - bt_msg = sprint(Base.show_backtrace, bt) - @test occursin("[1] sin", bt_msg) - @test occursin(r"\[2\] .+foobar", bt_msg) -end - -# some validation happens in `compile` - -@eval Main begin -struct CleverType{T} - x::T -end -Base.unsafe_trunc(::Type{Int}, x::CleverType) = unsafe_trunc(Int, x.x) -end - -@testset "non-isbits arguments" begin - foobar(i) = (sink(unsafe_trunc(Int,i)); return) - - @test_throws_message(KernelError, - ptx_code_llvm(foobar, Tuple{BigInt}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("BigInt", msg) - end - - # test that we can handle abstract types - @test_throws_message(KernelError, - ptx_code_llvm(foobar, Tuple{Any}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("Any", msg) - end - - @test_throws_message(KernelError, - ptx_code_llvm(foobar, Tuple{Union{Int32, Int64}}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("Union{Int32, Int64}", msg) - end - - @test_throws_message(KernelError, - ptx_code_llvm(foobar, Tuple{Union{Int32, Int64}}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("Union{Int32, Int64}", msg) - end - - # test that we get information about fields and reason why something is not isbits - @test_throws_message(KernelError, - ptx_code_llvm(foobar, Tuple{CleverType{BigInt}}; strict=true)) do msg - occursin("passing and using non-bitstype argument", msg) && - occursin("CleverType", msg) && - occursin("BigInt", msg) - end -end - -@testset "invalid LLVM IR" begin - foobar(i) = println(i) - - @test_throws_message(InvalidIRError, - ptx_code_llvm(foobar, Tuple{Int}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.RUNTIME_FUNCTION, msg) && - occursin("[1] println", msg) && - occursin(r"\[2\] .+foobar", msg) - end -end - -@testset "invalid LLVM IR (ccall)" begin - foobar(p) = (unsafe_store!(p, ccall(:time, Cint, ())); nothing) - - @test_throws_message(InvalidIRError, - ptx_code_llvm(foobar, Tuple{Ptr{Int}}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.POINTER_FUNCTION, msg) && - occursin(r"\[1\] .+foobar", msg) - end -end - -@testset "delayed bindings" begin - kernel() = (undefined; return) - - @test_throws_message(InvalidIRError, - ptx_code_llvm(kernel, Tuple{}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.DELAYED_BINDING, msg) && - occursin("use of 'undefined'", msg) && - occursin(r"\[1\] .+kernel", msg) - end -end - -@testset "dynamic call (invoke)" begin - @eval @noinline nospecialize_child(@nospecialize(i)) = i - kernel(a, b) = (unsafe_store!(b, nospecialize_child(a)); return) - - @test_throws_message(InvalidIRError, - ptx_code_llvm(kernel, Tuple{Int,Ptr{Int}}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.DYNAMIC_CALL, msg) && - occursin("call to nospecialize_child", msg) && - occursin(r"\[1\] .+kernel", msg) - end -end - -@testset "dynamic call (apply)" begin - func() = pointer(1) - - @test_throws_message(InvalidIRError, - ptx_code_llvm(func, Tuple{}; strict=true)) do msg - occursin("invalid LLVM IR", msg) && - occursin(GPUCompiler.DYNAMIC_CALL, msg) && - occursin("call to pointer", msg) && - occursin("[1] func", msg) - end -end - -end - ############################################################################################ end