diff --git a/Project.toml b/Project.toml index 566a41f7..24c0dfab 100644 --- a/Project.toml +++ b/Project.toml @@ -17,6 +17,7 @@ SPIRVIntrinsics = "71d1d633-e7e8-4a92-83a1-de8814b09ba8" SPIRV_LLVM_Backend_jll = "4376b9bf-cff8-51b6-bb48-39421dff0d0c" SPIRV_Tools_jll = "6ac6d60f-d740-5983-97d7-a4482c0689f4" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +spirv2clc_jll = "f0274c0c-8c8a-59f1-85b7-f7d60330c5fb" [compat] Adapt = "4" @@ -34,3 +35,4 @@ SPIRV_LLVM_Backend_jll = "20" SPIRV_Tools_jll = "2024.4" StaticArrays = "1" julia = "1.10" +spirv2clc_jll = "0.1.0" diff --git a/src/OpenCL.jl b/src/OpenCL.jl index 23cc0abb..a7c39dac 100644 --- a/src/OpenCL.jl +++ b/src/OpenCL.jl @@ -2,7 +2,7 @@ module OpenCL using GPUCompiler using LLVM, LLVM.Interop -using SPIRV_LLVM_Backend_jll, SPIRV_Tools_jll +using SPIRV_LLVM_Backend_jll, SPIRV_Tools_jll, spirv2clc_jll using Adapt using Reexport using GPUArrays diff --git a/src/compiler/compilation.jl b/src/compiler/compilation.jl index 49c50e04..901c6e6c 100644 --- a/src/compiler/compilation.jl +++ b/src/compiler/compilation.jl @@ -64,21 +64,64 @@ function compile(@nospecialize(job::CompilerJob)) (obj, entry=LLVM.name(meta.entry)) end +function run_and_collect(cmd) + stdout = Pipe() + proc = run(pipeline(ignorestatus(cmd); stdout, stderr=stdout), wait=false) + close(stdout.in) + + reader = Threads.@spawn String(read(stdout)) + Base.wait(proc) + log = strip(fetch(reader)) + + return proc, log +end + # link into an executable kernel function link(@nospecialize(job::CompilerJob), compiled) + spirv_bitcode = compiled.obj + clc_source = nothing + prog = if "cl_khr_il_program" in cl.device().extensions - cl.Program(; il=compiled.obj) + cl.Program(; il=spirv_bitcode) else - error("Your device does not support SPIR-V, which is currently required for native execution.") - # XXX: kpet/spirv2clc#87, caused by KhronosGroup/SPIRV-LLVM-Translator#2029 - source = mktempdir() do dir - il = joinpath(dir, "kernel.spv") - write(il, compiled.obj) - cmd = `spirv2clc $il` - read(cmd, String) + @warn """The current active OpenCL device '$(cl.device().name)' does not support IL programs. + Falling back to experimental SPIR-V to OpenCL C translation.""" maxlog=1 _id=Symbol(cl.device().name) + spirv_path = tempname(cleanup=false) * ".spv" + write(spirv_path, spirv_bitcode) + proc, log = run_and_collect(`$(spirv2clc_jll.spirv2clc()) $spirv_path`) + if !success(proc) + msg = "Failed to translate SPIR-V to OpenCL C source code:\n$(log)" + msg *= "\nIf you think this is a bug, please file an issue and attach $spirv_path" + if parse(Bool, get(ENV, "BUILDKITE", "false")) + run(`buildkite-agent artifact upload $spirv_path`) + end + error(msg) + end + rm(spirv_path) + clc_source = strip(log) + cl.Program(; source=clc_source) + end + + try + cl.build!(prog) + catch e + spirv_path = tempname(cleanup=false) * ".spv" + write(spirv_path, spirv_bitcode) + files = [spirv_path] + if clc_source !== nothing + clc_path = tempname(cleanup=false) * ".cl" + write(clc_path, clc_source) + push!(files, clc_path) + end + + msg = "Failed to compile OpenCL program" + msg *= "\nIf you think this is a bug, please file an issue and attach $(join(files, " and "))" + if parse(Bool, get(ENV, "BUILDKITE", "false")) + for file in files + run(`buildkite-agent artifact upload $file`) + end end - cl.Program(; source) + error(msg) end - cl.build!(prog) cl.Kernel(prog, compiled.entry) end