Skip to content

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

Merged
merged 6 commits into from
Jun 25, 2025
Merged

Allow the use of FileCheck #703

merged 6 commits into from
Jun 25, 2025

Conversation

vchuravy
Copy link
Member

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) where f 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

mod = """
define i32 @test(ptr %a) nounwind {
  %1 = load atomic i32, ptr %a seq_cst, align 16
; CHECK: ...
  ret i8 %1
}
"""

filecheck(mod) do mod
    job = # fake_job
    asm, meta = JuliaContext(opaque_pointers=true) do ctx
        ir = parse(LLVM.Module, mod)
        GPUCompiler.emit_asm(job, ir, LLVM.API.LLVMAssemblyFile)
    end
    write(stdout, asm)
end

Copy link
Contributor

github-actions bot commented Jun 20, 2025

Your PR requires formatting changes to meet the project's style guidelines.
Please consider running Runic (git runic master) to apply these changes.

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]*

@maleadt
Copy link
Member

maleadt commented Jun 20, 2025

write(stdout, asm)

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.

filecheck(mod) do mod

That seems redundant?

What about:

filecheck() do check
    # we can capture mod, convert it to asm
    check(asm)
end

If FileCheck is configurable, the filecheck function could take kwargs.

Copy link

codecov bot commented Jun 20, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 71.63%. Comparing base (79e0f56) to head (8a17cba).
Report is 1 commits behind head on master.

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@vchuravy
Copy link
Member Author

The big goal was to allow for multiline RUN commands written in Julia, with support for the FileCheck testing syntax.

A normal LLVM test file looks like:

; RUN: opt %s ... | FileCheck %s

define...
; CHECK:

The RUN part is parsed by lit and then executed (one can have multiple RUN statements)

The crux is that FileCheck is comparing two "files"

One is the input file with the CHECK statements (often as comments) and the other (often as a stream, but could also be a file) is the output that FileCheck is validating

So the input argument to the filecheck function is the list of CHECK statements, which often enough is the actual LLVM IR, with the CHECK statements as comments.

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.

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.

Copy link
Member Author

@vchuravy vchuravy left a 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

@maleadt
Copy link
Member

maleadt commented Jun 23, 2025

Trying this out, it looks like a match failure doesn't trigger test failures:

     Testing Running tests...
[ Info: Running 32 tests in parallel. If this is too many, specify the `--jobs` argument to the tests, or set the JULIA_CPU_THREADS environment variable.
                    |          | ---------------- CPU ---------------- |
Test       (Worker) | Time (s) | GC (s) | GC % | Alloc (MB) | RSS (MB) |
ptx/precompile  (3) |     6.25 |   0.00 |  0.0 |      58.80 |   557.61 |
      From worker 2:    /tmp/jl_c3EmRn:1:10: error: CHECK: expected string not found in input
      From worker 2:    ; CHECK: @{{(julia|j)_kernel\w*}}({{(ptr | { i64 }* | [1 x i64]*)}}
      From worker 2:             ^
      From worker 2:    <stdin>:1:1: note: scanning from here
      From worker 2:    ; @ /home/tim/Julia/pkg/GPUCompiler/test/ptx.jl:16 within `kernel`
      From worker 2:    ^
      From worker 2:    <stdin>:2:6: note: possible intended match here
      From worker 2:    define void @julia_kernel_12063([1 x i64]* nocapture noundef nonnull readonly align 8 dereferenceable(8) %0) local_unnamed_addr {
      From worker 2:         ^
      From worker 2:
      From worker 2:    Input file: <stdin>
      From worker 2:    Check file: /tmp/jl_c3EmRn
      From worker 2:
      From worker 2:    -dump-input=help explains the following input dump.
      From worker 2:
      From worker 2:    Input was:
      From worker 2:    <<<<<<
      From worker 2:               1: ; @ /home/tim/Julia/pkg/GPUCompiler/test/ptx.jl:16 within `kernel` 
      From worker 2:    check:1'0     X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
      From worker 2:               2: define void @julia_kernel_12063([1 x i64]* nocapture noundef nonnull readonly align 8 dereferenceable(8) %0) local_unnamed_addr { 
      From worker 2:    check:1'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      From worker 2:    check:1'1          ?                                                                                                                             possible intended match
      From worker 2:               3: top: 
      From worker 2:    check:1'0     ~~~~~
      From worker 2:               4:  ret void 
      From worker 2:    check:1'0     ~~~~~~~~~~
      From worker 2:               5: } 
      From worker 2:    check:1'0     ~~
      From worker 2:               6:  
      From worker 2:    check:1'0     ~
      From worker 2:    >>>>>>
ptx             (2) |    10.50 |   0.09 |  0.9 |     743.02 |   617.80 |
Testing finished in 14 seconds, 101 milliseconds

Test Summary: | Pass  Total  Time
  Overall     |   54     54      
    SUCCESS
     Testing GPUCompiler tests passed 

@vchuravy
Copy link
Member Author

Good point. I currently always have @test success which is annoying.

@maleadt
Copy link
Member

maleadt commented Jun 24, 2025

Took it a bit further / too far... But it looks nice, I think.

@maleadt maleadt force-pushed the vc/filecheck branch 2 times, most recently from f318e83 to 11530d9 Compare June 24, 2025 09:24
@vchuravy
Copy link
Member Author

LGTM!

@maleadt
Copy link
Member

maleadt commented Jun 24, 2025

Great. Will try to do some more conversions first, should be a great task for an LLM agent.

@maleadt
Copy link
Member

maleadt commented Jun 24, 2025

So one tricky thing is that CHECKs with FileCheck are order-dependent, while functions aren't emitted in the same order (e.g., with differences across Julia versions, or depending on whether bounds checks are used or not). I've used CHECK-DAG for a couple, and split some other checks into multiple @filecheck blocks, but I'm not entirely happy with this. Or maybe it just needs to grow on me.

Co-authored-by: Valentin Churavy <[email protected]>
@maleadt
Copy link
Member

maleadt commented Jun 24, 2025

So this escalated. Anyhow, there's still a handful of things I want to do; I'll finish tonight or tomorrow.

@maleadt maleadt merged commit 8b8c73f into master Jun 25, 2025
18 of 22 checks passed
@maleadt maleadt deleted the vc/filecheck branch June 25, 2025 06:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants