diff --git a/src/debug.jl b/src/debug.jl index 881bad94..382865a2 100644 --- a/src/debug.jl +++ b/src/debug.jl @@ -21,7 +21,9 @@ function backtrace(inst::LLVM.Instruction, bt = StackTraces.StackFrame[]) name = replace(something(scope.name, ""), r";$"=>"") isempty(name) && (name = "unknown") file = scope.file - path = file === nothing ? "unknown" : joinpath(file.directory, file.filename) + path = file === nothing ? "unknown" : + joinpath(file.directory::Union{Nothing,String}, + file.filename::Union{Nothing,String}) line = loc.line push!(bt, StackTraces.StackFrame(name, path, line)) end diff --git a/src/determinism.jl b/src/determinism.jl index 893e4307..cf39af62 100644 --- a/src/determinism.jl +++ b/src/determinism.jl @@ -78,12 +78,12 @@ function dedup_compile_units!(mod::LLVM.Module) cus = mds["llvm.dbg.cu"].operands length(cus) <= 1 && return false - canonical = Dict{Tuple,LLVM.Metadata}() + canonical = Dict{Vector{Union{Nothing,LLVM.Metadata}},LLVM.Metadata}() canonical_cus = LLVM.Metadata[] replacement = Dict{LLVM.Metadata,LLVM.Metadata}() for cu in cus cu === nothing && continue - key = Tuple(cu.operands) + key = Union{Nothing,LLVM.Metadata}[cu.operands...] canon = get!(canonical, key, cu) if canon == cu push!(canonical_cus, cu) diff --git a/src/driver.jl b/src/driver.jl index 13c3f81d..1065ca3c 100644 --- a/src/driver.jl +++ b/src/driver.jl @@ -282,7 +282,13 @@ const __llvm_initialized = Ref(false) # which was loaded in a newer world. dyn_ir, dyn_meta = @invokelatest deferred_codegen(dyn_job, job) dyn_entry_fn = dyn_meta.entry.name - merge!(compiled, dyn_meta.compiled) + # the sibling compiler's result isn't inferred + dyn_compiled = dyn_meta.compiled + if dyn_compiled isa Dict{Any,Any} + merge!(compiled, dyn_compiled) + else + Base.inferencebarrier(merge!)(compiled, dyn_compiled) + end @assert dyn_ir.context == ir.context link_relocatable!(ir, relocations, dyn_ir, dyn_meta.relocations) diff --git a/src/interface.jl b/src/interface.jl index 1b656eaf..0ada05fe 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -61,7 +61,7 @@ llvm_targetinfo(@nospecialize(target::AbstractCompilerTarget)) = nothing # the target's datalayout, with Julia's non-integral address spaces added to it, as a # `DataLayout` the caller owns (or `nothing`) function julia_datalayout(@nospecialize(target::AbstractCompilerTarget)) - dl = llvm_datalayout(target) + dl = llvm_datalayout(target)::Union{Nothing,String} dl === nothing && return nothing LLVM.DataLayout(dl * "-ni:10:11:12:13") end diff --git a/src/irgen.jl b/src/irgen.jl index c40f508c..7ded0af6 100644 --- a/src/irgen.jl +++ b/src/irgen.jl @@ -565,7 +565,7 @@ end # is not passed at the LLVM level. function classify_arguments(@nospecialize(job::CompilerJob), codegen_ft::LLVM.FunctionType; post_optimization::Bool=false) - source_sig = job.source.specTypes + source_sig = job.source.specTypes::DataType source_types = collect(Any, source_sig.parameters) source_argnames = Base.method_argnames(job.source.def) @@ -979,7 +979,7 @@ function (self::AddKernelState)(mod::LLVM.Module) position!(builder, LLVM.before(val)) state_arg = call!(builder, state_intr_ft, state_intr, Value[], "state") new_val = if val isa LLVM.CallInst - call!(builder, ft, f, [state_arg, val.arguments...], + call!(builder, ft, f, Value[state_arg, val.arguments...], val.operand_bundles) else # TODO: invoke and callbr @@ -997,13 +997,10 @@ function (self::AddKernelState)(mod::LLVM.Module) # XXX: we won't have to do this with opaque pointers. position!(builder, LLVM.before(val)) target_ft = val.called_type - new_args = map(zip(target_ft.parameters, - val.arguments)) do (param_typ, arg) - if arg.value_type != param_typ - const_bitcast(arg, param_typ) - else - arg - end + new_args = Value[] + for (param_typ, arg) in zip(target_ft.parameters, val.arguments) + push!(new_args, arg.value_type != param_typ ? + const_bitcast(arg, param_typ) : arg) end new_val = call!(builder, val.called_type, val.called_operand, new_args, val.operand_bundles) @@ -1460,7 +1457,7 @@ function add_input_arguments!(@nospecialize(job::CompilerJob), mod::LLVM.Module, position!(builder, LLVM.before(val)) new_val = if val isa LLVM.CallInst call!(builder, new_f.function_type, new_f, - [val.arguments..., callee_f.parameters[end-nargs+1:end]...], + Value[val.arguments..., callee_f.parameters[end-nargs+1:end]...], val.operand_bundles) else # TODO: invoke and callbr diff --git a/src/mangling.jl b/src/mangling.jl index 9272f05a..5f58e7a0 100644 --- a/src/mangling.jl +++ b/src/mangling.jl @@ -71,7 +71,7 @@ function mangle_param(@nospecialize(t), substitutions = Any[], top = false) # check if we already know this base type str = find_substitution(t.name.wrapper) if str === nothing - tn = safe_name(t) + tn = safe_name(t)::String str = "$(length(tn))$tn" push!(substitutions, t.name.wrapper) end @@ -82,7 +82,7 @@ function mangle_param(@nospecialize(t), substitutions = Any[], top = false) else # encode typevars as template parameters if isempty(t.parameters) - w_types = t.name.wrapper.types + w_types = (t.name.wrapper::DataType).types if !isempty(w_types) && !isempty(w_types[end] isa Core.TypeofVararg) # If the type accepts a variable amount of parameters, # e.g. `Tuple{}`, then we mark it as empty: "Tuple<>" @@ -123,7 +123,7 @@ function mangle_param(@nospecialize(t), substitutions = Any[], top = false) # `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 + N = isdefined(t, :N) && isa(t.N, Int) ? t.N::Int : nothing if N !== nothing # For NTuple, repeat the type as needed str = "" @@ -171,7 +171,7 @@ function mangle_param(@nospecialize(t), substitutions = Any[], top = false) bits = string(reinterpret(UInt64, t); base=16) "Ld$(bits)E" else - tn = safe_name(t) # TODO: actually does support digits... + tn = safe_name(t)::String # TODO: actually does support digits... if startswith(tn, r"\d") # C++ classes cannot start with a digit, so mangling doesn't support it tn = "_$(tn)" diff --git a/src/metal.jl b/src/metal.jl index 649f4bc1..aeff57dc 100644 --- a/src/metal.jl +++ b/src/metal.jl @@ -2271,18 +2271,19 @@ function msl_identifier(@nospecialize(T)) str = String(strip(replace(julia_type_words(T), r"[^A-Za-z0-9_]+" => "_"), '_')) return isempty(str) || isdigit(str[1]) ? "_" * str : str end -function julia_type_words(@nospecialize(x)) +# (recursive, so the result type is declared for inference) +function julia_type_words(@nospecialize(x))::String if x isa DataType - join([String(nameof(x)); map(julia_type_words, x.parameters)], "_") + join([String(nameof(x)); String[julia_type_words(p) for p in x.parameters]], "_") elseif x isa Union # (sorted, as Julia orders union members by module name, which can be generated) - join(["Union"; sort!(map(julia_type_words, Base.uniontypes(x)))], "_") + join(["Union"; sort!(String[julia_type_words(T) for T in Base.uniontypes(x)])], "_") elseif x isa UnionAll julia_type_words(Base.unwrap_unionall(x)) elseif x isa TypeVar String(x.name) elseif x isa Tuple - join(map(julia_type_words, x), "_") + join(String[julia_type_words(y) for y in x], "_") elseif x isa Union{Number,Symbol,AbstractChar,AbstractString} string(x) else diff --git a/src/relocation.jl b/src/relocation.jl index 59da580f..31bfab2a 100644 --- a/src/relocation.jl +++ b/src/relocation.jl @@ -83,7 +83,7 @@ end function resolve_relocation_target(target::CGlobalRef) if target.library === nothing # `jl_cglobal` accepts the symbol directly and does the process-wide `jl_dlfind`. - address = ccall(:jl_cglobal, Any, (Any, Any), target.symbol, UInt) + address = ccall(:jl_cglobal, Any, (Any, Any), target.symbol, UInt)::Ptr{UInt} return unsafe_load(address + target.offset) end handle = Libdl.dlopen(target.library) diff --git a/src/rtlib.jl b/src/rtlib.jl index 6c2d16a5..e38bd00c 100644 --- a/src/rtlib.jl +++ b/src/rtlib.jl @@ -37,7 +37,7 @@ function LLVM.call!(builder, rt::Runtime.RuntimeMethodInstance, args=LLVM.Value[ runtime_function_type(job, rt) end LLVM.Function(mod, rt.llvm_name, ft) - end + end::LLVM.Function ft = f.function_type if !isdeclaration(f) && (rt.name !== :gc_pool_alloc && rt.name !== :report_exception) # XXX: uses of the gc_pool_alloc intrinsic can be introduced _after_ the runtime diff --git a/src/runtime.jl b/src/runtime.jl index 52168924..205092bc 100644 --- a/src/runtime.jl +++ b/src/runtime.jl @@ -13,6 +13,11 @@ using ..GPUCompiler using LLVM, LLVM.IR, LLVM.Build using LLVM.Interop +# imported explicitly, so that the binding exists before the generated functions below +# first use it. Julia 1.13 reports edges to a binding that a downstream package's +# precompilation created as invalidations (JuliaLang/julia#59135). +import Base: | + ## representation of a runtime method instance @@ -202,7 +207,7 @@ const gc_bits = 0x3 # FIXME T_pjlvalue = convert(LLVMType, Any; allow_boxed=true) # this isn't really a function, but we abuse it to get the JIT to resolve the address - typ = LLVM.Function(current_module(builder), "jl_" * String(type_name) * "_type", + typ = LLVM.Function(current_module(builder), "jl_" * String(type_name::Symbol) * "_type", LLVM.FunctionType(T_pjlvalue)) typ_var = bitcast!(builder, typ, T_ptag) diff --git a/src/utils.jl b/src/utils.jl index 3fc15d79..02758d79 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -72,6 +72,9 @@ end struct ExternalBackend library::String # path to the shared library, as exported by its JLL prefix::String # e.g. "NVPTX" for `NVPTXCompile` + + # JLLs are loaded lazily, so the type of their library paths isn't inferred + ExternalBackend(library, prefix) = new(library::String, prefix::String) end function api(backend::ExternalBackend, name::String) diff --git a/src/validation.jl b/src/validation.jl index 2fef286a..2b0ea8d9 100644 --- a/src/validation.jl +++ b/src/validation.jl @@ -73,7 +73,7 @@ function explain_nonisbits(@nospecialize(dt), depth=1; maxdepth=10) end function check_invocation(@nospecialize(job::CompilerJob)) - sig = job.source.specTypes + sig = job.source.specTypes::DataType ft = sig.parameters[1] tt = Tuple{sig.parameters[2:end]...} @@ -656,6 +656,7 @@ function emitted_functions(mod::LLVM.Module, compiled) for entry in values(compiled) for name in (entry.func, entry.specfunc) name === nothing && continue + name = name::String # `compiled` holds entries of any type emitted[name] = entry # functions may have been renamed since, but not their debug information f = get(functions, name, nothing) @@ -795,7 +796,9 @@ end function describe_call(src::CodeInfo, mi::MethodInstance, pc::Int, @nospecialize(callee), world::UInt; strict::Bool=false) stmt = src.code[pc] - (stmt isa Expr && stmt.head === :call) || return nothing + # separate checks, so that inference narrows `stmt` to an `Expr` + stmt isa Expr || return nothing + stmt.head === :call || return nothing f = constant_value(stmt.args[1], world) if callee !== nothing f === nothing && strict && return nothing