Compiling a Metal kernel that ends up with dynamic code crashes the process during optimization, instead of reporting an InvalidIRError:
using Metal, UnsafeAtomics # UnsafeAtomics from JuliaConcurrent/UnsafeAtomics.jl#30
const UA = UnsafeAtomics
wrapper(p, x; kwargs...) = UA.add!(p, x, UA.monotonic, UA.device; kwargs...)
k(a) = (wrapper(pointer(a), Int32(1); volatile = true, align = 8); nothing)
@metal threads=1 k(MtlArray(Int32[0]))
[30093] signal 10 (1): Bus error: 10
_ZN12_GLOBAL__N_112CallAnalyzer7analyzeEv at .../libLLVM.dylib
llvm::getInlineCost(...)
...
llvm::InlinerPass::run(...)
...
llvm::ModuleInlinerWrapperPass::run(...)
LLVMRunJuliaPasses at LLVM/JGisQ/lib/18/libLLVM_extra.jl:319
run! at LLVM/JGisQ/src/newpm.jl:380
optimize_module! at GPUCompiler/src/metal.jl:425
optimize! at GPUCompiler/src/optim.jl:52
emit_llvm at GPUCompiler/src/driver.jl:176
GPUCompiler main (037ef5a), Julia 1.12.7, M1. The same crash happens with the Metal atomics branch (#942/#943). With #949, it crashed earlier instead, in check_allocation!/referenced_object.
The code is dynamic because Julia doesn't const-prop the keywords into the non-inlined wrapper, so align is a run-time value and Val(align) becomes a dynamic call to UnsafeAtomics' @generated llvmcall primitive. Base.@constprop :aggressive on the wrapper avoids it. Metal.code_llvm(…; optimize = false) works and gives about 2,400 lines of IR (typejoin, _growbeg!, boxing, …); the crash is in the LLVM inliner over that module. A similar kernel whose dynamic code doesn't involve llvmcall (wrapper(a, x; kwargs...) = store(a, x, Val(kwargs[:index]))) is correctly reported as an InvalidIRError.
Compiling a Metal kernel that ends up with dynamic code crashes the process during optimization, instead of reporting an
InvalidIRError:GPUCompiler
main(037ef5a), Julia 1.12.7, M1. The same crash happens with the Metal atomics branch (#942/#943). With #949, it crashed earlier instead, incheck_allocation!/referenced_object.The code is dynamic because Julia doesn't const-prop the keywords into the non-inlined
wrapper, soalignis a run-time value andVal(align)becomes a dynamic call to UnsafeAtomics'@generatedllvmcallprimitive.Base.@constprop :aggressiveon the wrapper avoids it.Metal.code_llvm(…; optimize = false)works and gives about 2,400 lines of IR (typejoin,_growbeg!, boxing, …); the crash is in the LLVM inliner over that module. A similar kernel whose dynamic code doesn't involvellvmcall(wrapper(a, x; kwargs...) = store(a, x, Val(kwargs[:index]))) is correctly reported as anInvalidIRError.