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
54 changes: 54 additions & 0 deletions src/jlgen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,56 @@ const HAS_LLVM_GET_CIS = (
)
)

# Julia before 1.12 casts pointers into `jl_small_typeof` to the generic address space with a
# `bitcast`: for constant references to small-tagged types in imaging mode, as used during
# precompilation (fixed in 1.11 by JuliaLang/julia#51517), and when looking up the type of a
# boxed value (fixed in 1.12). That's invalid IR on targets that put globals in another
# address space, like SPIR-V, so turn those bitcasts into address space casts.
function fix_small_typeof_casts!(mod::LLVM.Module)
haskey(globals(mod), "jl_small_typeof") || return false

function isaddrspacechange(val)
isa(val, LLVM.ConstantExpr) && opcode(val) == LLVM.API.LLVMBitCast ||
isa(val, LLVM.BitCastInst) || return false
src_typ = value_type(operands(val)[1])
dst_typ = value_type(val)
return isa(src_typ, LLVM.PointerType) && isa(dst_typ, LLVM.PointerType) &&
addrspace(src_typ) != addrspace(dst_typ)
end

# find the bad casts first, looking through the GEPs that index the table
casts = LLVM.Value[]
worklist = LLVM.Value[globals(mod)["jl_small_typeof"]]
while !isempty(worklist)
val = pop!(worklist)
for use in uses(val)
usr = user(use)
if isaddrspacechange(usr)
push!(casts, usr)
elseif isa(usr, LLVM.GetElementPtrInst) || isa(usr, LLVM.BitCastInst) ||
isa(usr, LLVM.ConstantExpr) &&
opcode(usr) in (LLVM.API.LLVMGetElementPtr, LLVM.API.LLVMBitCast)
push!(worklist, usr)
end
end
end

for cast in unique(casts)
src = operands(cast)[1]
typ = value_type(cast)
if isa(cast, LLVM.ConstantExpr)
replace_uses!(cast, const_addrspacecast(src, typ))
else
@dispose builder=IRBuilder() begin
position!(builder, cast) # also picks up its debug location
replace_uses!(cast, addrspacecast!(builder, src, typ))
end
erase!(cast)
end
end
return !isempty(casts)
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 @@ -867,6 +917,10 @@ function compile_method_instance(@nospecialize(job::CompilerJob))
cache_gbl = nothing
end

@static if VERSION < v"1.12-"
fix_small_typeof_casts!(llvm_mod)
end

# 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 previous versions when imaging=true, it is also the caller's responsibility
Expand Down
10 changes: 7 additions & 3 deletions src/mangling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ safe_name(@nospecialize(x)) = safe_name(repr(x))
# profilers, support them (grouping different instantiations of the same kernel together).

function mangle_param(@nospecialize(t), substitutions = Any[], top = false)
t == Nothing && return "v"
t === Nothing && return "v"

# Manual lookup instead of `findfirst(isequal(x), substitutions)`: the latter
# builds a `Base.Fix{2, isequal, typeof(x)}` that specializes `findfirst` per
Expand Down Expand Up @@ -120,10 +120,14 @@ function mangle_param(@nospecialize(t), substitutions = Any[], top = false)
mangle_param(Base.unwrap_unionall(t), substitutions)
elseif isa(t, Core.TypeofVararg)
T = isdefined(t, :T) ? t.T : Any
if isdefined(t, :N)
# `N` is a `TypeVar` when the length is still parametric, which is what unwrapping a
# `UnionAll` such as `NTuple{N,Int}` leaves behind. There is no count to repeat then,
# so the type is mangled like the unbounded `Vararg{T}` it is equal to.
N = isdefined(t, :N) && isa(t.N, Integer) ? t.N : nothing
if N !== nothing
# For NTuple, repeat the type as needed
str = ""
for _ in 1:t.N
for _ in 1:N
str *= mangle_param(T, substitutions)
end
str
Expand Down
Loading
Loading