From 17a3d1cb878e31e7be208afdf8bbc308d0977550 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Thu, 20 Aug 2020 11:02:44 +0200 Subject: [PATCH 1/3] Adapt to deprecated convert routine. --- src/optim.jl | 2 +- src/runtime.jl | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/optim.jl b/src/optim.jl index df95e7ac..75761875 100644 --- a/src/optim.jl +++ b/src/optim.jl @@ -91,7 +91,7 @@ function lower_gc_frame!(fun::LLVM.Function) alloc_obj = functions(mod)["julia.gc_alloc_obj"] alloc_obj_ft = eltype(llvmtype(alloc_obj)) T_prjlvalue = return_type(alloc_obj_ft) - T_pjlvalue = convert(LLVMType, Any, true) + T_pjlvalue = convert(LLVMType, Any; allow_boxed=true) for use in uses(alloc_obj) call = user(use)::LLVM.CallInst diff --git a/src/runtime.jl b/src/runtime.jl index 4ea8d763..c6a8872e 100644 --- a/src/runtime.jl +++ b/src/runtime.jl @@ -127,14 +127,14 @@ end # LLVM type of a tracked pointer function T_prjlvalue() - T_pjlvalue = convert(LLVMType, Any, true) + T_pjlvalue = convert(LLVMType, Any; allow_boxed=true) LLVM.PointerType(eltype(T_pjlvalue), Tracked) end else # FIXME: once we only support 1.4, get rid of this and allow boxed types -T_prjlvalue() = convert(LLVMType, Any, true) +T_prjlvalue() = convert(LLVMType, Any; allow_boxed=true) end @@ -165,7 +165,7 @@ const gc_bits = 0x3 # FIXME T_tag = convert(LLVMType, tag_type) T_ptag = LLVM.PointerType(T_tag) - T_pjlvalue = convert(LLVMType, Any, true) + T_pjlvalue = convert(LLVMType, Any; allow_boxed=true) # create function llvm_f, _ = create_function(T_tag) From 000b4b910aa55e8dd8b5a455b0334fa48bbd3dcf Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Thu, 20 Aug 2020 12:41:35 +0200 Subject: [PATCH 2/3] Adapt to LLVM.jl changes for stateless codegen. --- Manifest.toml | 4 ++- Project.toml | 2 +- src/driver.jl | 16 +++++++----- src/gcn.jl | 25 ++++++++++-------- src/irgen.jl | 25 +++++++++++------- src/mcgen.jl | 3 ++- src/optim.jl | 5 ++-- src/ptx.jl | 26 ++++++++++-------- src/rtlib.jl | 20 ++++++++------ src/runtime.jl | 71 +++++++++++++++++++++++++------------------------- src/utils.jl | 5 ++-- test/native.jl | 26 +++++++++--------- 12 files changed, 128 insertions(+), 100 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 2823b51f..ab820852 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -20,7 +20,9 @@ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" [[LLVM]] deps = ["CEnum", "Libdl", "Printf", "Unicode"] -git-tree-sha1 = "a662366a5d485dee882077e8da3e1a95a86d097f" +git-tree-sha1 = "daa2ad6a085fd7a6cac711062f1aad6f86ecb41c" +repo-rev = "ecb04cf1520ded1cf6e3ca4ac8cc53e15233688b" +repo-url = "https://github.com/maleadt/LLVM.jl.git" uuid = "929cbde3-209d-540e-8aea-75f648917ca0" version = "2.0.0" diff --git a/Project.toml b/Project.toml index 3385f7ff..3a803049 100644 --- a/Project.toml +++ b/Project.toml @@ -18,8 +18,8 @@ TimerOutputs = "0.5" julia = "1.3" [extras] -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] test = ["Test", "Pkg"] diff --git a/src/driver.jl b/src/driver.jl index 3590142f..116e0691 100644 --- a/src/driver.jl +++ b/src/driver.jl @@ -90,17 +90,20 @@ function codegen(output::Symbol, job::CompilerJob; ## LLVM IR + @timeit_debug to "IR generation" begin + ir, kernel = irgen(job, method_instance, world) + ctx = context(ir) + kernel_fn = LLVM.name(kernel) + end + # always preload the runtime, and do so early; it cannot be part of any timing block # because it recurses into the compiler if libraries - runtime = load_runtime(job) + runtime = load_runtime(job, ctx) runtime_fns = LLVM.name.(defs(runtime)) end @timeit_debug to "LLVM middle-end" begin - ir, kernel = @timeit_debug to "IR generation" irgen(job, method_instance, world) - kernel_fn = LLVM.name(kernel) - # target-specific libraries if libraries undefined_fns = LLVM.name.(decls(ir)) @@ -198,6 +201,7 @@ function codegen(output::Symbol, job::CompilerJob; strip=strip, validate=validate, deferred_codegen=false) dyn_kernel_fn = LLVM.name(dyn_kernel) + @assert context(dyn_ir) == ctx link!(ir, dyn_ir) changed = true dyn_kernel_fn @@ -205,9 +209,9 @@ function codegen(output::Symbol, job::CompilerJob; dyn_kernel = functions(ir)[dyn_kernel_fn] # insert a pointer to the function everywhere the kernel is used - T_ptr = convert(LLVMType, Ptr{Cvoid}) + T_ptr = convert(LLVMType, Ptr{Cvoid}, ctx) for call in worklist[dyn_job] - Builder(JuliaContext()) do builder + Builder(ctx) do builder position!(builder, call) fptr = ptrtoint!(builder, dyn_kernel, T_ptr) replace_uses!(call, fptr) diff --git a/src/gcn.jl b/src/gcn.jl index 0557b9dd..dcc007a6 100644 --- a/src/gcn.jl +++ b/src/gcn.jl @@ -47,6 +47,7 @@ end function lower_throw_extra!(mod::LLVM.Module) job = current_job::CompilerJob + ctx = context(mod) changed = false @timeit_debug to "lower throw (extra)" begin @@ -67,7 +68,7 @@ function lower_throw_extra!(mod::LLVM.Module) call = user(use)::LLVM.CallInst # replace the throw with a trap - let builder = Builder(JuliaContext()) + let builder = Builder(ctx) position!(builder, call) emit_exception!(builder, f_name, call) dispose(builder) @@ -104,14 +105,15 @@ function lower_throw_extra!(mod::LLVM.Module) end function emit_trap!(job::CompilerJob{GCNCompilerTarget}, builder, mod, inst) + ctx = context(mod) trap = if haskey(functions(mod), "llvm.trap") functions(mod)["llvm.trap"] else - LLVM.Function(mod, "llvm.trap", LLVM.FunctionType(LLVM.VoidType(JuliaContext()))) + LLVM.Function(mod, "llvm.trap", LLVM.FunctionType(LLVM.VoidType(ctx))) end if Base.libllvm_version < v"9" - rl_ft = LLVM.FunctionType(LLVM.Int32Type(JuliaContext()), - [LLVM.Int32Type(JuliaContext())]) + rl_ft = LLVM.FunctionType(LLVM.Int32Type(ctx), + [LLVM.Int32Type(ctx)]) rl = if haskey(functions(mod), "llvm.amdgcn.readfirstlane") functions(mod)["llvm.amdgcn.readfirstlane"] else @@ -124,8 +126,8 @@ function emit_trap!(job::CompilerJob{GCNCompilerTarget}, builder, mod, inst) # this, the target will only attempt to do a "masked branch", which # only works on vector instructions (trap is a scalar instruction, and # therefore it is executed even when EXEC==0). - rl_val = call!(builder, rl, [ConstantInt(Int32(32), JuliaContext())]) - rl_bc = inttoptr!(builder, rl_val, LLVM.PointerType(LLVM.Int32Type(JuliaContext()))) + rl_val = call!(builder, rl, [ConstantInt(Int32(32), ctx)]) + rl_bc = inttoptr!(builder, rl_val, LLVM.PointerType(LLVM.Int32Type(ctx))) store!(builder, rl_val, rl_bc) end call!(builder, trap) @@ -147,8 +149,9 @@ function wrapper_type(julia_t::Type, codegen_t::LLVMType)::LLVMType end # generate a kernel wrapper to fix & improve argument passing function wrap_entry!(job::CompilerJob, mod::LLVM.Module, entry_f::LLVM.Function) + ctx = context(mod) entry_ft = eltype(llvmtype(entry_f)::LLVM.PointerType)::LLVM.FunctionType - @compiler_assert return_type(entry_ft) == LLVM.VoidType(JuliaContext()) job + @compiler_assert return_type(entry_ft) == LLVM.VoidType(ctx) job # filter out types which don't occur in the LLVM function signatures sig = Base.signature_type(job.source.f, job.source.tt)::Type @@ -165,12 +168,12 @@ function wrap_entry!(job::CompilerJob, mod::LLVM.Module, entry_f::LLVM.Function) in zip(julia_types, parameters(entry_ft))] wrapper_fn = LLVM.name(entry_f) LLVM.name!(entry_f, wrapper_fn * ".inner") - wrapper_ft = LLVM.FunctionType(LLVM.VoidType(JuliaContext()), wrapper_types) + wrapper_ft = LLVM.FunctionType(LLVM.VoidType(ctx), wrapper_types) wrapper_f = LLVM.Function(mod, wrapper_fn, wrapper_ft) # emit IR performing the "conversions" - let builder = Builder(JuliaContext()) - entry = BasicBlock(wrapper_f, "entry", JuliaContext()) + let builder = Builder(ctx) + entry = BasicBlock(wrapper_f, "entry", ctx) position!(builder, entry) wrapper_args = Vector{LLVM.Value}() @@ -211,7 +214,7 @@ function wrap_entry!(job::CompilerJob, mod::LLVM.Module, entry_f::LLVM.Function) end # early-inline the original entry function into the wrapper - push!(function_attributes(entry_f), EnumAttribute("alwaysinline", 0, JuliaContext())) + push!(function_attributes(entry_f), EnumAttribute("alwaysinline", 0, ctx)) linkage!(entry_f, LLVM.API.LLVMInternalLinkage) fixup_metadata!(entry_f) diff --git a/src/irgen.jl b/src/irgen.jl index b5311da3..e54a6648 100644 --- a/src/irgen.jl +++ b/src/irgen.jl @@ -175,6 +175,8 @@ end else function module_setup(job::CompilerJob, mod::LLVM.Module) + ctx = context(mod) + # configure the module triple!(mod, llvm_triple(job.target)) datalayout!(mod, llvm_datalayout(job.target)) @@ -184,14 +186,14 @@ function module_setup(job::CompilerJob, mod::LLVM.Module) # Set Dwarf Version to 2, the DI printer will downgrade to v2 automatically, # but this is technically correct and the only version supported by NVPTX LLVM.flags(mod)["Dwarf Version", LLVM.API.LLVMModuleFlagBehaviorWarning] = - Metadata(ConstantInt(Int32(2), JuliaContext())) + Metadata(ConstantInt(Int32(2), ctx)) LLVM.flags(mod)["Debug Info Version", LLVM.API.LLVMModuleFlagBehaviorError] = - Metadata(ConstantInt(DEBUG_METADATA_VERSION(), JuliaContext())) + Metadata(ConstantInt(DEBUG_METADATA_VERSION(), ctx)) else push!(metadata(mod), "llvm.module.flags", - MDNode([ConstantInt(Int32(1), JuliaContext()), # llvm::Module::Error + MDNode([ConstantInt(Int32(1), ctx), # llvm::Module::Error MDString("Debug Info Version"), - ConstantInt(DEBUG_METADATA_VERSION(), JuliaContext())])) + ConstantInt(DEBUG_METADATA_VERSION(), ctx)])) end end @@ -330,12 +332,13 @@ end function irgen(job::CompilerJob, method_instance::Core.MethodInstance, world) entry, mod = @timeit_debug to "emission" compile_method_instance(job, method_instance, world) + ctx = context(mod) # clean up incompatibilities @timeit_debug to "clean-up" begin for llvmf in functions(mod) # only occurs in debug builds - delete!(function_attributes(llvmf), EnumAttribute("sspstrong", 0, JuliaContext())) + delete!(function_attributes(llvmf), EnumAttribute("sspstrong", 0, ctx)) if VERSION < v"1.5.0-DEV.393" # make function names safe for ptxas @@ -491,6 +494,7 @@ safe_name(x) = safe_name(repr(x)) # exception arguments) and proper debug info to unwind the stack, this pass can go. function lower_throw!(mod::LLVM.Module) job = current_job::CompilerJob + ctx = context(mod) changed = false @timeit_debug to "lower throw" begin @@ -524,7 +528,7 @@ function lower_throw!(mod::LLVM.Module) call = user(use)::LLVM.CallInst # replace the throw with a PTX-compatible exception - let builder = Builder(JuliaContext()) + let builder = Builder(ctx) position!(builder, call) emit_exception!(builder, name, call) dispose(builder) @@ -570,6 +574,7 @@ function emit_exception!(builder, name, inst) bb = position(builder) fun = LLVM.parent(bb) mod = LLVM.parent(fun) + ctx = context(mod) # report the exception if Base.JLOptions().debug_level >= 1 @@ -584,12 +589,13 @@ function emit_exception!(builder, name, inst) # report each frame if Base.JLOptions().debug_level >= 2 rt = Runtime.get(:report_exception_frame) + ft = convert(LLVM.FunctionType, rt, ctx) bt = backtrace(inst) for (i,frame) in enumerate(bt) - idx = ConstantInt(rt.llvm_types[1], i) + idx = ConstantInt(parameters(ft)[1], i) func = globalstring_ptr!(builder, String(frame.func), "di_func") file = globalstring_ptr!(builder, String(frame.file), "di_file") - line = ConstantInt(rt.llvm_types[4], frame.line) + line = ConstantInt(parameters(ft)[4], frame.line) call!(builder, rt, [idx, func, file, line]) end end @@ -601,10 +607,11 @@ function emit_exception!(builder, name, inst) end function emit_trap!(job::CompilerJob, builder, mod, inst) + ctx = context(mod) trap = if haskey(functions(mod), "llvm.trap") functions(mod)["llvm.trap"] else - LLVM.Function(mod, "llvm.trap", LLVM.FunctionType(LLVM.VoidType(JuliaContext()))) + LLVM.Function(mod, "llvm.trap", LLVM.FunctionType(LLVM.VoidType(ctx))) end call!(builder, trap) end diff --git a/src/mcgen.jl b/src/mcgen.jl index 5a068c1e..3d2d00c9 100644 --- a/src/mcgen.jl +++ b/src/mcgen.jl @@ -31,6 +31,7 @@ end # this pass performs that resolution at link time. function resolve_cpu_references!(mod::LLVM.Module) job = current_job::CompilerJob + ctx = context(mod) changed = false for f in functions(mod) @@ -39,7 +40,7 @@ function resolve_cpu_references!(mod::LLVM.Module) # eagerly resolve the address of the binding address = ccall(:jl_cglobal, Any, (Any, Any), fn, UInt) dereferenced = unsafe_load(address) - dereferenced = LLVM.ConstantInt(dereferenced, JuliaContext()) + dereferenced = LLVM.ConstantInt(dereferenced, ctx) function replace_bindings!(value) changed = false diff --git a/src/optim.jl b/src/optim.jl index 75761875..072ba5f3 100644 --- a/src/optim.jl +++ b/src/optim.jl @@ -84,6 +84,7 @@ end function lower_gc_frame!(fun::LLVM.Function) job = current_job::CompilerJob mod = LLVM.parent(fun) + ctx = context(fun) changed = false # plain alloc @@ -91,7 +92,7 @@ function lower_gc_frame!(fun::LLVM.Function) alloc_obj = functions(mod)["julia.gc_alloc_obj"] alloc_obj_ft = eltype(llvmtype(alloc_obj)) T_prjlvalue = return_type(alloc_obj_ft) - T_pjlvalue = convert(LLVMType, Any; allow_boxed=true) + T_pjlvalue = convert(LLVMType, Any, ctx; allow_boxed=true) for use in uses(alloc_obj) call = user(use)::LLVM.CallInst @@ -101,7 +102,7 @@ function lower_gc_frame!(fun::LLVM.Function) sz = ops[2] # replace with PTX alloc_obj - let builder = Builder(JuliaContext()) + let builder = Builder(ctx) position!(builder, call) ptr = call!(builder, Runtime.get(:gc_pool_alloc), [sz]) replace_uses!(call, ptr) diff --git a/src/ptx.jl b/src/ptx.jl index 095eb7e7..e3e62f3b 100644 --- a/src/ptx.jl +++ b/src/ptx.jl @@ -58,36 +58,38 @@ isintrinsic(::CompilerJob{PTXCompilerTarget}, fn::String) = in(fn, ptx_intrinsic runtime_slug(job::CompilerJob{PTXCompilerTarget}) = "ptx-sm_$(job.target.cap.major)$(job.target.cap.minor)" function process_kernel!(job::CompilerJob{PTXCompilerTarget}, mod::LLVM.Module, kernel::LLVM.Function) + ctx = context(mod) + # property annotations annotations = LLVM.Value[kernel] ## kernel metadata - append!(annotations, [MDString("kernel"), ConstantInt(Int32(1), JuliaContext())]) + append!(annotations, [MDString("kernel"), ConstantInt(Int32(1), ctx)]) ## expected CTA sizes if job.target.minthreads != nothing for (dim, name) in enumerate([:x, :y, :z]) bound = dim <= length(job.target.minthreads) ? job.target.minthreads[dim] : 1 append!(annotations, [MDString("reqntid$name"), - ConstantInt(Int32(bound), JuliaContext())]) + ConstantInt(Int32(bound), ctx)]) end end if job.target.maxthreads != nothing for (dim, name) in enumerate([:x, :y, :z]) bound = dim <= length(job.target.maxthreads) ? job.target.maxthreads[dim] : 1 append!(annotations, [MDString("maxntid$name"), - ConstantInt(Int32(bound), JuliaContext())]) + ConstantInt(Int32(bound), ctx)]) end end if job.target.blocks_per_sm != nothing append!(annotations, [MDString("minctasm"), - ConstantInt(Int32(job.target.blocks_per_sm), JuliaContext())]) + ConstantInt(Int32(job.target.blocks_per_sm), ctx)]) end if job.target.maxregs != nothing append!(annotations, [MDString("maxnreg"), - ConstantInt(Int32(job.target.maxregs), JuliaContext())]) + ConstantInt(Int32(job.target.maxregs), ctx)]) end push!(metadata(mod), "nvvm.annotations", MDNode(annotations)) @@ -145,6 +147,7 @@ end # is still responsible for generating structured control flow). function hide_unreachable!(fun::LLVM.Function) job = current_job::CompilerJob + ctx = context(fun) changed = false @timeit_debug to "hide unreachable" begin @@ -153,7 +156,7 @@ function hide_unreachable!(fun::LLVM.Function) # when calling a `noreturn` function, LLVM places an `unreachable` after the call. # this leads to an early `ret` from the function. attrs = function_attributes(fun) - delete!(attrs, EnumAttribute("noreturn", 0, JuliaContext())) + delete!(attrs, EnumAttribute("noreturn", 0, ctx)) # build a map of basic block predecessors predecessors = Dict(bb => Set{LLVM.BasicBlock}() for bb in blocks(fun)) @@ -184,7 +187,7 @@ function hide_unreachable!(fun::LLVM.Function) # TODO: `unreachable; unreachable` catch ex isa(ex, UndefRefError) || rethrow(ex) - let builder = Builder(JuliaContext()) + let builder = Builder(ctx) position!(builder, bb) # find the strict predecessors to this block @@ -220,7 +223,7 @@ function hide_unreachable!(fun::LLVM.Function) # apply the pending terminator rewrites @timeit_debug to "replace" if !isempty(worklist) - let builder = Builder(JuliaContext()) + let builder = Builder(ctx) for (bb, fallthrough) in worklist position!(builder, bb) if fallthrough !== nothing @@ -229,7 +232,7 @@ function hide_unreachable!(fun::LLVM.Function) # couldn't find any other successor. this happens with functions # that only contain a single block, or when the block is dead. ft = eltype(llvmtype(fun)) - if return_type(ft) == LLVM.VoidType(JuliaContext()) + if return_type(ft) == LLVM.VoidType(ctx) # even though returning can lead to invalid control flow, # it mostly happens with functions that just throw, # and leaving the unreachable there would make the optimizer @@ -252,11 +255,12 @@ end # if LLVM knows we're trapping, code is marked `unreachable` (see `hide_unreachable!`). function hide_trap!(mod::LLVM.Module) job = current_job::CompilerJob + ctx = context(mod) changed = false @timeit_debug to "hide trap" begin # inline assembly to exit a thread, hiding control flow from LLVM - exit_ft = LLVM.FunctionType(LLVM.VoidType(JuliaContext())) + exit_ft = LLVM.FunctionType(LLVM.VoidType(ctx)) exit = if job.target.cap < v"7" # ptxas for old compute capabilities has a bug where it messes up the # synchronization stack in the presence of shared memory and thread-divergend exit. @@ -271,7 +275,7 @@ function hide_trap!(mod::LLVM.Module) for use in uses(trap) val = user(use) if isa(val, LLVM.CallInst) - let builder = Builder(JuliaContext()) + let builder = Builder(ctx) position!(builder, val) call!(builder, exit) dispose(builder) diff --git a/src/rtlib.jl b/src/rtlib.jl index 66da0148..2f265784 100644 --- a/src/rtlib.jl +++ b/src/rtlib.jl @@ -42,13 +42,14 @@ function LLVM.call!(builder, rt::Runtime.RuntimeMethodInstance, args=LLVM.Value[ bb = position(builder) f = LLVM.parent(bb) mod = LLVM.parent(f) + ctx = context(mod) # get or create a function prototype if haskey(functions(mod), rt.llvm_name) f = functions(mod)[rt.llvm_name] ft = eltype(llvmtype(f)) else - ft = LLVM.FunctionType(rt.llvm_return_type, rt.llvm_types) + ft = convert(LLVM.FunctionType, rt, ctx) f = LLVM.Function(mod, rt.llvm_name, ft) end @@ -76,8 +77,10 @@ function emit_function!(mod, job::CompilerJob, f, method) tt = Base.to_tuple_type(method.types) new_mod, entry = codegen(:llvm, similar(job, FunctionSpec(f, tt, #=kernel=# false)); optimize=false, libraries=false) - if return_type(eltype(llvmtype(entry))) != method.llvm_return_type - error("Invalid return type for runtime function '$(method.name)': expected $(method.llvm_return_type), got $(return_type(eltype(llvmtype(entry))))") + ft = eltype(llvmtype(entry)) + expected_ft = convert(LLVM.FunctionType, method, context(new_mod)) + if return_type(ft) != return_type(expected_ft) + error("Invalid return type for runtime function '$(method.name)': expected $(return_type(expected_ft)), got $(return_type(ft))") end # recent Julia versions include prototypes for all runtime functions, even if unused @@ -88,6 +91,7 @@ function emit_function!(mod, job::CompilerJob, f, method) dispose(pm) end + @assert context(mod) == context(new_mod) temp_name = LLVM.name(entry) link!(mod, new_mod) entry = functions(mod)[temp_name] @@ -104,8 +108,8 @@ function emit_function!(mod, job::CompilerJob, f, method) LLVM.name!(entry, name) end -function build_runtime(job::CompilerJob) - mod = LLVM.Module("GPUCompiler run-time library", JuliaContext()) +function build_runtime(job::CompilerJob, ctx) + mod = LLVM.Module("GPUCompiler run-time library", ctx) for method in values(Runtime.methods) def = if isa(method.def, Symbol) @@ -122,7 +126,7 @@ function build_runtime(job::CompilerJob) mod end -function load_runtime(job::CompilerJob) +function load_runtime(job::CompilerJob, ctx) # find the first existing cache directory (for when dealing with layered depots) cachedirs = [cachedir(depot) for depot in DEPOT_PATH] filter!(isdir, cachedirs) @@ -151,12 +155,12 @@ function load_runtime(job::CompilerJob) get!(libcache, path) do if ispath(path) open(path) do io - parse(LLVM.Module, read(io), JuliaContext()) + parse(LLVM.Module, read(io), ctx) end else @debug "Building the GPU runtime library at $path" mkpath(output_dir) - lib = build_runtime(job) + lib = build_runtime(job, ctx) open(path, "w") do io write(io, lib) end diff --git a/src/runtime.jl b/src/runtime.jl index c6a8872e..3c96bf0f 100644 --- a/src/runtime.jl +++ b/src/runtime.jl @@ -33,23 +33,20 @@ struct RuntimeMethodInstance llvm_name::String end -function Base.getproperty(rt::RuntimeMethodInstance, field::Symbol) - value = getfield(rt, field) - if field == :llvm_types - if value == nothing - LLVMType[convert.(LLVMType, typ) for typ in rt.types] - else - value() - end - elseif field == :llvm_return_type - if value == nothing - convert(LLVMType, rt.return_type) - else - value() - end +function Base.convert(::Type{LLVM.FunctionType}, rt::RuntimeMethodInstance, ctx::LLVM.Context) + types = if rt.llvm_types === nothing + LLVMType[convert(LLVMType, typ, ctx; allow_boxed=true) for typ in rt.types] + else + rt.llvm_types(ctx) + end + + return_type = if rt.llvm_return_type === nothing + convert(LLVMType, rt.return_type, ctx; allow_boxed=true) else - return value + rt.llvm_return_type(ctx) end + + LLVM.FunctionType(return_type, types) end const methods = Dict{Symbol,RuntimeMethodInstance}() @@ -126,15 +123,15 @@ if VERSION < v"1.4" end # LLVM type of a tracked pointer -function T_prjlvalue() - T_pjlvalue = convert(LLVMType, Any; allow_boxed=true) +function T_prjlvalue(ctx) + T_pjlvalue = convert(LLVMType, Any, ctx; allow_boxed=true) LLVM.PointerType(eltype(T_pjlvalue), Tracked) end else # FIXME: once we only support 1.4, get rid of this and allow boxed types -T_prjlvalue() = convert(LLVMType, Any; allow_boxed=true) +T_prjlvalue(ctx) = convert(LLVMType, Any, ctx; allow_boxed=true) end @@ -162,32 +159,34 @@ const gc_bits = 0x3 # FIXME # get the type tag of a type at run-time @generated function type_tag(::Val{type_name}) where type_name - T_tag = convert(LLVMType, tag_type) - T_ptag = LLVM.PointerType(T_tag) + JuliaContext() do ctx + T_tag = convert(LLVMType, tag_type, ctx) + T_ptag = LLVM.PointerType(T_tag) - T_pjlvalue = convert(LLVMType, Any; allow_boxed=true) + T_pjlvalue = convert(LLVMType, Any, ctx; allow_boxed=true) - # create function - llvm_f, _ = create_function(T_tag) - mod = LLVM.parent(llvm_f) + # create function + llvm_f, _ = create_function(T_tag) + mod = LLVM.parent(llvm_f) - # this isn't really a function, but we abuse it to get the JIT to resolve the address - typ = LLVM.Function(mod, "jl_" * String(type_name) * "_type", - LLVM.FunctionType(T_pjlvalue)) + # this isn't really a function, but we abuse it to get the JIT to resolve the address + typ = LLVM.Function(mod, "jl_" * String(type_name) * "_type", + LLVM.FunctionType(T_pjlvalue)) - # generate IR - Builder(JuliaContext()) do builder - entry = BasicBlock(llvm_f, "entry", JuliaContext()) - position!(builder, entry) + # generate IR + Builder(ctx) do builder + entry = BasicBlock(llvm_f, "entry", ctx) + position!(builder, entry) - typ_var = bitcast!(builder, typ, T_ptag) + typ_var = bitcast!(builder, typ, T_ptag) - tag = load!(builder, typ_var) + tag = load!(builder, typ_var) - ret!(builder, tag) - end + ret!(builder, tag) + end - call_function(llvm_f, tag_type) + call_function(llvm_f, tag_type) + end end # we use `jl_value_ptr`, a Julia pseudo-intrinsic that can be used to box and unbox values diff --git a/src/utils.jl b/src/utils.jl index a01c87d9..20f767c7 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,6 +1,8 @@ export tbaa_make_child -function tbaa_make_child(name::String, constant::Bool=false; ctx::LLVM.Context=JuliaContext()) +@deprecate tbaa_make_child(name::String, constant::Bool) tbaa_make_child(name; constant=constant) + +function tbaa_make_child(name::String, ctx::LLVM.Context=JuliaContext(); constant::Bool=false) tbaa_root = MDNode([MDString("gputbaa", ctx)], ctx) tbaa_struct_type = MDNode([MDString("gputbaa_$name", ctx), @@ -15,7 +17,6 @@ function tbaa_make_child(name::String, constant::Bool=false; ctx::LLVM.Context=J return tbaa_access_tag end - defs(mod::LLVM.Module) = filter(f -> !isdeclaration(f), collect(functions(mod))) decls(mod::LLVM.Module) = filter(f -> isdeclaration(f) && !LLVM.isintrinsic(f), collect(functions(mod))) diff --git a/test/native.jl b/test/native.jl index acefc34b..1f665e22 100644 --- a/test/native.jl +++ b/test/native.jl @@ -25,19 +25,21 @@ include("definitions/native.jl") @testset "Undefined Globals" begin @generated function makegbl(::Val{name}, ::Type{T}, ::Val{isext}) where {name,T,isext} - T_gbl = convert(LLVMType, T) - T_ptr = convert(LLVMType, Ptr{T}) - llvm_f, _ = create_function(T_ptr) - mod = LLVM.parent(llvm_f) - gvar = GlobalVariable(mod, T_gbl, string(name)) - isext && extinit!(gvar, true) - Builder(JuliaContext()) do builder - entry = BasicBlock(llvm_f, "entry", JuliaContext()) - position!(builder, entry) - result = ptrtoint!(builder, gvar, T_ptr) - ret!(builder, result) + JuliaContext() do ctx + T_gbl = convert(LLVMType, T, ctx) + T_ptr = convert(LLVMType, Ptr{T}, ctx) + llvm_f, _ = create_function(T_ptr) + mod = LLVM.parent(llvm_f) + gvar = GlobalVariable(mod, T_gbl, string(name)) + isext && extinit!(gvar, true) + Builder(ctx) do builder + entry = BasicBlock(llvm_f, "entry", ctx) + position!(builder, entry) + result = ptrtoint!(builder, gvar, T_ptr) + ret!(builder, result) + end + call_function(llvm_f, Ptr{T}) end - call_function(llvm_f, Ptr{T}) end function undef_gbl() ext_ptr = makegbl(Val(:someglobal), Int64, Val(true)) From 5d86ab4cd1c63e3c14a764d918a08a86ecf5e5e4 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Thu, 20 Aug 2020 13:52:09 +0200 Subject: [PATCH 3/3] Replace TBAA utils with LLVM.jl's. --- Manifest.toml | 4 ++-- src/utils.jl | 19 ------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index ab820852..b0ea5d1a 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -20,8 +20,8 @@ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" [[LLVM]] deps = ["CEnum", "Libdl", "Printf", "Unicode"] -git-tree-sha1 = "daa2ad6a085fd7a6cac711062f1aad6f86ecb41c" -repo-rev = "ecb04cf1520ded1cf6e3ca4ac8cc53e15233688b" +git-tree-sha1 = "cf5f5a54f381f290cca33a1ccdc12bcd1b453800" +repo-rev = "6ec68e6" repo-url = "https://github.com/maleadt/LLVM.jl.git" uuid = "929cbde3-209d-540e-8aea-75f648917ca0" version = "2.0.0" diff --git a/src/utils.jl b/src/utils.jl index 20f767c7..409be347 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,22 +1,3 @@ -export tbaa_make_child - -@deprecate tbaa_make_child(name::String, constant::Bool) tbaa_make_child(name; constant=constant) - -function tbaa_make_child(name::String, ctx::LLVM.Context=JuliaContext(); constant::Bool=false) - tbaa_root = MDNode([MDString("gputbaa", ctx)], ctx) - tbaa_struct_type = - MDNode([MDString("gputbaa_$name", ctx), - tbaa_root, - LLVM.ConstantInt(0, ctx)], ctx) - tbaa_access_tag = - MDNode([tbaa_struct_type, - tbaa_struct_type, - LLVM.ConstantInt(0, ctx), - LLVM.ConstantInt(constant ? 1 : 0, ctx)], ctx) - - return tbaa_access_tag -end - defs(mod::LLVM.Module) = filter(f -> !isdeclaration(f), collect(functions(mod))) decls(mod::LLVM.Module) = filter(f -> isdeclaration(f) && !LLVM.isintrinsic(f), collect(functions(mod)))