Skip to content

Commit

Permalink
Simplify function name matching in tests using private modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
maleadt committed Sep 17, 2024
1 parent a96fc50 commit 6540a44
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 108 deletions.
53 changes: 30 additions & 23 deletions test/gcn_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,44 +74,51 @@ end
# bug: depending on a child function from multiple parents resulted in
# the child only being present once

@noinline child(i) = sink_gcn(i)
function parent1(i)
child(i)
return
mod = @eval module $(gensym())
export child, parent1, parent2

@noinline child(i) = sink_gcn(i)
function parent1(i)
child(i)
return
end
function parent2(i)
child(i+1)
return
end
end

asm = sprint(io->GCN.code_native(io, parent1, Tuple{Int}; dump_module=true))
asm = sprint(io->GCN.code_native(io, mod.parent1, Tuple{Int}; dump_module=true))
@test occursin(r"\.type.*julia_[[:alnum:]_.]*child_\d*,@function", asm)

function parent2(i)
child(i+1)
return
end

asm = sprint(io->GCN.code_native(io, parent2, Tuple{Int}; dump_module=true))
asm = sprint(io->GCN.code_native(io, mod.parent2, Tuple{Int}; dump_module=true))
@test occursin(r"\.type.*julia_[[:alnum:]_.]*child_\d*,@function", asm)
end

@testset "child function reuse bis" begin
# bug: similar, but slightly different issue as above
# in the case of two child functions
@noinline child1(i) = sink_gcn(i)
@noinline child2(i) = sink_gcn(i+1)
function parent1(i)
child1(i) + child2(i)
return

mod = @eval module $(gensym())
export parent1, parent2, child1, child2

@noinline child1(i) = sink_gcn(i)
@noinline child2(i) = sink_gcn(i+1)
function parent1(i)
child1(i) + child2(i)
return
end
function parent2(i)
child1(i+1) + child2(i+1)
return
end
end

asm = sprint(io->GCN.code_native(io, parent1, Tuple{Int}; dump_module=true))
asm = sprint(io->GCN.code_native(io, mod.parent1, Tuple{Int}; dump_module=true))
@test occursin(r"\.type.*julia_[[:alnum:]_.]*child1_\d*,@function", asm)
@test occursin(r"\.type.*julia_[[:alnum:]_.]*child2_\d*,@function", asm)

function parent2(i)
child1(i+1) + child2(i+1)
return
end

asm = sprint(io->GCN.code_native(io, parent2, Tuple{Int}; dump_module=true))
asm = sprint(io->GCN.code_native(io, mod.parent2, Tuple{Int}; dump_module=true))
@test occursin(r"\.type.*julia_[[:alnum:]_.]*child1_\d*,@function", asm)
@test occursin(r"\.type.*julia_[[:alnum:]_.]*child2_\d*,@function", asm)
end
Expand Down
46 changes: 32 additions & 14 deletions test/native_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -388,46 +388,61 @@ Base.unsafe_trunc(::Type{Int}, x::CleverType) = unsafe_trunc(Int, x.x)
end

@testset "invalid LLVM IR" begin
foobar(i) = println(i)
mod = @eval module $(gensym())
export foobar
foobar(i) = println(i)
end

@test_throws_message(InvalidIRError,
Native.code_execution(foobar, Tuple{Int})) do msg
Native.code_execution(mod.foobar, Tuple{Int})) do msg
occursin("invalid LLVM IR", msg) &&
(occursin(GPUCompiler.RUNTIME_FUNCTION, msg) ||
occursin(GPUCompiler.UNKNOWN_FUNCTION, msg) ||
occursin(GPUCompiler.DYNAMIC_CALL, msg)) &&
occursin("[1] println", msg) &&
occursin(r"\[2\] .*foobar", msg)
occursin("[2] foobar", msg)
end
end

@testset "invalid LLVM IR (ccall)" begin
foobar(p) = (unsafe_store!(p, ccall(:time, Cint, ())); nothing)
mod = @eval module $(gensym())
export foobar
function foobar(p)
unsafe_store!(p, ccall(:time, Cint, ()))
return
end
end

@test_throws_message(InvalidIRError,
Native.code_execution(foobar, Tuple{Ptr{Int}})) do msg
Native.code_execution(mod.foobar, Tuple{Ptr{Int}})) do msg
if VERSION >= v"1.11-"
occursin("invalid LLVM IR", msg) &&
occursin(GPUCompiler.LAZY_FUNCTION, msg) &&
occursin("call to time", msg) &&
occursin(r"\[1\] .*foobar", msg)
occursin("[1] foobar", msg)
else
occursin("invalid LLVM IR", msg) &&
occursin(GPUCompiler.POINTER_FUNCTION, msg) &&
occursin(r"\[1\] .*foobar", msg)
occursin("[1] foobar", msg)
end
end
end

