-
Notifications
You must be signed in to change notification settings - Fork 54
Allow the use of FileCheck #703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Your PR requires formatting changes to meet the project's style guidelines. Click here to view the suggested changes.diff --git a/test/bpf.jl b/test/bpf.jl
index a4b10f3..58d26a0 100644
--- a/test/bpf.jl
+++ b/test/bpf.jl
@@ -1,6 +1,6 @@
@testset "No-op" begin
mod = @eval module $(gensym())
- kernel() = 0
+ kernel() = 0
end
@test @filecheck begin
@@ -12,7 +12,7 @@
end
@testset "Return argument" begin
mod = @eval module $(gensym())
- kernel(x) = x
+ kernel(x) = x
end
@test @filecheck begin
@@ -24,7 +24,7 @@ end
end
@testset "Addition" begin
mod = @eval module $(gensym())
- kernel(x) = x+1
+ kernel(x) = x + 1
end
@test @filecheck begin
@@ -37,7 +37,7 @@ end
end
@testset "Errors" begin
mod = @eval module $(gensym())
- kernel(x) = fakefunc(x)
+ kernel(x) = fakefunc(x)
end
@test_throws GPUCompiler.InvalidIRError BPF.code_execution(mod.kernel, (UInt64,))
@@ -45,8 +45,8 @@ end
@testset "Function Pointers" begin
@testset "valid" begin
mod = @eval module $(gensym())
- goodcall(x) = Base.llvmcall("%2 = call i64 inttoptr (i64 3 to i64 (i64)*)(i64 %0)\nret i64 %2", Int, Tuple{Int}, x)
- kernel(x) = goodcall(x)
+ goodcall(x) = Base.llvmcall("%2 = call i64 inttoptr (i64 3 to i64 (i64)*)(i64 %0)\nret i64 %2", Int, Tuple{Int}, x)
+ kernel(x) = goodcall(x)
end
@test @filecheck begin
@@ -59,8 +59,8 @@ end
@testset "invalid" begin
mod = @eval module $(gensym())
- badcall(x) = Base.llvmcall("%2 = call i64 inttoptr (i64 3000 to i64 (i64)*)(i64 %0)\nret i64 %2", Int, Tuple{Int}, x)
- kernel(x) = badcall(x)
+ badcall(x) = Base.llvmcall("%2 = call i64 inttoptr (i64 3000 to i64 (i64)*)(i64 %0)\nret i64 %2", Int, Tuple{Int}, x)
+ kernel(x) = badcall(x)
end
@test_throws GPUCompiler.InvalidIRError BPF.code_execution(mod.kernel, (Int,))
diff --git a/test/gcn.jl b/test/gcn.jl
index 0108d6a..ab4d30c 100644
--- a/test/gcn.jl
+++ b/test/gcn.jl
@@ -1,24 +1,24 @@
if :AMDGPU in LLVM.backends()
-# XXX: generic `sink` generates an instruction selection error
-sink_gcn(i) = sink(i, Val(5))
+ # XXX: generic `sink` generates an instruction selection error
+ sink_gcn(i) = sink(i, Val(5))
@testset "IR" begin
@testset "kernel calling convention" begin
- mod = @eval module $(gensym())
- kernel() = return
- end
+ mod = @eval module $(gensym())
+ kernel() = return
+ end
- @test @filecheck begin
- check"CHECK-NOT: amdgpu_kernel"
- GCN.code_llvm(mod.kernel, Tuple{}; dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-NOT: amdgpu_kernel"
+ GCN.code_llvm(mod.kernel, Tuple{}; dump_module = true)
+ end
- @test @filecheck begin
- check"CHECK: amdgpu_kernel"
- GCN.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK: amdgpu_kernel"
+ GCN.code_llvm(mod.kernel, Tuple{}; dump_module = true, kernel = true)
+ end
end
end
@@ -27,62 +27,62 @@ end
@testset "assembly" begin
@testset "skip scalar trap" begin
- mod = @eval module $(gensym())
- workitem_idx_x() = ccall("llvm.amdgcn.workitem.id.x", llvmcall, Int32, ())
- trap() = ccall("llvm.trap", llvmcall, Nothing, ())
-
- function kernel()
- if workitem_idx_x() > 1
- trap()
+ mod = @eval module $(gensym())
+ workitem_idx_x() = ccall("llvm.amdgcn.workitem.id.x", llvmcall, Int32, ())
+ trap() = ccall("llvm.trap", llvmcall, Nothing, ())
+
+ function kernel()
+ if workitem_idx_x() > 1
+ trap()
+ end
+ return
end
- return
- end
end
- @test @filecheck begin
- check"CHECK-LABEL: {{(julia|j)_kernel_[0-9]+}}:"
- check"CHECK: s_cbranch_exec"
- check"CHECK: s_trap 2"
- GCN.code_native(mod.kernel, Tuple{})
+ @test @filecheck begin
+ check"CHECK-LABEL: {{(julia|j)_kernel_[0-9]+}}:"
+ check"CHECK: s_cbranch_exec"
+ check"CHECK: s_trap 2"
+ GCN.code_native(mod.kernel, Tuple{})
end
end
@testset "child functions" begin
# we often test using @noinline child functions, so test whether these survive
# (despite not having side-effects)
- mod = @eval module $(gensym())
- import ..sink_gcn
- @noinline child(i) = sink_gcn(i)
- function parent(i)
- child(i)
- return
- end
+ mod = @eval module $(gensym())
+ import ..sink_gcn
+ @noinline child(i) = sink_gcn(i)
+ function parent(i)
+ child(i)
+ return
+ end
end
- @test @filecheck begin
- check"CHECK-LABEL: {{(julia|j)_parent_[0-9]+}}:"
- check"CHECK: s_add_u32 {{.+}} {{(julia|j)_child_[0-9]+}}@rel32@"
- check"CHECK: s_addc_u32 {{.+}} {{(julia|j)_child_[0-9]+}}@rel32@"
- GCN.code_native(mod.parent, Tuple{Int64}; dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: {{(julia|j)_parent_[0-9]+}}:"
+ check"CHECK: s_add_u32 {{.+}} {{(julia|j)_child_[0-9]+}}@rel32@"
+ check"CHECK: s_addc_u32 {{.+}} {{(julia|j)_child_[0-9]+}}@rel32@"
+ GCN.code_native(mod.parent, Tuple{Int64}; dump_module = true)
+ end
end
@testset "kernel functions" begin
- mod = @eval module $(gensym())
- import ..sink_gcn
- @noinline nonentry(i) = sink_gcn(i)
- function entry(i)
- nonentry(i)
- return
- end
+ mod = @eval module $(gensym())
+ import ..sink_gcn
+ @noinline nonentry(i) = sink_gcn(i)
+ function entry(i)
+ nonentry(i)
+ return
+ end
end
- @test @filecheck begin
- check"CHECK-NOT: .amdhsa_kernel {{(julia|j)_nonentry_[0-9]+}}"
- check"CHECK: .type {{(julia|j)_nonentry_[0-9]+}},@function"
- check"CHECK: .amdhsa_kernel _Z5entry5Int64"
- GCN.code_native(mod.entry, Tuple{Int64}; dump_module=true, kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK-NOT: .amdhsa_kernel {{(julia|j)_nonentry_[0-9]+}}"
+ check"CHECK: .type {{(julia|j)_nonentry_[0-9]+}},@function"
+ check"CHECK: .amdhsa_kernel _Z5entry5Int64"
+ GCN.code_native(mod.entry, Tuple{Int64}; dump_module = true, kernel = true)
+ end
end
@testset "child function reuse" begin
@@ -90,7 +90,7 @@ end
# the child only being present once
mod = @eval module $(gensym())
- import ..sink_gcn
+ import ..sink_gcn
@noinline child(i) = sink_gcn(i)
function parent1(i)
child(i)
@@ -102,15 +102,15 @@ end
end
end
- @test @filecheck begin
- check"CHECK: .type {{(julia|j)_child_[0-9]+}},@function"
- GCN.code_native(mod.parent1, Tuple{Int}; dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK: .type {{(julia|j)_child_[0-9]+}},@function"
+ GCN.code_native(mod.parent1, Tuple{Int}; dump_module = true)
+ end
- @test @filecheck begin
- check"CHECK: .type {{(julia|j)_child_[0-9]+}},@function"
- GCN.code_native(mod.parent2, Tuple{Int}; dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK: .type {{(julia|j)_child_[0-9]+}},@function"
+ GCN.code_native(mod.parent2, Tuple{Int}; dump_module = true)
+ end
end
@testset "child function reuse bis" begin
@@ -118,7 +118,7 @@ end
# in the case of two child functions
mod = @eval module $(gensym())
- import ..sink_gcn
+ import ..sink_gcn
@noinline child1(i) = sink_gcn(i)
@noinline child2(i) = sink_gcn(i+1)
function parent1(i)
@@ -131,17 +131,17 @@ end
end
end
- @test @filecheck begin
- check"CHECK-DAG: .type {{(julia|j)_child1_[0-9]+}},@function"
- check"CHECK-DAG: .type {{(julia|j)_child2_[0-9]+}},@function"
- GCN.code_native(mod.parent1, Tuple{Int}; dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-DAG: .type {{(julia|j)_child1_[0-9]+}},@function"
+ check"CHECK-DAG: .type {{(julia|j)_child2_[0-9]+}},@function"
+ GCN.code_native(mod.parent1, Tuple{Int}; dump_module = true)
+ end
- @test @filecheck begin
- check"CHECK-DAG: .type {{(julia|j)_child1_[0-9]+}},@function"
- check"CHECK-DAG: .type {{(julia|j)_child2_[0-9]+}},@function"
- GCN.code_native(mod.parent2, Tuple{Int}; dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-DAG: .type {{(julia|j)_child1_[0-9]+}},@function"
+ check"CHECK-DAG: .type {{(julia|j)_child2_[0-9]+}},@function"
+ GCN.code_native(mod.parent2, Tuple{Int}; dump_module = true)
+ end
end
@testset "indirect sysimg function use" begin
@@ -150,57 +150,57 @@ end
# NOTE: Int32 to test for #49
- mod = @eval module $(gensym())
- function kernel(out)
- wid, lane = fldmod1(unsafe_load(out), Int32(32))
- unsafe_store!(out, wid)
- return
- end
+ mod = @eval module $(gensym())
+ function kernel(out)
+ wid, lane = fldmod1(unsafe_load(out), Int32(32))
+ unsafe_store!(out, wid)
+ return
+ end
end
- @test @filecheck begin
- check"CHECK-LABEL: {{(julia|j)_kernel_[0-9]+}}:"
- check"CHECK-NOT: jl_throw"
- check"CHECK-NOT: jl_invoke"
- GCN.code_native(mod.kernel, Tuple{Ptr{Int32}})
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: {{(julia|j)_kernel_[0-9]+}}:"
+ check"CHECK-NOT: jl_throw"
+ check"CHECK-NOT: jl_invoke"
+ GCN.code_native(mod.kernel, Tuple{Ptr{Int32}})
+ end
end
@testset "LLVM intrinsics" begin
# issue #13 (a): cannot select trunc
- mod = @eval module $(gensym())
- function kernel(x)
- unsafe_trunc(Int, x)
- return
- end
+ mod = @eval module $(gensym())
+ function kernel(x)
+ unsafe_trunc(Int, x)
+ return
+ end
end
- GCN.code_native(devnull, mod.kernel, Tuple{Float64})
+ GCN.code_native(devnull, mod.kernel, Tuple{Float64})
@test "We did not crash!" != ""
end
# FIXME: _ZNK4llvm14TargetLowering20scalarizeVectorStoreEPNS_11StoreSDNodeERNS_12SelectionDAGE
false && @testset "exception arguments" begin
- mod = @eval module $(gensym())
- function kernel(a)
- unsafe_store!(a, trunc(Int, unsafe_load(a)))
- return
- end
+ mod = @eval module $(gensym())
+ function kernel(a)
+ unsafe_store!(a, trunc(Int, unsafe_load(a)))
+ return
+ end
end
- GCN.code_native(devnull, mod.kernel, Tuple{Ptr{Float64}})
+ GCN.code_native(devnull, mod.kernel, Tuple{Ptr{Float64}})
end
# FIXME: in function julia_inner_18528 void (%jl_value_t addrspace(10)*): invalid addrspacecast
false && @testset "GC and TLS lowering" begin
mod = @eval module $(gensym())
- import ..sink_gcn
+ import ..sink_gcn
mutable struct PleaseAllocate
y::Csize_t
end
# common pattern in Julia 0.7: outlined throw to avoid a GC frame in the calling code
@noinline function inner(x)
- sink_gcn(x.y)
+ sink_gcn(x.y)
nothing
end
@@ -210,14 +210,14 @@ false && @testset "GC and TLS lowering" begin
end
end
- @test @filecheck begin
- check"CHECK-NOT: jl_push_gc_frame"
- check"CHECK-NOT: jl_pop_gc_frame"
- check"CHECK-NOT: jl_get_gc_frame_slot"
- check"CHECK-NOT: jl_new_gc_frame"
- check"CHECK: gpu_gc_pool_alloc"
- GCN.code_native(mod.kernel, Tuple{Int})
- end
+ @test @filecheck begin
+ check"CHECK-NOT: jl_push_gc_frame"
+ check"CHECK-NOT: jl_pop_gc_frame"
+ check"CHECK-NOT: jl_get_gc_frame_slot"
+ check"CHECK-NOT: jl_new_gc_frame"
+ check"CHECK: gpu_gc_pool_alloc"
+ GCN.code_native(mod.kernel, Tuple{Int})
+ end
# make sure that we can still ellide allocations
function ref_kernel(ptr, i)
@@ -232,31 +232,31 @@ false && @testset "GC and TLS lowering" begin
return nothing
end
- @test @filecheck begin
- check"CHECK-NOT: gpu_gc_pool_alloc"
- GCN.code_native(ref_kernel, Tuple{Ptr{Int64}, Int})
- end
+ @test @filecheck begin
+ check"CHECK-NOT: gpu_gc_pool_alloc"
+ GCN.code_native(ref_kernel, Tuple{Ptr{Int64}, Int})
+ end
end
@testset "float boxes" begin
- mod = @eval module $(gensym())
- function kernel(a,b)
- c = Int32(a)
- # the conversion to Int32 may fail, in which case the input Float32 is boxed in order to
- # pass it to the @nospecialize exception constructor. we should really avoid that (eg.
- # by avoiding @nospecialize, or optimize the unused arguments away), but for now the box
- # should just work.
- unsafe_store!(b, c)
- return
- end
- end
+ mod = @eval module $(gensym())
+ function kernel(a, b)
+ c = Int32(a)
+ # the conversion to Int32 may fail, in which case the input Float32 is boxed in order to
+ # pass it to the @nospecialize exception constructor. we should really avoid that (eg.
+ # by avoiding @nospecialize, or optimize the unused arguments away), but for now the box
+ # should just work.
+ unsafe_store!(b, c)
+ return
+ end
+ end
- @test @filecheck begin
- check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
- check"CHECK: jl_box_float32"
- GCN.code_llvm(mod.kernel, Tuple{Float32,Ptr{Float32}})
- end
- GCN.code_native(devnull, mod.kernel, Tuple{Float32,Ptr{Float32}})
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
+ check"CHECK: jl_box_float32"
+ GCN.code_llvm(mod.kernel, Tuple{Float32, Ptr{Float32}})
+ end
+ GCN.code_native(devnull, mod.kernel, Tuple{Float32, Ptr{Float32}})
end
end
diff --git a/test/helpers/test.jl b/test/helpers/test.jl
index 014ddb2..0256785 100644
--- a/test/helpers/test.jl
+++ b/test/helpers/test.jl
@@ -47,10 +47,10 @@ module FileCheck
global filecheck_path::String
function __init__()
- global filecheck_path = joinpath(LLVM_jll.artifact_dir, "tools", "FileCheck")
+ return global filecheck_path = joinpath(LLVM_jll.artifact_dir, "tools", "FileCheck")
end
- function filecheck_exe(; adjust_PATH::Bool=true, adjust_LIBPATH::Bool=true)
+ function filecheck_exe(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true)
env = Base.invokelatest(
LLVM_jll.JLLWrappers.adjust_ENV!,
copy(ENV),
@@ -69,12 +69,12 @@ module FileCheck
function filecheck(f, input)
# FileCheck assumes that the input is available as a file
- mktemp() do path, input_io
+ return mktemp() do path, input_io
write(input_io, input)
close(input_io)
# capture the output of `f` and write it into a temporary buffer
- result = IOCapture.capture(rethrow=Union{}) do
+ result = IOCapture.capture(rethrow = Union{}) do
f(input)
end
output_io = IOBuffer()
@@ -90,9 +90,11 @@ module FileCheck
end
# determine some useful prefixes for FileCheck
- prefixes = ["CHECK",
- "JULIA$(VERSION.major)_$(VERSION.minor)",
- "LLVM$(Base.libllvm_version.major)"]
+ prefixes = [
+ "CHECK",
+ "JULIA$(VERSION.major)_$(VERSION.minor)",
+ "LLVM$(Base.libllvm_version.major)",
+ ]
## whether we use typed pointers or opaque pointers
if julia_typed_pointers
push!(prefixes, "TYPED")
@@ -110,11 +112,11 @@ module FileCheck
seekstart(output_io)
filecheck_io = Pipe()
cmd = ```$(filecheck_exe())
- --color
- --allow-unused-prefixes
- --check-prefixes $(join(prefixes, ','))
- $path```
- proc = run(pipeline(ignorestatus(cmd); stdin=output_io, stdout=filecheck_io, stderr=filecheck_io); wait=false)
+ --color
+ --allow-unused-prefixes
+ --check-prefixes $(join(prefixes, ','))
+ $path```
+ proc = run(pipeline(ignorestatus(cmd); stdin = output_io, stdout = filecheck_io, stderr = filecheck_io); wait = false)
close(filecheck_io.in)
# collect the output of FileCheck
@@ -135,7 +137,7 @@ module FileCheck
const checks = String[]
macro check_str(str)
push!(checks, str)
- nothing
+ return nothing
end
macro filecheck(ex)
@@ -146,10 +148,12 @@ module FileCheck
check_str = join(checks, "\n")
empty!(checks)
- esc(quote
- filecheck($check_str) do _
- $ex
+ return esc(
+ quote
+ filecheck($check_str) do _
+ $ex
+ end
end
- end)
+ )
end
end
diff --git a/test/metal.jl b/test/metal.jl
index 951781f..84d94f2 100644
--- a/test/metal.jl
+++ b/test/metal.jl
@@ -2,151 +2,159 @@
@testset "kernel functions" begin
@testset "byref aggregates" begin
- mod = @eval module $(gensym())
- kernel(x) = return
- end
+ mod = @eval module $(gensym())
+ kernel(x) = return
+ end
- @test @filecheck begin
- check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
- check"TYPED-SAME: ({{(\{ i64 \}|\[1 x i64\])}}*"
- check"OPAQUE-SAME: (ptr"
- Metal.code_llvm(mod.kernel, Tuple{Tuple{Int}})
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
+ check"TYPED-SAME: ({{(\{ i64 \}|\[1 x i64\])}}*"
+ check"OPAQUE-SAME: (ptr"
+ Metal.code_llvm(mod.kernel, Tuple{Tuple{Int}})
+ end
# for kernels, every pointer argument needs to take an address space
- @test @filecheck begin
- check"CHECK-LABEL: define void @_Z6kernel5TupleI5Int64E"
- check"TYPED-SAME: ({{(\{ i64 \}|\[1 x i64\])}} addrspace(1)*"
- check"OPAQUE-SAME: (ptr addrspace(1)"
- Metal.code_llvm(mod.kernel, Tuple{Tuple{Int}}; kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @_Z6kernel5TupleI5Int64E"
+ check"TYPED-SAME: ({{(\{ i64 \}|\[1 x i64\])}} addrspace(1)*"
+ check"OPAQUE-SAME: (ptr addrspace(1)"
+ Metal.code_llvm(mod.kernel, Tuple{Tuple{Int}}; kernel = true)
+ end
end
@testset "byref primitives" begin
- mod = @eval module $(gensym())
- kernel(x) = return
- end
+ mod = @eval module $(gensym())
+ kernel(x) = return
+ end
- @test @filecheck begin
- check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
- check"CHECK-SAME: (i64"
- Metal.code_llvm(mod.kernel, Tuple{Int})
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
+ check"CHECK-SAME: (i64"
+ Metal.code_llvm(mod.kernel, Tuple{Int})
+ end
# for kernels, every pointer argument needs to take an address space
- @test @filecheck begin
- check"CHECK-LABEL: define void @_Z6kernel5Int64"
- check"TYPED-SAME: (i64 addrspace(1)*"
- check"OPAQUE-SAME: (ptr addrspace(1)"
- Metal.code_llvm(mod.kernel, Tuple{Int}; kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @_Z6kernel5Int64"
+ check"TYPED-SAME: (i64 addrspace(1)*"
+ check"OPAQUE-SAME: (ptr addrspace(1)"
+ Metal.code_llvm(mod.kernel, Tuple{Int}; kernel = true)
+ end
end
@testset "module metadata" begin
- mod = @eval module $(gensym())
- kernel() = return
- end
-
- @test @filecheck begin
- check"CHECK: air.version"
- check"CHECK: air.language_version"
- check"CHECK: air.max_device_buffers"
- Metal.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true)
- end
+ mod = @eval module $(gensym())
+ kernel() = return
+ end
+
+ @test @filecheck begin
+ check"CHECK: air.version"
+ check"CHECK: air.language_version"
+ check"CHECK: air.max_device_buffers"
+ Metal.code_llvm(mod.kernel, Tuple{}; dump_module = true, kernel = true)
+ end
end
@testset "argument metadata" begin
- mod = @eval module $(gensym())
- kernel(x) = return
- end
+ mod = @eval module $(gensym())
+ kernel(x) = return
+ end
- @test @filecheck begin
- check"CHECK: air.buffer"
- Metal.code_llvm(mod.kernel, Tuple{Int}; dump_module=true, kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK: air.buffer"
+ Metal.code_llvm(mod.kernel, Tuple{Int}; dump_module = true, kernel = true)
+ end
# XXX: perform more exhaustive testing of argument passing metadata here,
# or just defer to execution testing in Metal.jl?
end
@testset "input arguments" begin
- mod = @eval module $(gensym())
- function kernel(ptr)
- idx = ccall("extern julia.air.thread_position_in_threadgroup.i32",
- llvmcall, UInt32, ()) + 1
- unsafe_store!(ptr, 42, idx)
- return
- end
- end
-
- @test @filecheck begin
- check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
- check"TYPED-SAME: ({{.+}} addrspace(1)* %{{.+}})"
- check"OPAQUE-SAME: (ptr addrspace(1) %{{.+}})"
- check"CHECK: call i32 @julia.air.thread_position_in_threadgroup.i32"
- Metal.code_llvm(mod.kernel, Tuple{Core.LLVMPtr{Int,1}})
- end
-
- @test @filecheck begin
- check"CHECK-LABEL: define void @_Z6kernel7LLVMPtrI5Int64Li1EE"
- check"TYPED-SAME: ({{.+}} addrspace(1)* %{{.+}}, i32 %thread_position_in_threadgroup)"
- check"OPAQUE-SAME: (ptr addrspace(1) %{{.+}}, i32 %thread_position_in_threadgroup)"
- check"CHECK-NOT: call i32 @julia.air.thread_position_in_threadgroup.i32"
- Metal.code_llvm(mod.kernel, Tuple{Core.LLVMPtr{Int,1}}; kernel=true)
- end
+ mod = @eval module $(gensym())
+ function kernel(ptr)
+ idx = ccall(
+ "extern julia.air.thread_position_in_threadgroup.i32",
+ llvmcall, UInt32, ()
+ ) + 1
+ unsafe_store!(ptr, 42, idx)
+ return
+ end
+ end
+
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
+ check"TYPED-SAME: ({{.+}} addrspace(1)* %{{.+}})"
+ check"OPAQUE-SAME: (ptr addrspace(1) %{{.+}})"
+ check"CHECK: call i32 @julia.air.thread_position_in_threadgroup.i32"
+ Metal.code_llvm(mod.kernel, Tuple{Core.LLVMPtr{Int, 1}})
+ end
+
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @_Z6kernel7LLVMPtrI5Int64Li1EE"
+ check"TYPED-SAME: ({{.+}} addrspace(1)* %{{.+}}, i32 %thread_position_in_threadgroup)"
+ check"OPAQUE-SAME: (ptr addrspace(1) %{{.+}}, i32 %thread_position_in_threadgroup)"
+ check"CHECK-NOT: call i32 @julia.air.thread_position_in_threadgroup.i32"
+ Metal.code_llvm(mod.kernel, Tuple{Core.LLVMPtr{Int, 1}}; kernel = true)
+ end
end
@testset "vector intrinsics" begin
- mod = @eval module $(gensym())
- foo(x, y) = ccall("llvm.smax.v2i64", llvmcall, NTuple{2, VecElement{Int64}},
- (NTuple{2, VecElement{Int64}}, NTuple{2, VecElement{Int64}}), x, y)
- end
-
- @test @filecheck begin
- check"CHECK-LABEL: define <2 x i64> @{{(julia|j)_foo_[0-9]+}}"
- check"CHECK: air.max.s.v2i64"
- Metal.code_llvm(mod.foo, (NTuple{2, VecElement{Int64}}, NTuple{2, VecElement{Int64}}))
- end
+ mod = @eval module $(gensym())
+ foo(x, y) = ccall(
+ "llvm.smax.v2i64", llvmcall, NTuple{2, VecElement{Int64}},
+ (NTuple{2, VecElement{Int64}}, NTuple{2, VecElement{Int64}}), x, y
+ )
+ end
+
+ @test @filecheck begin
+ check"CHECK-LABEL: define <2 x i64> @{{(julia|j)_foo_[0-9]+}}"
+ check"CHECK: air.max.s.v2i64"
+ Metal.code_llvm(mod.foo, (NTuple{2, VecElement{Int64}}, NTuple{2, VecElement{Int64}}))
+ end
end
@testset "unsupported type detection" begin
- mod = @eval module $(gensym())
- function kernel(ptr)
- buf = reinterpret(Ptr{Float32}, ptr)
- val = unsafe_load(buf)
- dval = Cdouble(val)
- # ccall("extern metal_os_log", llvmcall, Nothing, (Float64,), dval)
- Base.llvmcall(("""
- declare void @llvm.va_start(i8*)
- declare void @llvm.va_end(i8*)
- declare void @air.os_log(i8*, i64)
-
- define void @metal_os_log(...) {
- %1 = alloca i8*
- %2 = bitcast i8** %1 to i8*
- call void @llvm.va_start(i8* %2)
- %3 = load i8*, i8** %1
- call void @air.os_log(i8* %3, i64 8)
- call void @llvm.va_end(i8* %2)
- ret void
- }
-
- define void @entry(double %val) #0 {
- call void (...) @metal_os_log(double %val)
- ret void
- }
-
- attributes #0 = { alwaysinline }""", "entry"),
- Nothing, Tuple{Float64}, dval)
- return
- end
- end
-
- @test @filecheck begin
- check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
- check"CHECK: @metal_os_log"
- Metal.code_llvm(mod.kernel, Tuple{Core.LLVMPtr{Float32,1}}; validate=true)
- end
+ mod = @eval module $(gensym())
+ function kernel(ptr)
+ buf = reinterpret(Ptr{Float32}, ptr)
+ val = unsafe_load(buf)
+ dval = Cdouble(val)
+ # ccall("extern metal_os_log", llvmcall, Nothing, (Float64,), dval)
+ Base.llvmcall(
+ (
+ """
+ declare void @llvm.va_start(i8*)
+ declare void @llvm.va_end(i8*)
+ declare void @air.os_log(i8*, i64)
+
+ define void @metal_os_log(...) {
+ %1 = alloca i8*
+ %2 = bitcast i8** %1 to i8*
+ call void @llvm.va_start(i8* %2)
+ %3 = load i8*, i8** %1
+ call void @air.os_log(i8* %3, i64 8)
+ call void @llvm.va_end(i8* %2)
+ ret void
+ }
+
+ define void @entry(double %val) #0 {
+ call void (...) @metal_os_log(double %val)
+ ret void
+ }
+
+ attributes #0 = { alwaysinline }""", "entry",
+ ),
+ Nothing, Tuple{Float64}, dval
+ )
+ return
+ end
+ end
+
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
+ check"CHECK: @metal_os_log"
+ Metal.code_llvm(mod.kernel, Tuple{Core.LLVMPtr{Float32, 1}}; validate = true)
+ end
function kernel2(ptr)
val = unsafe_load(ptr)
@@ -155,9 +163,13 @@ end
return
end
- @test_throws_message(InvalidIRError,
- Metal.code_execution(kernel2,
- Tuple{Core.LLVMPtr{Float64,1}})) do msg
+ @test_throws_message(
+ InvalidIRError,
+ Metal.code_execution(
+ kernel2,
+ Tuple{Core.LLVMPtr{Float64, 1}}
+ )
+ ) do msg
occursin("unsupported use of double value", msg)
end
end
@@ -173,12 +185,14 @@ end
end
end
- @test @filecheck begin
- check"CHECK: @{{.+}} ={{.*}} addrspace(2) constant [2 x float]"
- check"CHECK: define void @_Z6kernel7LLVMPtrI7Float32Li1EE5Int64"
- Metal.code_llvm(mod.kernel, Tuple{Core.LLVMPtr{Float32,1}, Int};
- dump_module=true, kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK: @{{.+}} ={{.*}} addrspace(2) constant [2 x float]"
+ check"CHECK: define void @_Z6kernel7LLVMPtrI7Float32Li1EE5Int64"
+ Metal.code_llvm(
+ mod.kernel, Tuple{Core.LLVMPtr{Float32, 1}, Int};
+ dump_module = true, kernel = true
+ )
+ end
end
end
diff --git a/test/native.jl b/test/native.jl
index 1b0757a..45c7449 100644
--- a/test/native.jl
+++ b/test/native.jl
@@ -25,20 +25,20 @@ end
@testset "compilation" begin
@testset "callable structs" begin
mod = @eval module $(gensym())
- struct MyCallable end
- (::MyCallable)(a, b) = a+b
+ struct MyCallable end
+ (::MyCallable)(a, b) = a + b
end
- (ci, rt) = Native.code_typed(mod.MyCallable(), (Int, Int), kernel=false)[1]
+ (ci, rt) = Native.code_typed(mod.MyCallable(), (Int, Int), kernel = false)[1]
@test ci.slottypes[1] == Core.Compiler.Const(mod.MyCallable())
end
@testset "compilation database" begin
mod = @eval module $(gensym())
- @noinline inner(x) = x+1
- function outer(x)
- return inner(x)
- end
+ @noinline inner(x) = x + 1
+ function outer(x)
+ return inner(x)
+ end
end
job, _ = Native.create_job(mod.outer, (Int,))
@@ -58,11 +58,11 @@ end
@testset "advanced database" begin
mod = @eval module $(gensym())
- @noinline inner(x) = x+1
- foo(x) = sum(inner, fill(x, 10, 10))
+ @noinline inner(x) = x + 1
+ foo(x) = sum(inner, fill(x, 10, 10))
end
- job, _ = Native.create_job(mod.foo, (Float64,); validate=false)
+ job, _ = Native.create_job(mod.foo, (Float64,); validate = false)
JuliaContext() do ctx
# shouldn't segfault
ir, meta = GPUCompiler.compile(:llvm, job)
@@ -74,7 +74,7 @@ end
inner_methods = filter(keys(meta.compiled)) do mi
mi.def in methods(mod.inner) &&
- mi.specTypes == Tuple{typeof(mod.inner), Float64}
+ mi.specTypes == Tuple{typeof(mod.inner), Float64}
end
@test length(inner_methods) == 1
end
@@ -82,8 +82,8 @@ end
@testset "cached compilation" begin
mod = @eval module $(gensym())
- @noinline child(i) = i
- kernel(i) = child(i)+1
+ @noinline child(i) = i
+ kernel(i) = child(i) + 1
end
# smoke test
@@ -95,7 +95,7 @@ end
end
# basic redefinition
- @eval mod kernel(i) = child(i)+2
+ @eval mod kernel(i) = child(i) + 2
job, _ = Native.create_job(mod.kernel, (Int64,))
@test @filecheck begin
check"CHECK-LABEL: define i64 @{{(julia|j)_kernel_[0-9]+}}"
@@ -135,7 +135,7 @@ end
@test invocations[] == 1
# redefinition
- @eval mod kernel(i) = child(i)+3
+ @eval mod kernel(i) = child(i) + 3
source = methodinstance(ft, tt, Base.get_world_counter())
@test @filecheck begin
check"CHECK-LABEL: define i64 @{{(julia|j)_kernel_[0-9]+}}"
@@ -158,7 +158,7 @@ end
@test invocations[] == 2
# redefining child functions
- @eval mod @noinline child(i) = i+1
+ @eval mod @noinline child(i) = i + 1
Base.invokelatest(GPUCompiler.cached_compilation, cache, source, job.config, compiler, linker)
@test invocations[] == 3
@@ -184,7 +184,7 @@ end
end
t = @async Base.invokelatest(background, job)
wait(c1) # make sure the task has started
- @eval mod kernel(i) = child(i)+4
+ @eval mod kernel(i) = child(i) + 4
source = methodinstance(ft, tt, Base.get_world_counter())
ir = Base.invokelatest(GPUCompiler.cached_compilation, cache, source, job.config, compiler, linker)
@test contains(ir, r"add i64 %\d+, 4")
@@ -214,59 +214,59 @@ end
@testset "IR" begin
@testset "basic reflection" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
valid_kernel() = return
invalid_kernel() = 1
- end
+ end
- @test @filecheck begin
- # module should contain our function + a generic call wrapper
- check"CHECK: @{{(julia|j)_valid_kernel_[0-9]+}}"
- Native.code_llvm(mod.valid_kernel, Tuple{}; optimize=false, dump_module=true)
- end
+ @test @filecheck begin
+ # module should contain our function + a generic call wrapper
+ check"CHECK: @{{(julia|j)_valid_kernel_[0-9]+}}"
+ Native.code_llvm(mod.valid_kernel, Tuple{}; optimize = false, dump_module = true)
+ end
- @test Native.code_llvm(devnull, mod.invalid_kernel, Tuple{}) == nothing
- @test_throws KernelError Native.code_llvm(devnull, mod.invalid_kernel, Tuple{}; kernel=true) == nothing
+ @test Native.code_llvm(devnull, mod.invalid_kernel, Tuple{}) == nothing
+ @test_throws KernelError Native.code_llvm(devnull, mod.invalid_kernel, Tuple{}; kernel = true) == nothing
end
@testset "unbound typevars" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
invalid_kernel() where {unbound} = return
- end
- @test_throws KernelError Native.code_llvm(devnull, mod.invalid_kernel, Tuple{})
+ end
+ @test_throws KernelError Native.code_llvm(devnull, mod.invalid_kernel, Tuple{})
end
@testset "child functions" begin
# we often test using `@noinline sink` child functions, so test whether these survive
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
import ..sink
@noinline child(i) = sink(i)
parent(i) = child(i)
- end
+ end
- @test @filecheck begin
- check"CHECK-LABEL: define i64 @{{(julia|j)_parent_[0-9]+}}"
- check"CHECK: call{{.*}} i64 @{{(julia|j)_child_[0-9]+}}"
- Native.code_llvm(mod.parent, Tuple{Int})
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define i64 @{{(julia|j)_parent_[0-9]+}}"
+ check"CHECK: call{{.*}} i64 @{{(julia|j)_child_[0-9]+}}"
+ Native.code_llvm(mod.parent, Tuple{Int})
+ end
end
@testset "sysimg" begin
# bug: use a system image function
- mod = @eval module $(gensym())
- function foobar(a,i)
- Base.pointerset(a, 0, mod1(i,10), 8)
+ mod = @eval module $(gensym())
+ function foobar(a, i)
+ Base.pointerset(a, 0, mod1(i, 10), 8)
end
end
- @test @filecheck begin
- check"CHECK-NOT: jlsys_"
- Native.code_llvm(mod.foobar, Tuple{Ptr{Int},Int})
- end
+ @test @filecheck begin
+ check"CHECK-NOT: jlsys_"
+ Native.code_llvm(mod.foobar, Tuple{Ptr{Int}, Int})
+ end
end
@testset "tracked pointers" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
function kernel(a)
a[1] = 1
return
@@ -274,11 +274,11 @@ end
end
# this used to throw an LLVM assertion (#223)
- Native.code_llvm(devnull, mod.kernel, Tuple{Vector{Int}}; kernel=true)
+ Native.code_llvm(devnull, mod.kernel, Tuple{Vector{Int}}; kernel = true)
@test "We did not crash!" != ""
end
-@testset "CUDA.jl#278" begin
+ @testset "CUDA.jl#278" begin
# codegen idempotency
# NOTE: this isn't fixed, but surfaces here due to bad inference of checked_sub
# NOTE: with the fix to print_to_string this doesn't error anymore,
@@ -308,42 +308,42 @@ end
end
@testset "slow abi" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
x = 2
- f = () -> x+1
- end
- @test @filecheck begin
- check"CHECK: define {{.+}} @julia"
- check"TYPED: define nonnull {}* @jfptr"
- check"OPAQUE: define nonnull ptr @jfptr"
- check"CHECK: call {{.+}} @julia"
- Native.code_llvm(mod.f, Tuple{}; entry_abi=:func, dump_module=true)
- end
+ f = () -> x + 1
+ end
+ @test @filecheck begin
+ check"CHECK: define {{.+}} @julia"
+ check"TYPED: define nonnull {}* @jfptr"
+ check"OPAQUE: define nonnull ptr @jfptr"
+ check"CHECK: call {{.+}} @julia"
+ Native.code_llvm(mod.f, Tuple{}; entry_abi = :func, dump_module = true)
+ end
end
@testset "function entry safepoint emission" begin
- @test @filecheck begin
- check"CHECK-LABEL: define void @{{(julia|j)_identity_[0-9]+}}"
- check"CHECK-NOT: %safepoint"
- Native.code_llvm(identity, Tuple{Nothing}; entry_safepoint=false, optimize=false, dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @{{(julia|j)_identity_[0-9]+}}"
+ check"CHECK-NOT: %safepoint"
+ Native.code_llvm(identity, Tuple{Nothing}; entry_safepoint = false, optimize = false, dump_module = true)
+ end
# XXX: broken by JuliaLang/julia#57010,
# see https://github.com/JuliaLang/julia/pull/57010/files#r2079576894
- if VERSION < v"1.13.0-DEV.533"
- @test @filecheck begin
- check"CHECK-LABEL: define void @{{(julia|j)_identity_[0-9]+}}"
- check"CHECK: %safepoint"
- Native.code_llvm(identity, Tuple{Nothing}; entry_safepoint=true, optimize=false, dump_module=true)
+ if VERSION < v"1.13.0-DEV.533"
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @{{(julia|j)_identity_[0-9]+}}"
+ check"CHECK: %safepoint"
+ Native.code_llvm(identity, Tuple{Nothing}; entry_safepoint = true, optimize = false, dump_module = true)
+ end
end
- end
end
@testset "always_inline" begin
# XXX: broken by JuliaLang/julia#51599, see JuliaGPU/GPUCompiler.jl#527
mod = @eval module $(gensym())
import ..sink
- expensive(x) = $(foldl((e, _) -> :($sink($e) + $sink(x)), 1:100; init=:x))
+ expensive(x) = $(foldl((e, _) -> :($sink($e) + $sink(x)), 1:100; init = :x))
function g(x)
expensive(x)
return
@@ -354,48 +354,52 @@ end
end
end
- @test @filecheck begin
- check"CHECK: @{{(julia|j)_expensive_[0-9]+}}"
- Native.code_llvm(mod.g, Tuple{Int64}; dump_module=true, kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK: @{{(julia|j)_expensive_[0-9]+}}"
+ Native.code_llvm(mod.g, Tuple{Int64}; dump_module = true, kernel = true)
+ end
- @test @filecheck begin
- check"CHECK-NOT: @{{(julia|j)_expensive_[0-9]+}}"
- Native.code_llvm(mod.g, Tuple{Int64}; dump_module=true, kernel=true, always_inline=true)
- end
+ @test @filecheck begin
+ check"CHECK-NOT: @{{(julia|j)_expensive_[0-9]+}}"
+ Native.code_llvm(mod.g, Tuple{Int64}; dump_module = true, kernel = true, always_inline = true)
+ end
- @test @filecheck begin
- check"CHECK: @{{(julia|j)_expensive_[0-9]+}}"
- Native.code_llvm(mod.h, Tuple{Int64}; dump_module=true, kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK: @{{(julia|j)_expensive_[0-9]+}}"
+ Native.code_llvm(mod.h, Tuple{Int64}; dump_module = true, kernel = true)
+ end
- @test @filecheck begin
- check"CHECK-NOT: @{{(julia|j)_expensive_[0-9]+}}"
- Native.code_llvm(mod.h, Tuple{Int64}; dump_module=true, kernel=true, always_inline=true)
- end
+ @test @filecheck begin
+ check"CHECK-NOT: @{{(julia|j)_expensive_[0-9]+}}"
+ Native.code_llvm(mod.h, Tuple{Int64}; dump_module = true, kernel = true, always_inline = true)
+ end
end
@testset "function attributes" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
@inline function convergent_barrier()
- Base.llvmcall(("""
- declare void @barrier() #1
+ Base.llvmcall(
+ (
+ """
+ declare void @barrier() #1
- define void @entry() #0 {
- call void @barrier()
- ret void
- }
+ define void @entry() #0 {
+ call void @barrier()
+ ret void
+ }
- attributes #0 = { alwaysinline }
- attributes #1 = { convergent }""", "entry"),
- Nothing, Tuple{})
+ attributes #0 = { alwaysinline }
+ attributes #1 = { convergent }""", "entry",
+ ),
+ Nothing, Tuple{}
+ )
end
end
- @test @filecheck begin
- check"CHECK: attributes #{{.}} = { convergent }"
- Native.code_llvm(mod.convergent_barrier, Tuple{}; dump_module=true, raw=true)
- end
+ @test @filecheck begin
+ check"CHECK: attributes #{{.}} = { convergent }"
+ Native.code_llvm(mod.convergent_barrier, Tuple{}; dump_module = true, raw = true)
+ end
end
end
@@ -405,32 +409,32 @@ end
@testset "assembly" begin
@testset "basic reflection" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
valid_kernel() = return
invalid_kernel() = 1
- end
+ end
- @test Native.code_native(devnull, mod.valid_kernel, Tuple{}) == nothing
- @test Native.code_native(devnull, mod.invalid_kernel, Tuple{}) == nothing
- @test_throws KernelError Native.code_native(devnull, mod.invalid_kernel, Tuple{}; kernel=true)
+ @test Native.code_native(devnull, mod.valid_kernel, Tuple{}) == nothing
+ @test Native.code_native(devnull, mod.invalid_kernel, Tuple{}) == nothing
+ @test_throws KernelError Native.code_native(devnull, mod.invalid_kernel, Tuple{}; kernel = true)
end
@testset "idempotency" begin
# bug: generate code twice for the same kernel (jl_to_ptx wasn't idempotent)
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
kernel() = return
- end
- Native.code_native(devnull, mod.kernel, Tuple{})
- Native.code_native(devnull, mod.kernel, Tuple{})
+ end
+ Native.code_native(devnull, mod.kernel, Tuple{})
+ Native.code_native(devnull, mod.kernel, Tuple{})
@test "We did not crash!" != ""
end
@testset "compile for host after gpu" begin
# issue #11: re-using host functions after GPU compilation
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
import ..sink
- @noinline child(i) = sink(i+1)
+ @noinline child(i) = sink(i + 1)
function fromhost()
child(10)
@@ -442,8 +446,8 @@ end
end
end
- Native.code_native(devnull, mod.fromptx, Tuple{})
- @test mod.fromhost() == 11
+ Native.code_native(devnull, mod.fromptx, Tuple{})
+ @test mod.fromhost() == 11
end
end
@@ -454,27 +458,29 @@ end
@testset "non-isbits arguments" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
import ..sink
- foobar(i) = (sink(unsafe_trunc(Int,i)); return)
- end
+ foobar(i) = (sink(unsafe_trunc(Int, i)); return)
+ end
@test_throws_message(KernelError,
- Native.code_execution(mod.foobar, Tuple{BigInt})) do msg
+ Native.code_execution(mod.foobar, Tuple{BigInt})
+ ) do msg
occursin("passing non-bitstype argument", msg) &&
occursin("BigInt", msg)
end
# test that we get information about fields and reason why something is not isbits
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
struct CleverType{T}
x::T
end
Base.unsafe_trunc(::Type{Int}, x::CleverType) = unsafe_trunc(Int, x.x)
- foobar(i) = (sink(unsafe_trunc(Int,i)); return)
- end
+ foobar(i) = (sink(unsafe_trunc(Int, i)); return)
+ end
@test_throws_message(KernelError,
- Native.code_execution(mod.foobar, Tuple{mod.CleverType{BigInt}})) do msg
+ Native.code_execution(mod.foobar, Tuple{mod.CleverType{BigInt}})
+ ) do msg
occursin("passing non-bitstype argument", msg) &&
occursin("CleverType", msg) &&
occursin("BigInt", msg)
@@ -482,7 +488,7 @@ end
end
@testset "invalid LLVM IR" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
foobar(i) = println(i)
end
@@ -498,7 +504,7 @@ end
end
@testset "invalid LLVM IR (ccall)" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
function foobar(p)
unsafe_store!(p, ccall(:time, Cint, ()))
return
@@ -521,7 +527,7 @@ end
end
@testset "delayed bindings" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
function kernel()
undefined
return
@@ -553,7 +559,7 @@ end
end
@testset "dynamic call (apply)" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
func() = println(1)
end
@@ -575,7 +581,7 @@ end
mod = @eval module $(gensym())
kernel() = child()
- @inline child() = 0
+ @inline child() = 0
end
@test @filecheck begin
@@ -590,7 +596,7 @@ end
Base.Experimental.@MethodTable(method_table)
kernel() = child()
- @inline child() = 0
+ @inline child() = 0
Base.Experimental.@overlay method_table child() = 1
end
@@ -624,7 +630,7 @@ end
check"CHECK-LABEL: @julia_kernel"
check"CHECK-NOT: apply_generic"
check"CHECK: llvm.floor"
- Native.code_llvm(mod.kernel, Tuple{Int, Int}; debuginfo=:none, mod.method_table)
+ Native.code_llvm(mod.kernel, Tuple{Int, Int}; debuginfo = :none, mod.method_table)
end
end
@@ -650,6 +656,6 @@ end
check"CHECK-NOT: inttoptr"
check"CHECK-NOT: apply_type"
check"CHECK: ret void"
- Native.code_llvm(mod.parent, Tuple{}; debuginfo=:none, mod.method_table)
+ Native.code_llvm(mod.parent, Tuple{}; debuginfo = :none, mod.method_table)
end
end
diff --git a/test/ptx.jl b/test/ptx.jl
index 18dd0e4..3d0884e 100644
--- a/test/ptx.jl
+++ b/test/ptx.jl
@@ -1,18 +1,18 @@
@testset "IR" begin
@testset "exceptions" begin
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
foobar() = throw(DivideError())
- end
- @test @filecheck begin
- check"CHECK-LABEL: define void @{{(julia|j)_foobar_[0-9]+}}"
- # plain exceptions should get lowered to a call to the GPU run-time
- # not a jl_throw referencing a jl_value_t representing the exception
- check"CHECK-NOT: jl_throw"
- check"CHECK: gpu_report_exception"
-
- PTX.code_llvm(mod.foobar, Tuple{}; dump_module=true)
- end
+ end
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @{{(julia|j)_foobar_[0-9]+}}"
+ # plain exceptions should get lowered to a call to the GPU run-time
+ # not a jl_throw referencing a jl_value_t representing the exception
+ check"CHECK-NOT: jl_throw"
+ check"CHECK: gpu_report_exception"
+
+ PTX.code_llvm(mod.foobar, Tuple{}; dump_module = true)
+ end
end
@testset "kernel functions" begin
@@ -25,97 +25,97 @@ end
end
end
- @test @filecheck begin
- check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
- check"TYPED-SAME: ({{({ i64 }|\[1 x i64\])}}*"
- check"OPAQUE-SAME: (ptr"
- PTX.code_llvm(mod.kernel, Tuple{mod.Aggregate})
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}"
+ check"TYPED-SAME: ({{({ i64 }|\[1 x i64\])}}*"
+ check"OPAQUE-SAME: (ptr"
+ PTX.code_llvm(mod.kernel, Tuple{mod.Aggregate})
+ end
- @test @filecheck begin
- check"CHECK-LABEL: define ptx_kernel void @_Z6kernel9Aggregate"
- check"TYPED-NOT: *"
- check"OPAQUE-NOT: ptr"
- PTX.code_llvm(mod.kernel, Tuple{mod.Aggregate}; kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define ptx_kernel void @_Z6kernel9Aggregate"
+ check"TYPED-NOT: *"
+ check"OPAQUE-NOT: ptr"
+ PTX.code_llvm(mod.kernel, Tuple{mod.Aggregate}; kernel = true)
+ end
end
@testset "property_annotations" begin
- mod = @eval module $(gensym())
- kernel() = return
- end
+ mod = @eval module $(gensym())
+ kernel() = return
+ end
- @test @filecheck begin
- check"CHECK-NOT: nvvm.annotations"
- PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-NOT: nvvm.annotations"
+ PTX.code_llvm(mod.kernel, Tuple{}; dump_module = true)
+ end
- @test @filecheck begin
- check"CHECK-NOT: maxntid"
- check"CHECK-NOT: reqntid"
- check"CHECK-NOT: minctasm"
- check"CHECK-NOT: maxnreg"
- check"CHECK: nvvm.annotations"
- PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK-NOT: maxntid"
+ check"CHECK-NOT: reqntid"
+ check"CHECK-NOT: minctasm"
+ check"CHECK-NOT: maxnreg"
+ check"CHECK: nvvm.annotations"
+ PTX.code_llvm(mod.kernel, Tuple{}; dump_module = true, kernel = true)
+ end
- @test @filecheck begin
- check"CHECK: maxntidx\", i32 42"
- check"CHECK: maxntidy\", i32 1"
- check"CHECK: maxntidz\", i32 1"
- PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true, maxthreads=42)
- end
+ @test @filecheck begin
+ check"CHECK: maxntidx\", i32 42"
+ check"CHECK: maxntidy\", i32 1"
+ check"CHECK: maxntidz\", i32 1"
+ PTX.code_llvm(mod.kernel, Tuple{}; dump_module = true, kernel = true, maxthreads = 42)
+ end
- @test @filecheck begin
- check"CHECK: reqntidx\", i32 42"
- check"CHECK: reqntidy\", i32 1"
- check"CHECK: reqntidz\", i32 1"
- PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true, minthreads=42)
- end
+ @test @filecheck begin
+ check"CHECK: reqntidx\", i32 42"
+ check"CHECK: reqntidy\", i32 1"
+ check"CHECK: reqntidz\", i32 1"
+ PTX.code_llvm(mod.kernel, Tuple{}; dump_module = true, kernel = true, minthreads = 42)
+ end
- @test @filecheck begin
- check"CHECK: minctasm\", i32 42"
- PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true, blocks_per_sm=42)
- end
+ @test @filecheck begin
+ check"CHECK: minctasm\", i32 42"
+ PTX.code_llvm(mod.kernel, Tuple{}; dump_module = true, kernel = true, blocks_per_sm = 42)
+ end
- @test @filecheck begin
- check"CHECK: maxnreg\", i32 42"
- PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true, maxregs=42)
- end
+ @test @filecheck begin
+ check"CHECK: maxnreg\", i32 42"
+ PTX.code_llvm(mod.kernel, Tuple{}; dump_module = true, kernel = true, maxregs = 42)
+ end
end
LLVM.version() >= v"8" && @testset "calling convention" begin
- mod = @eval module $(gensym())
- kernel() = return
- end
+ mod = @eval module $(gensym())
+ kernel() = return
+ end
- @test @filecheck begin
- check"CHECK-NOT: ptx_kernel"
- PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-NOT: ptx_kernel"
+ PTX.code_llvm(mod.kernel, Tuple{}; dump_module = true)
+ end
- @test @filecheck begin
- check"CHECK: ptx_kernel"
- PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK: ptx_kernel"
+ PTX.code_llvm(mod.kernel, Tuple{}; dump_module = true, kernel = true)
+ end
end
@testset "kernel state" begin
# state should be passed by value to kernel functions
- mod = @eval module $(gensym())
+ mod = @eval module $(gensym())
kernel() = return
end
- @test @filecheck begin
- check"CHECK: @{{(julia|j)_kernel[0-9_]*}}()"
- PTX.code_llvm(mod.kernel, Tuple{})
- end
+ @test @filecheck begin
+ check"CHECK: @{{(julia|j)_kernel[0-9_]*}}()"
+ PTX.code_llvm(mod.kernel, Tuple{})
+ end
- @test @filecheck begin
- check"CHECK: @_Z6kernel([1 x i64] %state)"
- PTX.code_llvm(mod.kernel, Tuple{}; kernel=true)
- end
+ @test @filecheck begin
+ check"CHECK: @_Z6kernel([1 x i64] %state)"
+ PTX.code_llvm(mod.kernel, Tuple{}; kernel = true)
+ end
# state should only passed to device functions that use it
@@ -134,21 +134,21 @@ end
end
# kernel should take state argument before all else
- @test @filecheck begin
- check"CHECK-LABEL: define ptx_kernel void @_Z6kernelP5Int64([1 x i64] %state"
- check"CHECK-NOT: julia.gpu.state_getter"
- PTX.code_llvm(mod.kernel, Tuple{Ptr{Int64}}; kernel=true, dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define ptx_kernel void @_Z6kernelP5Int64([1 x i64] %state"
+ check"CHECK-NOT: julia.gpu.state_getter"
+ PTX.code_llvm(mod.kernel, Tuple{Ptr{Int64}}; kernel = true, dump_module = true)
+ end
# child1 doesn't use the state
- @test @filecheck begin
- check"CHECK-LABEL: define{{.*}} i64 @{{(julia|j)_child1_[0-9]+}}"
- PTX.code_llvm(mod.kernel, Tuple{Ptr{Int64}}; kernel=true, dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define{{.*}} i64 @{{(julia|j)_child1_[0-9]+}}"
+ PTX.code_llvm(mod.kernel, Tuple{Ptr{Int64}}; kernel = true, dump_module = true)
+ end
# child2 does
- @test @filecheck begin
- check"CHECK-LABEL: define{{.*}} i64 @{{(julia|j)_child2_[0-9]+}}"
- PTX.code_llvm(mod.kernel, Tuple{Ptr{Int64}}; kernel=true, dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: define{{.*}} i64 @{{(julia|j)_child2_[0-9]+}}"
+ PTX.code_llvm(mod.kernel, Tuple{Ptr{Int64}}; kernel = true, dump_module = true)
+ end
end
end
@@ -163,7 +163,7 @@ if :NVPTX in LLVM.backends()
# (despite not having side-effects)
mod = @eval module $(gensym())
- import ..sink
+ import ..sink
@noinline child(i) = sink(i)
function parent(i)
child(i)
@@ -171,17 +171,17 @@ if :NVPTX in LLVM.backends()
end
end
- @test @filecheck begin
- check"CHECK-LABEL: .visible .func {{(julia|j)_parent[0-9_]*}}"
- check"CHECK: call.uni"
- check"CHECK-NEXT: {{(julia|j)_child_}}"
- PTX.code_native(mod.parent, Tuple{Int64})
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: .visible .func {{(julia|j)_parent[0-9_]*}}"
+ check"CHECK: call.uni"
+ check"CHECK-NEXT: {{(julia|j)_child_}}"
+ PTX.code_native(mod.parent, Tuple{Int64})
+ end
end
@testset "kernel functions" begin
mod = @eval module $(gensym())
- import ..sink
+ import ..sink
@noinline nonentry(i) = sink(i)
function entry(i)
nonentry(i)
@@ -189,39 +189,39 @@ end
end
end
- @test @filecheck begin
- check"CHECK-NOT: .visible .func {{(julia|j)_nonentry}}"
- check"CHECK-LABEL: .visible .entry _Z5entry5Int64"
- check"CHECK: {{(julia|j)_nonentry}}"
- PTX.code_native(mod.entry, Tuple{Int64}; kernel=true, dump_module=true)
- end
+ @test @filecheck begin
+ check"CHECK-NOT: .visible .func {{(julia|j)_nonentry}}"
+ check"CHECK-LABEL: .visible .entry _Z5entry5Int64"
+ check"CHECK: {{(julia|j)_nonentry}}"
+ PTX.code_native(mod.entry, Tuple{Int64}; kernel = true, dump_module = true)
+ end
@testset "property_annotations" begin
- @test @filecheck begin
- check"CHECK-NOT: maxntid"
- PTX.code_native(mod.entry, Tuple{Int64}; kernel=true)
- end
-
- @test @filecheck begin
- check"CHECK: .maxntid 42, 1, 1"
- PTX.code_native(mod.entry, Tuple{Int64}; kernel=true, maxthreads=42)
- end
-
- @test @filecheck begin
- check"CHECK: .reqntid 42, 1, 1"
- PTX.code_native(mod.entry, Tuple{Int64}; kernel=true, minthreads=42)
- end
-
- @test @filecheck begin
- check"CHECK: .minnctapersm 42"
- PTX.code_native(mod.entry, Tuple{Int64}; kernel=true, blocks_per_sm=42)
- end
+ @test @filecheck begin
+ check"CHECK-NOT: maxntid"
+ PTX.code_native(mod.entry, Tuple{Int64}; kernel = true)
+ end
+
+ @test @filecheck begin
+ check"CHECK: .maxntid 42, 1, 1"
+ PTX.code_native(mod.entry, Tuple{Int64}; kernel = true, maxthreads = 42)
+ end
+
+ @test @filecheck begin
+ check"CHECK: .reqntid 42, 1, 1"
+ PTX.code_native(mod.entry, Tuple{Int64}; kernel = true, minthreads = 42)
+ end
+
+ @test @filecheck begin
+ check"CHECK: .minnctapersm 42"
+ PTX.code_native(mod.entry, Tuple{Int64}; kernel = true, blocks_per_sm = 42)
+ end
if LLVM.version() >= v"4.0"
- @test @filecheck begin
- check"CHECK: .maxnreg 42"
- PTX.code_native(mod.entry, Tuple{Int64}; kernel=true, maxregs=42)
- end
+ @test @filecheck begin
+ check"CHECK: .maxnreg 42"
+ PTX.code_native(mod.entry, Tuple{Int64}; kernel = true, maxregs = 42)
+ end
end
end
end
@@ -231,7 +231,7 @@ end
# the child only being present once
mod = @eval module $(gensym())
- import ..sink
+ import ..sink
@noinline child(i) = sink(i)
function parent1(i)
child(i)
@@ -243,15 +243,15 @@ end
end
end
- @test @filecheck begin
- check"CHECK: .func {{(julia|j)_child}}"
- PTX.code_native(mod.parent1, Tuple{Int})
- end
+ @test @filecheck begin
+ check"CHECK: .func {{(julia|j)_child}}"
+ PTX.code_native(mod.parent1, Tuple{Int})
+ end
- @test @filecheck begin
- check"CHECK: .func {{(julia|j)_child}}"
- PTX.code_native(mod.parent2, Tuple{Int})
- end
+ @test @filecheck begin
+ check"CHECK: .func {{(julia|j)_child}}"
+ PTX.code_native(mod.parent2, Tuple{Int})
+ end
end
@testset "child function reuse bis" begin
@@ -259,7 +259,7 @@ end
# in the case of two child functions
mod = @eval module $(gensym())
- import ..sink
+ import ..sink
@noinline child1(i) = sink(i)
@noinline child2(i) = sink(i+1)
function parent1(i)
@@ -272,17 +272,17 @@ end
end
end
- @test @filecheck begin
- check"CHECK-DAG: .func {{(julia|j)_child1}}"
- check"CHECK-DAG: .func {{(julia|j)_child2}}"
- PTX.code_native(mod.parent1, Tuple{Int})
- end
+ @test @filecheck begin
+ check"CHECK-DAG: .func {{(julia|j)_child1}}"
+ check"CHECK-DAG: .func {{(julia|j)_child2}}"
+ PTX.code_native(mod.parent1, Tuple{Int})
+ end
- @test @filecheck begin
- check"CHECK-DAG: .func {{(julia|j)_child1}}"
- check"CHECK-DAG: .func {{(julia|j)_child2}}"
- PTX.code_native(mod.parent2, Tuple{Int})
- end
+ @test @filecheck begin
+ check"CHECK-DAG: .func {{(julia|j)_child1}}"
+ check"CHECK-DAG: .func {{(julia|j)_child2}}"
+ PTX.code_native(mod.parent2, Tuple{Int})
+ end
end
@testset "indirect sysimg function use" begin
@@ -290,42 +290,42 @@ end
# (host fldmod1->mod1 throws, so the PTX code shouldn't contain a throw)
# NOTE: Int32 to test for #49
- mod = @eval module $(gensym())
- function kernel(out)
- wid, lane = fldmod1(unsafe_load(out), Int32(32))
- unsafe_store!(out, wid)
- return
- end
+ mod = @eval module $(gensym())
+ function kernel(out)
+ wid, lane = fldmod1(unsafe_load(out), Int32(32))
+ unsafe_store!(out, wid)
+ return
+ end
end
- @test @filecheck begin
- check"CHECK-LABEL: .visible .func {{(julia|j)_kernel[0-9_]*}}"
- check"CHECK-NOT: jl_throw"
- check"CHECK-NOT: jl_invoke"
- PTX.code_native(mod.kernel, Tuple{Ptr{Int32}})
- end
+ @test @filecheck begin
+ check"CHECK-LABEL: .visible .func {{(julia|j)_kernel[0-9_]*}}"
+ check"CHECK-NOT: jl_throw"
+ check"CHECK-NOT: jl_invoke"
+ PTX.code_native(mod.kernel, Tuple{Ptr{Int32}})
+ end
end
@testset "LLVM intrinsics" begin
# issue #13 (a): cannot select trunc
- mod = @eval module $(gensym())
- function kernel(x)
- unsafe_trunc(Int, x)
- return
- end
+ mod = @eval module $(gensym())
+ function kernel(x)
+ unsafe_trunc(Int, x)
+ return
+ end
end
- PTX.code_native(devnull, mod.kernel, Tuple{Float64})
+ PTX.code_native(devnull, mod.kernel, Tuple{Float64})
@test "We did not crash!" != ""
end
@testset "exception arguments" begin
- mod = @eval module $(gensym()...*[Comment body truncated]* |
That seems fragile; what if we want to log, or LLVM generates a warning? In principle, all that should go to stderr, but you know how things go.
That seems redundant? What about: filecheck() do check
# we can capture mod, convert it to asm
check(asm)
end If |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #703 +/- ##
==========================================
- Coverage 73.77% 71.63% -2.14%
==========================================
Files 24 24
Lines 3519 3519
==========================================
- Hits 2596 2521 -75
- Misses 923 998 +75 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
The big goal was to allow for multiline RUN commands written in Julia, with support for the A normal LLVM test file looks like:
The The crux is that One is the input file with the So the input argument to the
So the biggest issue is everything that would trigger a crash/abort. I did add a test to make sure that we can check for errors (as long as they are raised through Julia). Everything else would require process isolation and loading the helpers in that process, which is the main thing I wanted to avoid. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use testset to not overwrite success
Trying this out, it looks like a match failure doesn't trigger test failures:
|
Good point. I currently always have |
Took it a bit further / too far... But it looks nice, I think. |
f318e83
to
11530d9
Compare
LGTM! |
Great. Will try to do some more conversions first, should be a great task for an LLM agent. |
So one tricky thing is that |
Co-authored-by: Valentin Churavy <[email protected]>
So this escalated. Anyhow, there's still a handful of things I want to do; I'll finish tonight or tomorrow. |
Instead of using
lit
to run a test harness @maleadt comment in #701 (comment)made me realize what we actually want is easy FileCheck integration.
filecheck(f, input)
wheref
is a function that input and runs some transformation and outputs it to stdout.As an example we could add a function that runs the optimzation pipeline