From 6da085bf8e108343e99d25d616b01c396236ade1 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Thu, 29 Jan 2026 11:38:47 +0100 Subject: [PATCH] Switch to FileCheck.jl. --- test/Project.toml | 6 ++- test/bpf.jl | 26 ++++----- test/gcn.jl | 62 +++++++++++----------- test/helpers/test.jl | 120 ++---------------------------------------- test/metal.jl | 58 ++++++++++---------- test/native.jl | 96 +++++++++++++++++----------------- test/ptx.jl | 122 +++++++++++++++++++++---------------------- test/runtests.jl | 2 +- test/spirv.jl | 36 ++++++------- test/utils.jl | 22 -------- 10 files changed, 210 insertions(+), 340 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index def54d1b..1fa140c2 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,6 +1,6 @@ [deps] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" -IOCapture = "b5f81e59-6552-4d32-b1f0-c071b021bf89" +FileCheck = "4e644321-382b-4b05-b0b6-5d23c3d944fb" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" LLVM = "929cbde3-209d-540e-8aea-75f648917ca0" LLVM_jll = "86de99a1-58d6-5da7-8064-bd56ce2e322c" @@ -18,4 +18,6 @@ demumble_jll = "1e29f10c-031c-5a83-9565-69cddfc27673" [compat] Aqua = "0.8" ParallelTestRunner = "1" -LLVM_jll = "15,16,18,20" + +[sources] +FileCheck = {url = "https://github.com/JuliaLLVM/FileCheck.jl", rev="main"} diff --git a/test/bpf.jl b/test/bpf.jl index a4b10f38..15352e3b 100644 --- a/test/bpf.jl +++ b/test/bpf.jl @@ -4,9 +4,9 @@ end @test @filecheck begin - check"CHECK-LABEL: julia_kernel_{{[0-9_]*}}:" - check"CHECK: r0 = 0" - check"CHECK-NEXT: exit" + @check_label "julia_kernel_{{[0-9_]*}}:" + @check "r0 = 0" + @check_next "exit" BPF.code_native(mod.kernel, ()) end end @@ -16,9 +16,9 @@ end end @test @filecheck begin - check"CHECK-LABEL: julia_kernel_{{[0-9_]*}}:" - check"CHECK: r0 = r1" - check"CHECK-NEXT: exit" + @check_label "julia_kernel_{{[0-9_]*}}:" + @check "r0 = r1" + @check_next "exit" BPF.code_native(mod.kernel, (UInt64,)) end end @@ -28,10 +28,10 @@ end end @test @filecheck begin - check"CHECK-LABEL: julia_kernel_{{[0-9_]*}}:" - check"CHECK: r0 = r1" - check"CHECK-NEXT: r0 += 1" - check"CHECK-NEXT: exit" + @check_label "julia_kernel_{{[0-9_]*}}:" + @check "r0 = r1" + @check_next "r0 += 1" + @check_next "exit" BPF.code_native(mod.kernel, (UInt64,)) end end @@ -50,9 +50,9 @@ end end @test @filecheck begin - check"CHECK-LABEL: julia_kernel_{{[0-9_]*}}:" - check"CHECK: call" - check"CHECK-NEXT: exit" + @check_label "julia_kernel_{{[0-9_]*}}:" + @check "call" + @check_next "exit" BPF.code_native(mod.kernel, (Int,)) end end diff --git a/test/gcn.jl b/test/gcn.jl index 95641a44..a16d4254 100644 --- a/test/gcn.jl +++ b/test/gcn.jl @@ -11,12 +11,12 @@ sink_gcn(i) = sink(i, Val(5)) end @test @filecheck begin - check"CHECK-NOT: amdgpu_kernel" + @check_not "amdgpu_kernel" GCN.code_llvm(mod.kernel, Tuple{}; dump_module=true) end @test @filecheck begin - check"CHECK: amdgpu_kernel" + @check "amdgpu_kernel" GCN.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true) end end @@ -30,9 +30,9 @@ end end @test @filecheck begin - check"CHECK-NOT: {{julia_throw_boundserror_[0-9]+}}" - check"CHECK: @gpu_report_exception" - check"CHECK: @gpu_signal_exception" + @check_not "{{julia_throw_boundserror_[0-9]+}}" + @check "@gpu_report_exception" + @check "@gpu_signal_exception" GCN.code_llvm(mod.kernel, Tuple{}) end end @@ -63,9 +63,9 @@ end end @test @filecheck begin - check"CHECK-LABEL: {{(julia|j)_kernel_[0-9]+}}:" - check"CHECK: s_cbranch_exec" - check"CHECK: s_trap 2" + @check_label "{{(julia|j)_kernel_[0-9]+}}:" + @check "s_cbranch_exec" + @check "s_trap 2" GCN.code_native(mod.kernel, Tuple{}) end end @@ -83,9 +83,9 @@ 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@" + @check_label "{{(julia|j)_parent_[0-9]+}}:" + @check "s_add_u32 {{.+}} {{(julia|j)_child_[0-9]+}}@rel32@" + @check "s_addc_u32 {{.+}} {{(julia|j)_child_[0-9]+}}@rel32@" GCN.code_native(mod.parent, Tuple{Int64}; dump_module=true) end end @@ -101,9 +101,9 @@ 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" + @check_not ".amdhsa_kernel {{(julia|j)_nonentry_[0-9]+}}" + @check ".type {{(julia|j)_nonentry_[0-9]+}},@function" + @check ".amdhsa_kernel _Z5entry5Int64" GCN.code_native(mod.entry, Tuple{Int64}; dump_module=true, kernel=true) end end @@ -126,12 +126,12 @@ end end @test @filecheck begin - check"CHECK: .type {{(julia|j)_child_[0-9]+}},@function" + @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" + @check ".type {{(julia|j)_child_[0-9]+}},@function" GCN.code_native(mod.parent2, Tuple{Int}; dump_module=true) end end @@ -155,14 +155,14 @@ 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" + @check_dag ".type {{(julia|j)_child1_[0-9]+}},@function" + @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" + @check_dag ".type {{(julia|j)_child1_[0-9]+}},@function" + @check_dag ".type {{(julia|j)_child2_[0-9]+}},@function" GCN.code_native(mod.parent2, Tuple{Int}; dump_module=true) end end @@ -182,9 +182,9 @@ end end @test @filecheck begin - check"CHECK-LABEL: {{(julia|j)_kernel_[0-9]+}}:" - check"CHECK-NOT: jl_throw" - check"CHECK-NOT: jl_invoke" + @check_label "{{(julia|j)_kernel_[0-9]+}}:" + @check_not "jl_throw" + @check_not "jl_invoke" GCN.code_native(mod.kernel, Tuple{Ptr{Int32}}) end end @@ -234,11 +234,11 @@ false && @testset "GC and TLS lowering" begin 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" + @check_not "jl_push_gc_frame" + @check_not "jl_pop_gc_frame" + @check_not "jl_get_gc_frame_slot" + @check_not "jl_new_gc_frame" + @check "gpu_gc_pool_alloc" GCN.code_native(mod.kernel, Tuple{Int}) end @@ -256,7 +256,7 @@ false && @testset "GC and TLS lowering" begin end @test @filecheck begin - check"CHECK-NOT: gpu_gc_pool_alloc" + @check_not "gpu_gc_pool_alloc" GCN.code_native(ref_kernel, Tuple{Ptr{Int64}, Int}) end end @@ -275,8 +275,8 @@ end end @test @filecheck begin - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: jl_box_float32" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check "jl_box_float32" GCN.code_llvm(mod.kernel, Tuple{Float32,Ptr{Float32}}) end GCN.code_native(devnull, mod.kernel, Tuple{Float32,Ptr{Float32}}) diff --git a/test/helpers/test.jl b/test/helpers/test.jl index 014ddb27..895af911 100644 --- a/test/helpers/test.jl +++ b/test/helpers/test.jl @@ -36,120 +36,10 @@ end return :(Base.llvmcall($llvmcall_str, T, Tuple{T}, i)) end -# filecheck utils +# typed/opaque pointer detection for conditional FileCheck checks -module FileCheck - import LLVM_jll - import IOCapture - using GPUCompiler, LLVM - - export filecheck, @filecheck, @check_str - - global filecheck_path::String - function __init__() - global filecheck_path = joinpath(LLVM_jll.artifact_dir, "tools", "FileCheck") - end - - function filecheck_exe(; adjust_PATH::Bool=true, adjust_LIBPATH::Bool=true) - env = Base.invokelatest( - LLVM_jll.JLLWrappers.adjust_ENV!, - copy(ENV), - LLVM_jll.PATH[], - LLVM_jll.LIBPATH[], - adjust_PATH, - adjust_LIBPATH - ) - - return Cmd(Cmd([filecheck_path]); env) - end - - const julia_typed_pointers = JuliaContext() do ctx - supports_typed_pointers(ctx) - end - - function filecheck(f, input) - # FileCheck assumes that the input is available as a file - 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 - f(input) - end - output_io = IOBuffer() - write(output_io, result.output) - println(output_io) - - if result.error - # if the function errored, also render the exception and backtrace - showerror(output_io, result.value, result.backtrace) - elseif result.value !== nothing - # also show the returned value; some APIs don't print - write(output_io, string(result.value)) - end - - # determine some useful prefixes for FileCheck - 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") - else - push!(prefixes, "OPAQUE") - end - ## whether we pass pointers as integers or as actual pointers - if VERSION >= v"1.12.0-DEV.225" - push!(prefixes, "PTR_ABI") - else - push!(prefixes, "INTPTR_ABI") - end - - # now pass the collected output to 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) - close(filecheck_io.in) - - # collect the output of FileCheck - reader = Threads.@spawn String(read(filecheck_io)) - Base.wait(proc) - log = strip(fetch(reader)) - - # error out if FileCheck did not succeed. - # otherwise, return true so that `@test @filecheck` works as expected. - if !success(proc) - error(log) - end - return true - end - end - - # collect checks used in the @filecheck block by piggybacking on macro expansion - const checks = String[] - macro check_str(str) - push!(checks, str) - nothing - end - - macro filecheck(ex) - ex = Base.macroexpand(__module__, ex) - if isempty(checks) - error("No checks provided within the @filecheck macro block") - end - check_str = join(checks, "\n") - empty!(checks) - - esc(quote - filecheck($check_str) do _ - $ex - end - end) - end +using LLVM +const typed_ptrs = JuliaContext() do ctx + supports_typed_pointers(ctx) end +const opaque_ptrs = !typed_ptrs diff --git a/test/metal.jl b/test/metal.jl index 951781f1..d35ada93 100644 --- a/test/metal.jl +++ b/test/metal.jl @@ -7,17 +7,17 @@ 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" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check_same cond=typed_ptrs "({{(\\{ i64 \\}|\\[1 x i64\\])}}*" + @check_same cond=opaque_ptrs "(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)" + @check_label "define void @_Z6kernel5TupleI5Int64E" + @check_same cond=typed_ptrs "({{(\\{ i64 \\}|\\[1 x i64\\])}} addrspace(1)*" + @check_same cond=opaque_ptrs "(ptr addrspace(1)" Metal.code_llvm(mod.kernel, Tuple{Tuple{Int}}; kernel=true) end end @@ -28,16 +28,16 @@ end end @test @filecheck begin - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK-SAME: (i64" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @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)" + @check_label "define void @_Z6kernel5Int64" + @check_same cond=typed_ptrs "(i64 addrspace(1)*" + @check_same cond=opaque_ptrs "(ptr addrspace(1)" Metal.code_llvm(mod.kernel, Tuple{Int}; kernel=true) end end @@ -48,9 +48,9 @@ end end @test @filecheck begin - check"CHECK: air.version" - check"CHECK: air.language_version" - check"CHECK: air.max_device_buffers" + @check "air.version" + @check "air.language_version" + @check "air.max_device_buffers" Metal.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true) end end @@ -61,7 +61,7 @@ end end @test @filecheck begin - check"CHECK: air.buffer" + @check "air.buffer" Metal.code_llvm(mod.kernel, Tuple{Int}; dump_module=true, kernel=true) end @@ -80,18 +80,18 @@ 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" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check_same cond=typed_ptrs "({{.+}} addrspace(1)* %{{.+}})" + @check_same cond=opaque_ptrs "(ptr addrspace(1) %{{.+}})" + @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" + @check_label "define void @_Z6kernel7LLVMPtrI5Int64Li1EE" + @check_same cond=typed_ptrs "({{.+}} addrspace(1)* %{{.+}}, i32 %thread_position_in_threadgroup)" + @check_same cond=opaque_ptrs "(ptr addrspace(1) %{{.+}}, i32 %thread_position_in_threadgroup)" + @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 @@ -103,8 +103,8 @@ end end @test @filecheck begin - check"CHECK-LABEL: define <2 x i64> @{{(julia|j)_foo_[0-9]+}}" - check"CHECK: air.max.s.v2i64" + @check_label "define <2 x i64> @{{(julia|j)_foo_[0-9]+}}" + @check "air.max.s.v2i64" Metal.code_llvm(mod.foo, (NTuple{2, VecElement{Int64}}, NTuple{2, VecElement{Int64}})) end end @@ -143,8 +143,8 @@ end end @test @filecheck begin - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: @metal_os_log" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check "@metal_os_log" Metal.code_llvm(mod.kernel, Tuple{Core.LLVMPtr{Float32,1}}; validate=true) end @@ -174,8 +174,8 @@ end end @test @filecheck begin - check"CHECK: @{{.+}} ={{.*}} addrspace(2) constant [2 x float]" - check"CHECK: define void @_Z6kernel7LLVMPtrI7Float32Li1EE5Int64" + @check "@{{.+}} ={{.*}} addrspace(2) constant [2 x float]" + @check "define void @_Z6kernel7LLVMPtrI7Float32Li1EE5Int64" Metal.code_llvm(mod.kernel, Tuple{Core.LLVMPtr{Float32,1}, Int}; dump_module=true, kernel=true) end diff --git a/test/native.jl b/test/native.jl index 320bbacf..cbd5ac44 100644 --- a/test/native.jl +++ b/test/native.jl @@ -7,17 +7,17 @@ @test rt === Int @test @filecheck begin - check"CHECK: MethodInstance for identity" + @check "MethodInstance for identity" GPUCompiler.code_warntype(job) end @test @filecheck begin - check"CHECK: @{{(julia|j)_identity_[0-9]+}}" + @check "@{{(julia|j)_identity_[0-9]+}}" GPUCompiler.code_llvm(job) end @test @filecheck begin - check"CHECK: @{{(julia|j)_identity_[0-9]+}}" + @check "@{{(julia|j)_identity_[0-9]+}}" GPUCompiler.code_native(job) end end @@ -105,8 +105,8 @@ end # smoke test job, _ = Native.create_job(mod.kernel, (Int64,)) @test @filecheck begin - check"CHECK-LABEL: define i64 @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: add i64 %{{[0-9]+}}, 1" + @check_label "define i64 @{{(julia|j)_kernel_[0-9]+}}" + @check "add i64 %{{[0-9]+}}, 1" GPUCompiler.code_llvm(job) end @@ -114,8 +114,8 @@ end @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]+}}" - check"CHECK: add i64 %{{[0-9]+}}, 2" + @check_label "define i64 @{{(julia|j)_kernel_[0-9]+}}" + @check "add i64 %{{[0-9]+}}, 2" GPUCompiler.code_llvm(job) end @@ -136,16 +136,16 @@ end # initial compilation source = methodinstance(ft, tt, Base.get_world_counter()) @test @filecheck begin - check"CHECK-LABEL: define i64 @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: add i64 %{{[0-9]+}}, 2" + @check_label "define i64 @{{(julia|j)_kernel_[0-9]+}}" + @check "add i64 %{{[0-9]+}}, 2" Base.invokelatest(GPUCompiler.cached_compilation, cache, source, job.config, compiler, linker) end @test invocations[] == 1 # cached compilation @test @filecheck begin - check"CHECK-LABEL: define i64 @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: add i64 %{{[0-9]+}}, 2" + @check_label "define i64 @{{(julia|j)_kernel_[0-9]+}}" + @check "add i64 %{{[0-9]+}}, 2" Base.invokelatest(GPUCompiler.cached_compilation, cache, source, job.config, compiler, linker) end @test invocations[] == 1 @@ -154,16 +154,16 @@ end @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]+}}" - check"CHECK: add i64 %{{[0-9]+}}, 3" + @check_label "define i64 @{{(julia|j)_kernel_[0-9]+}}" + @check "add i64 %{{[0-9]+}}, 3" Base.invokelatest(GPUCompiler.cached_compilation, cache, source, job.config, compiler, linker) end @test invocations[] == 2 # cached compilation @test @filecheck begin - check"CHECK-LABEL: define i64 @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: add i64 %{{[0-9]+}}, 3" + @check_label "define i64 @{{(julia|j)_kernel_[0-9]+}}" + @check "add i64 %{{[0-9]+}}, 3" Base.invokelatest(GPUCompiler.cached_compilation, cache, source, job.config, compiler, linker) end @test invocations[] == 2 @@ -185,7 +185,7 @@ end # change in configuration config = CompilerConfig(job.config; name="foobar") @test @filecheck begin - check"CHECK: define i64 @foobar" + @check "define i64 @foobar" Base.invokelatest(GPUCompiler.cached_compilation, cache, source, config, compiler, linker) end @test invocations[] == 4 @@ -206,8 +206,8 @@ end @test contains(ir, r"add i64 %\d+, 4") notify(c2) # wake up the task @test @filecheck begin - check"CHECK-LABEL: define i64 @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: add i64 %{{[0-9]+}}, 3" + @check_label "define i64 @{{(julia|j)_kernel_[0-9]+}}" + @check "add i64 %{{[0-9]+}}, 3" fetch(t) end end @@ -237,7 +237,7 @@ end @test @filecheck begin # module should contain our function + a generic call wrapper - check"CHECK: @{{(julia|j)_valid_kernel_[0-9]+}}" + @check "@{{(julia|j)_valid_kernel_[0-9]+}}" Native.code_llvm(mod.valid_kernel, Tuple{}; optimize=false, dump_module=true) end @@ -261,8 +261,8 @@ end end @test @filecheck begin - check"CHECK-LABEL: define i64 @{{(julia|j)_parent_[0-9]+}}" - check"CHECK: call{{.*}} i64 @{{(julia|j)_child_[0-9]+}}" + @check_label "define i64 @{{(julia|j)_parent_[0-9]+}}" + @check "call{{.*}} i64 @{{(julia|j)_child_[0-9]+}}" Native.code_llvm(mod.parent, Tuple{Int}) end end @@ -276,7 +276,7 @@ end end @test @filecheck begin - check"CHECK-NOT: jlsys_" + @check_not "jlsys_" Native.code_llvm(mod.foobar, Tuple{Ptr{Int},Int}) end end @@ -329,18 +329,18 @@ 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" + @check "define {{.+}} @julia" + @check cond=typed_ptrs "define nonnull {}* @jfptr" + @check cond=opaque_ptrs "define nonnull ptr @jfptr" + @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" + @check_label "define void @{{(julia|j)_identity_[0-9]+}}" + @check_not "%safepoint" Native.code_llvm(identity, Tuple{Nothing}; entry_safepoint=false, optimize=false, dump_module=true) end @@ -348,8 +348,8 @@ end # 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" + @check_label "define void @{{(julia|j)_identity_[0-9]+}}" + @check "%safepoint" Native.code_llvm(identity, Tuple{Nothing}; entry_safepoint=true, optimize=false, dump_module=true) end end @@ -374,22 +374,22 @@ end end @test @filecheck begin - check"CHECK: @{{(julia|j)_expensive_[0-9]+}}" + @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]+}}" + @check_not "@{{(julia|j)_expensive_[0-9]+}}" Native.code_llvm(mod.g, Tuple{Int64}; dump_module=true, kernel=true, always_inline=true) end) broken=broken @test @filecheck begin - check"CHECK: @{{(julia|j)_expensive_[0-9]+}}" + @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]+}}" + @check_not "@{{(julia|j)_expensive_[0-9]+}}" Native.code_llvm(mod.h, Tuple{Int64}; dump_module=true, kernel=true, always_inline=true) end) broken=broken end @@ -412,7 +412,7 @@ end end @test @filecheck begin - check"CHECK: attributes #{{.}} = { convergent }" + @check "attributes #{{.}} = { convergent }" Native.code_llvm(mod.convergent_barrier, Tuple{}; dump_module=true, raw=true) end end @@ -598,8 +598,8 @@ end end @test @filecheck begin - check"CHECK-LABEL: @julia_kernel" - check"CHECK: ret i64 0" + @check_label "@julia_kernel" + @check "ret i64 0" Native.code_llvm(mod.kernel, Tuple{}) end @@ -615,8 +615,8 @@ end end @test @filecheck begin - check"CHECK-LABEL: @julia_kernel" - check"CHECK: ret i64 1" + @check_label "@julia_kernel" + @check "ret i64 1" Native.code_llvm(mod.kernel, Tuple{}; mod.method_table) end end @@ -640,9 +640,9 @@ end end @test @filecheck begin - check"CHECK-LABEL: @julia_kernel" - check"CHECK-NOT: apply_generic" - check"CHECK: llvm.floor" + @check_label "@julia_kernel" + @check_not "apply_generic" + @check "llvm.floor" Native.code_llvm(mod.kernel, Tuple{Int, Int}; debuginfo=:none, mod.method_table) end end @@ -668,12 +668,12 @@ end end @test @filecheck begin - check"CHECK-LABEL: @julia_parent" - check"CHECK-NOT: jl_invoke" - check"CHECK-NOT: apply_iterate" - check"CHECK-NOT: inttoptr" - check"CHECK-NOT: apply_type" - check"CHECK: ret void" + @check_label "@julia_parent" + @check_not "jl_invoke" + @check_not "apply_iterate" + @check_not "inttoptr" + @check_not "apply_type" + @check "ret void" Native.code_llvm(mod.parent, Tuple{}; debuginfo=:none, mod.method_table) end end diff --git a/test/ptx.jl b/test/ptx.jl index 9e56ee51..7010917a 100644 --- a/test/ptx.jl +++ b/test/ptx.jl @@ -5,11 +5,11 @@ foobar() = throw(DivideError()) end @test @filecheck begin - check"CHECK-LABEL: define void @{{(julia|j)_foobar_[0-9]+}}" + @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" + @check_not "jl_throw" + @check "gpu_report_exception" PTX.code_llvm(mod.foobar, Tuple{}; dump_module=true) end @@ -26,16 +26,16 @@ 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" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check_same cond=typed_ptrs "({{({ i64 }|\\[1 x i64\\])}}*" + @check_same cond=opaque_ptrs "(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" + @check_label "define ptx_kernel void @_Z6kernel9Aggregate" + @check_not cond=typed_ptrs "*" + @check_not cond=opaque_ptrs "ptr" PTX.code_llvm(mod.kernel, Tuple{mod.Aggregate}; kernel=true) end end @@ -46,40 +46,40 @@ end end @test @filecheck begin - check"CHECK-NOT: nvvm.annotations" + @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" + @check_not "maxntid" + @check_not "reqntid" + @check_not "minctasm" + @check_not "maxnreg" + @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" + @check "maxntidx\", i32 42" + @check "maxntidy\", i32 1" + @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" + @check "reqntidx\", i32 42" + @check "reqntidy\", i32 1" + @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" + @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" + @check "maxnreg\", i32 42" PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true, maxregs=42) end end @@ -90,12 +90,12 @@ LLVM.version() >= v"8" && @testset "calling convention" begin end @test @filecheck begin - check"CHECK-NOT: ptx_kernel" + @check_not "ptx_kernel" PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true) end @test @filecheck begin - check"CHECK: ptx_kernel" + @check "ptx_kernel" PTX.code_llvm(mod.kernel, Tuple{}; dump_module=true, kernel=true) end end @@ -108,12 +108,12 @@ end end @test @filecheck begin - check"CHECK: @{{(julia|j)_kernel[0-9_]*}}()" + @check "@{{(julia|j)_kernel[0-9_]*}}()" PTX.code_llvm(mod.kernel, Tuple{}) end @test @filecheck begin - check"CHECK: @_Z6kernel([1 x i64] %state)" + @check "@_Z6kernel([1 x i64] %state)" PTX.code_llvm(mod.kernel, Tuple{}; kernel=true) end @@ -135,18 +135,18 @@ 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" + @check_label "define ptx_kernel void @_Z6kernelP5Int64([1 x i64] %state" + @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]+}}" + @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]+}}" + @check_label "define{{.*}} i64 @{{(julia|j)_child2_[0-9]+}}" PTX.code_llvm(mod.kernel, Tuple{Ptr{Int64}}; kernel=true, dump_module=true) end end @@ -189,9 +189,9 @@ if :NVPTX in LLVM.backends() end @test @filecheck begin - check"CHECK-LABEL: .visible .func {{(julia|j)_parent[0-9_]*}}" - check"CHECK: call.uni" - check"CHECK-NEXT: {{(julia|j)_child_}}" + @check_label ".visible .func {{(julia|j)_parent[0-9_]*}}" + @check "call.uni" + @check_next "{{(julia|j)_child_}}" PTX.code_native(mod.parent, Tuple{Int64}) end end @@ -207,36 +207,36 @@ end end @test @filecheck begin - check"CHECK-NOT: .visible .func {{(julia|j)_nonentry}}" - check"CHECK-LABEL: .visible .entry _Z5entry5Int64" - check"CHECK: {{(julia|j)_nonentry}}" + @check_not ".visible .func {{(julia|j)_nonentry}}" + @check_label ".visible .entry _Z5entry5Int64" + @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" + @check_not "maxntid" PTX.code_native(mod.entry, Tuple{Int64}; kernel=true) end @test @filecheck begin - check"CHECK: .maxntid 42, 1, 1" + @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" + @check ".reqntid 42, 1, 1" PTX.code_native(mod.entry, Tuple{Int64}; kernel=true, minthreads=42) end @test @filecheck begin - check"CHECK: .minnctapersm 42" + @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" + @check ".maxnreg 42" PTX.code_native(mod.entry, Tuple{Int64}; kernel=true, maxregs=42) end end @@ -261,12 +261,12 @@ end end @test @filecheck begin - check"CHECK: .func {{(julia|j)_child}}" + @check ".func {{(julia|j)_child}}" PTX.code_native(mod.parent1, Tuple{Int}) end @test @filecheck begin - check"CHECK: .func {{(julia|j)_child}}" + @check ".func {{(julia|j)_child}}" PTX.code_native(mod.parent2, Tuple{Int}) end end @@ -290,14 +290,14 @@ end end @test @filecheck begin - check"CHECK-DAG: .func {{(julia|j)_child1}}" - check"CHECK-DAG: .func {{(julia|j)_child2}}" + @check_dag ".func {{(julia|j)_child1}}" + @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}}" + @check_dag ".func {{(julia|j)_child1}}" + @check_dag ".func {{(julia|j)_child2}}" PTX.code_native(mod.parent2, Tuple{Int}) end end @@ -316,9 +316,9 @@ 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" + @check_label ".visible .func {{(julia|j)_kernel[0-9_]*}}" + @check_not "jl_throw" + @check_not "jl_invoke" PTX.code_native(mod.kernel, Tuple{Ptr{Int32}}) end end @@ -367,12 +367,12 @@ end end @test @filecheck begin - check"CHECK-LABEL: .visible .func {{(julia|j)_kernel[0-9_]*}}" - check"CHECK-NOT: julia.push_gc_frame" - check"CHECK-NOT: julia.pop_gc_frame" - check"CHECK-NOT: julia.get_gc_frame_slot" - check"CHECK-NOT: julia.new_gc_frame" - check"CHECK: gpu_gc_pool_alloc" + @check_label ".visible .func {{(julia|j)_kernel[0-9_]*}}" + @check_not "julia.push_gc_frame" + @check_not "julia.pop_gc_frame" + @check_not "julia.get_gc_frame_slot" + @check_not "julia.new_gc_frame" + @check "gpu_gc_pool_alloc" PTX.code_native(mod.kernel, Tuple{Int}) end @@ -392,8 +392,8 @@ end end @test @filecheck begin - check"CHECK-LABEL: .visible .func {{(julia|j)_ref_kernel[0-9_]*}}" - check"CHECK-NOT: gpu_gc_pool_alloc" + @check_label ".visible .func {{(julia|j)_ref_kernel[0-9_]*}}" + @check_not "gpu_gc_pool_alloc" PTX.code_native(mod.ref_kernel, Tuple{Ptr{Int64}, Int}) end end @@ -412,8 +412,8 @@ end end @test @filecheck begin - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: jl_box_float32" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check "jl_box_float32" PTX.code_llvm(mod.kernel, Tuple{Float32,Ptr{Float32}}) end PTX.code_native(devnull, mod.kernel, Tuple{Float32,Ptr{Float32}}) diff --git a/test/runtests.jl b/test/runtests.jl index 1f1d705d..adc2280d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -12,7 +12,7 @@ const init_code = quote include(joinpath(@__DIR__, "helpers", file)) end end - using .FileCheck + using FileCheck end function test_filter(test) diff --git a/test/spirv.jl b/test/spirv.jl index e8903140..123436ca 100644 --- a/test/spirv.jl +++ b/test/spirv.jl @@ -9,12 +9,12 @@ for backend in (:khronos, :llvm) end @test @filecheck begin - check"CHECK-NOT: spir_kernel" + @check_not "spir_kernel" SPIRV.code_llvm(mod.kernel, Tuple{}; backend, dump_module=true) end @test @filecheck begin - check"CHECK: spir_kernel" + @check "spir_kernel" SPIRV.code_llvm(mod.kernel, Tuple{}; backend, dump_module=true, kernel=true) end end @@ -25,12 +25,12 @@ end end @test @filecheck begin - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" SPIRV.code_llvm(mod.kernel, Tuple{Tuple{Int}}; backend) end @test @filecheck begin - check"CHECK-LABEL: define spir_kernel void @_Z6kernel" + @check_label "define spir_kernel void @_Z6kernel" SPIRV.code_llvm(mod.kernel, Tuple{Tuple{Int}}; backend, kernel=true) end end @@ -41,7 +41,7 @@ end @noinline kernel() = return end @test @filecheck begin - check"CHECK-LABEL: define spir_kernel void @_Z6kernel" + @check_label "define spir_kernel void @_Z6kernel" SPIRV.code_llvm(mod.kernel, Tuple{}; backend, kernel=true) end end @@ -56,20 +56,20 @@ end end @test @filecheck begin - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: store half" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check "store half" SPIRV.code_llvm(mod.kernel, Tuple{Ptr{Float16}, Float16}; backend) end @test @filecheck begin - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: store float" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check "store float" SPIRV.code_llvm(mod.kernel, Tuple{Ptr{Float32}, Float32}; backend) end @test @filecheck begin - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" - check"CHECK: store double" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check "store double" SPIRV.code_llvm(mod.kernel, Tuple{Ptr{Float64}, Float64}; backend) end @@ -105,7 +105,7 @@ end end @test @filecheck begin - check"CHECK: %_Z6kernel4Bool = OpFunction %void None" + @check "%_Z6kernel4Bool = OpFunction %void None" SPIRV.code_native(mod.kernel, Tuple{Bool}; backend, kernel=true) end end @@ -131,16 +131,16 @@ end @test @filecheck begin # TODO: should structs of `NTuple{VecElement{T}}` be passed by value instead of sret? - check"CHECK-NOT: i128" - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" - @static VERSION >= v"1.12" && check"CHECK: alloca <2 x i64>, align 16" + @check_not "i128" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check cond=(VERSION >= v"1.12") "alloca <2 x i64>, align 16" SPIRV.code_llvm(mod.kernel, NTuple{2, mod.Vec{4, Float32}}; backend, dump_module=true) end @test @filecheck begin - check"CHECK-NOT: i128" - check"CHECK-LABEL: define void @{{(julia|j)_kernel_[0-9]+}}" - @static VERSION >= v"1.12" && check"CHECK: alloca [2 x <2 x i64>], align 16" + @check_not "i128" + @check_label "define void @{{(julia|j)_kernel_[0-9]+}}" + @check cond=(VERSION >= v"1.12") "alloca [2 x <2 x i64>], align 16" SPIRV.code_llvm(mod.kernel, NTuple{2, mod.Vec{8, Float32}}; backend, dump_module=true) end end diff --git a/test/utils.jl b/test/utils.jl index 3b742795..4ce2258c 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -165,28 +165,6 @@ next_world = Base.get_world_counter() end end -# Test FileCheck -@testset "FileCheck" begin - @test @filecheck begin - check"CHECK: works" - println("works") - end - - @test_throws "expected string not found in input" @filecheck begin - check"CHECK: works" - println("doesn't work") - end - - @test @filecheck begin - check"CHECK: errors" - error("errors") - end - - @test_throws "expected string not found in input" @filecheck begin - check"CHECK: works" - error("errors") - end -end @testset "Mock Enzyme" begin Enzyme.deferred_codegen_id(typeof(identity), Tuple{Vector{Float64}})