@testset "delayed bindings" begin
kernel() = (undefined; return)
mod = @eval module $(gensym())
export kernel
function kernel()
undefined
return
end
end

@test_throws_message(InvalidIRError,
Native.code_execution(kernel, Tuple{})) do msg
Native.code_execution(mod.kernel, Tuple{})) do msg
occursin("invalid LLVM IR", msg) &&
occursin(GPUCompiler.DELAYED_BINDING, msg) &&
occursin("use of 'undefined'", msg) &&
occursin(r"\[1\] .*kernel", msg)
occursin(r"use of '.*undefined'", msg) &&
occursin("[1] kernel", msg)
end
end

Expand All @@ -442,15 +457,18 @@ end
occursin("invalid LLVM IR", msg) &&
occursin(GPUCompiler.DYNAMIC_CALL, msg) &&
occursin("call to nospecialize_child", msg) &&
occursin(r"\[1\] kernel", msg)
occursin("[1] kernel", msg)
end
end

@testset "dynamic call (apply)" begin
func() = println(1)
mod = @eval module $(gensym())
export func
func() = println(1)
end

@test_throws_message(InvalidIRError,
Native.code_execution(func, Tuple{})) do msg
Native.code_execution(mod.func, Tuple{})) do msg
occursin("invalid LLVM IR", msg) &&
occursin(GPUCompiler.DYNAMIC_CALL, msg) &&
occursin("call to println", msg) &&
Expand Down
144 changes: 86 additions & 58 deletions test/ptx_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ end
end

ir = sprint(io->PTX.code_llvm(io, mod.kernel, Tuple{mod.Aggregate}))
@test occursin(r"@\w*kernel\w*\(({ i64 }|\[1 x i64\])\* ", ir) ||
occursin(r"@\w*kernel\w*\(ptr ", ir)
@test occursin(r"@julia_kernel\w*\(({ i64 }|\[1 x i64\])\* ", ir) ||
occursin(r"@julia_kernel\w*\(ptr ", ir)

ir = sprint(io->PTX.code_llvm(io, mod.kernel, Tuple{mod.Aggregate}; kernel=true))
@test occursin(r"@\w*kernel\w*\(.*({ i64 }|\[1 x i64\]) ", ir)
@test occursin(r"@_Z6kernel9Aggregate\(.*({ i64 }|\[1 x i64\]) ", ir)
end

@testset "property_annotations" begin
Expand Down Expand Up @@ -83,13 +83,16 @@ end
@testset "kernel state" begin
# state should be passed by value to kernel functions

kernel() = return
mod = @eval module $(gensym())
export kernel
kernel() = return
end

ir = sprint(io->PTX.code_llvm(io, kernel, Tuple{}))
@test occursin(r"@\w*kernel\w*\(\)", ir)
ir = sprint(io->PTX.code_llvm(io, mod.kernel, Tuple{}))
@test occursin(r"@julia_kernel\w*\(\)", ir)

ir = sprint(io->PTX.code_llvm(io, kernel, Tuple{}; kernel=true))
@test occursin(r"@\w*kernel\w*\(\[1 x i64\] %state\)", ir)
ir = sprint(io->PTX.code_llvm(io, mod.kernel, Tuple{}; kernel=true))
@test occursin("@_Z6kernel([1 x i64] %state)", ir)

# state should only passed to device functions that use it

Expand All @@ -111,13 +114,13 @@ end
kernel=true, dump_module=true))

# kernel should take state argument before all else
@test occursin(r"@\w*kernel\w*\(\[1 x i64\] %state", ir)
@test occursin(r"@_Z6kernelP5Int64\(\[1 x i64\] %state", ir)

# child1 doesn't use the state
@test occursin(r"@\w*child1\w*\((i64|i8\*|ptr)", ir)
@test occursin(r"@julia_child1\w*\((i64|i8\*|ptr)", ir)

# child2 does
@test occursin(r"@\w*child2\w*\(\[1 x i64\] %state", ir)
@test occursin(r"@julia_child2\w*\(\[1 x i64\] %state", ir)

# can't have the unlowered intrinsic
@test !occursin("julia.gpu.state_getter", ir)
Expand All @@ -133,46 +136,58 @@ end
@testset "child functions" begin
# we often test using @noinline child functions, so test whether these survive
# (despite not having side-effects)
@noinline child(i) = sink(i)
function parent(i)
child(i)
return

mod = @eval module $(gensym())
import ..sink
export child, parent

@noinline child(i) = sink(i)
function parent(i)
child(i)
return
end
end

asm = sprint(io->PTX.code_native(io, parent, Tuple{Int64}))
@test occursin(r"call.uni\s+julia_.*child_"m, asm)
asm = sprint(io->PTX.code_native(io, mod.parent, Tuple{Int64}))
@test occursin(r"call.uni\s+julia_child_"m, asm)
end

