Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/jlgen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,29 @@ function fix_small_typeof_casts!(mod::LLVM.Module)
return !isempty(casts)
end

# Julia's runtime symbol lookup passes the library-handle global directly to
# jl_load_and_lookup, whose third parameter is a generic pointer. On targets with a
# nonzero global address space (e.g. GCN or SPIR-V), that produces invalid IR before optimization.
# TODO: version-gate once JuliaLang/julia#63715 lands in 1.14 and is backported to 1.13.
function fix_runtime_lookup_casts!(mod::LLVM.Module)
changed = false
for name in ("jl_load_and_lookup", "ijl_load_and_lookup")
haskey(mod.functions, name) || continue
fn = mod.functions[name]
typ = fn.function_type.parameters[3]
for user in fn.users
user isa LLVM.CallInst || continue
user.called_operand == fn || continue
arg = user.arguments[3]
arg.value_type == typ && continue
arg isa LLVM.GlobalVariable || continue
user.arguments[3] = const_addrspacecast(arg, typ)
changed = true
end
end
return changed
end

function compile_method_instance(@nospecialize(job::CompilerJob))
if job.source.def.primary_world > job.world
error("Cannot compile $(job.source) for world $(job.world); method is only valid from world $(job.source.def.primary_world) onwards")
Expand Down Expand Up @@ -787,6 +810,8 @@ function compile_method_instance(@nospecialize(job::CompilerJob))
fix_small_typeof_casts!(llvm_mod)
end

fix_runtime_lookup_casts!(llvm_mod)

# Since Julia 1.13, the caller is responsible for initializing global variables that
# point to global values or bindings with their address in memory. Similarly on earlier
# versions where `HAS_LLVM_GVS_GLOBALS` is true (see
Expand Down
19 changes: 19 additions & 0 deletions test/gcn.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ end

@testset "IR" begin

@testset "runtime symbol lookup" begin
# A libjulia ccall emits a lookup through jl_libjulia_internal_handle. Its global
# lives in AS1 on GCN, while jl_load_and_lookup takes a generic pointer.
mod = @eval module $(gensym())
alloc_string(n::UInt) = ccall(:jl_alloc_string, Any, (Csize_t,), n)
end
job, _ = GCN.create_job(mod.alloc_string, Tuple{UInt})
# Enter through the driver to initialize LLVM's target machinery.
GPUCompiler.code_llvm(devnull, job; optimize=false)
JuliaContext() do ctx
ir, _, _ = GPUCompiler.compile_method_instance(job)
try
@test LLVM.verification_error(ir) === nothing
finally
LLVM.dispose(ir)
end
end
end

@testset "fma" begin
# `fma` uses the hardware instruction, not the Float64-based `fma_emulated`
mod = @eval module $(gensym())
Expand Down
Loading