@testset "kernel functions" begin
@noinline nonentry(i) = sink(i)
function entry(i)
nonentry(i)
return
mod = @eval module $(gensym())
import ..sink
export nonentry, entry

@noinline nonentry(i) = sink(i)
function entry(i)
nonentry(i)
return
end
end

asm = sprint(io->PTX.code_native(io, entry, Tuple{Int64}; kernel=true))
@test occursin(r"\.visible \.entry \w*entry", asm)
@test !occursin(r"\.visible \.func \w*nonentry", asm)
@test occursin(r"\.func \w*nonentry", asm)
asm = sprint(io->PTX.code_native(io, mod.entry, Tuple{Int64};
kernel=true, dump_module=true))
@test occursin(".visible .entry _Z5entry5Int64", asm)
@test !occursin(".visible .func julia_nonentry", asm)
@test occursin(".func julia_nonentry", asm)

@testset "property_annotations" begin
asm = sprint(io->PTX.code_native(io, entry, Tuple{Int64}; kernel=true))
asm = sprint(io->PTX.code_native(io, mod.entry, Tuple{Int64}; kernel=true))
@test !occursin("maxntid", asm)

asm = sprint(io->PTX.code_native(io, entry, Tuple{Int64};
asm = sprint(io->PTX.code_native(io, mod.entry, Tuple{Int64};
kernel=true, maxthreads=42))
@test occursin(".maxntid 42, 1, 1", asm)

asm = sprint(io->PTX.code_native(io, entry, Tuple{Int64};
asm = sprint(io->PTX.code_native(io, mod.entry, Tuple{Int64};
kernel=true, minthreads=42))
@test occursin(".reqntid 42, 1, 1", asm)

asm = sprint(io->PTX.code_native(io, entry, Tuple{Int64};
asm = sprint(io->PTX.code_native(io, mod.entry, Tuple{Int64};
kernel=true, blocks_per_sm=42))
@test occursin(".minnctapersm 42", asm)

if LLVM.version() >= v"4.0"
asm = sprint(io->PTX.code_native(io, entry, Tuple{Int64};
asm = sprint(io->PTX.code_native(io, mod.entry, Tuple{Int64};
kernel=true, maxregs=42))
@test occursin(".maxnreg 42", asm)
end
Expand All @@ -183,44 +198,55 @@ end
# bug: depending on a child function from multiple parents resulted in
# the child only being present once

@noinline child(i) = sink(i)
function parent1(i)
child(i)
return
end

asm = sprint(io->PTX.code_native(io, parent1, Tuple{Int}))
@test occursin(r".func \w*child_", asm)
mod = @eval module $(gensym())
import ..sink
export child, parent1, parent2

function parent2(i)
child(i+1)
return
@noinline child(i) = sink(i)
function parent1(i)
child(i)
return
end
function parent2(i)
child(i+1)
return
end
end

asm = sprint(io->PTX.code_native(io, parent2, Tuple{Int}))
@test occursin(r".func \w*child_", asm)
asm = sprint(io->PTX.code_native(io, mod.parent1, Tuple{Int}))
@test occursin(".func julia_child_", asm)

asm = sprint(io->PTX.code_native(io, mod.parent2, Tuple{Int}))
@test occursin(".func julia_child_", asm)
end

@testset "child function reuse bis" begin
# bug: similar, but slightly different issue as above
# in the case of two child functions
@noinline child1(i) = sink(i)
@noinline child2(i) = sink(i+1)
function parent1(i)
child1(i) + child2(i)
return
end
asm = sprint(io->PTX.code_native(io, parent1, Tuple{Int}))
@test occursin(r".func \w*child1_", asm)
@test occursin(r".func \w*child2_", asm)

function parent2(i)
child1(i+1) + child2(i+1)
return
mod = @eval module $(gensym())
import ..sink
export parent1, parent2, child1, child2

@noinline child1(i) = sink(i)
@noinline child2(i) = sink(i+1)
function parent1(i)
child1(i) + child2(i)
return
end
function parent2(i)
child1(i+1) + child2(i+1)
return
end
end
asm = sprint(io->PTX.code_native(io, parent2, Tuple{Int}))
@test occursin(r".func \w*child1_", asm)
@test occursin(r".func \w*child2_", asm)

asm = sprint(io->PTX.code_native(io, mod.parent1, Tuple{Int}))
@test occursin(".func julia_child1_", asm)
@test occursin(".func julia_child2_", asm)

asm = sprint(io->PTX.code_native(io, mod.parent2, Tuple{Int}))
@test occursin(".func julia_child1_", asm)
@test occursin(".func julia_child2_", asm)
end

@testset "indirect sysimg function use" begin
Expand Down Expand Up @@ -261,6 +287,8 @@ end

@testset "GC and TLS lowering" begin
mod = @eval module $(gensym())
import ..sink

mutable struct PleaseAllocate
y::Csize_t
end
Expand Down
Loading

0 comments on commit 6540a44

Please sign in to comment.