From dfad142ba6416f33f2f4827135b8033ba8cd0faa Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 4 Sep 2023 11:06:14 +0200 Subject: [PATCH] Drop support for Julia 1.6-1.7. --- .github/workflows/ci.yml | 10 +- Project.toml | 2 +- README.md | 16 +- examples/sum_orc.jl | 52 +---- src/LLVM.jl | 17 +- src/core/attributes.jl | 7 +- src/interop/base.jl | 13 +- src/interop/passes.jl | 6 +- src/orc.jl | 475 +++++++++++++++++++++++++++++--------- src/orcv2.jl | 431 ---------------------------------- src/state.jl | 4 - test/core_tests.jl | 26 +-- test/debuginfo_tests.jl | 19 +- test/jljit_tests.jl | 4 +- test/orc_tests.jl | 484 ++++++++++++++++++--------------------- test/orcv2_tests.jl | 306 ------------------------- test/runtests.jl | 10 - test/transform_tests.jl | 10 +- 18 files changed, 656 insertions(+), 1236 deletions(-) delete mode 100644 src/orcv2.jl delete mode 100644 test/orcv2_tests.jl diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84a79352..921c99a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - version: ['1.6', '1.7', '1.8', '1.9', 'nightly'] + version: ['1.8', '1.9', 'nightly'] os: ['ubuntu-latest', 'macOS-latest', 'windows-latest'] arch: [x64] llvm_args: [''] @@ -85,7 +85,7 @@ jobs: strategy: fail-fast: false matrix: - branch: ['release-1.6', 'release-1.7', 'release-1.8', 'release-1.9', 'master'] + branch: ['release-1.8', 'release-1.9', 'master'] os: ['ubuntu-latest', 'macOS-latest', 'windows-latest'] arch: ['x64'] llvm_args: [''] @@ -114,10 +114,6 @@ jobs: - branch: 'master' os: 'macOS-latest' arch: 'x64' - # 1.6 requires gfortran, which isn't available on macOS runners - - branch: 'release-1.6' - os: 'macOS-latest' - arch: 'x64' steps: - uses: actions/checkout@v3 with: @@ -191,7 +187,7 @@ jobs: - uses: actions/checkout@v3 - uses: julia-actions/setup-julia@latest with: - version: '1.6' + version: '1.8' - name: Install dependencies run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - name: Build and deploy diff --git a/Project.toml b/Project.toml index d655a843..54e2e8ed 100644 --- a/Project.toml +++ b/Project.toml @@ -12,4 +12,4 @@ Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" [compat] CEnum = "0.2, 0.3, 0.4" LLVMExtra_jll = "=0.0.23" -julia = "1.6" +julia = "1.8" diff --git a/README.md b/README.md index 0629d6d0..44dbe6c2 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,16 @@ by Julia, to interoperate with the Julia compiler, or to create your own compile heavily used by the different GPU compilers for the Julia programming language. +## Requirements + +LLVM.jl is supported on Juila 1.8+, and thus requires LLVM 13. However, the package is +really only **intended to be used with the LLVM library shipped with Julia**. That means you +can not use it with other LLVM libraries, like the one provided by your operating system. It +is recommended to use the official binaries from +[julialang.org](https://julialang.org/downloads/), but custom builds are supported too (as +long as they provide a dynamically-linked copy of the LLVM library). + + ## Installation LLVM.jl can be installed with the Julia package manager. @@ -39,9 +49,3 @@ Or, equivalently, via the `Pkg` API: ```julia julia> import Pkg; Pkg.add("LLVM") ``` - -Note that the package **is intended to be used with the LLVM library shipped with Julia**. -That means you can not use it with other LLVM libraries, like the one provided by your -operating system. It is recommended to use the official binaries from -[julialang.org](https://julialang.org/downloads/), but custom builds are supported too (as -long as they provide a dynamically-linked copy of the LLVM library). diff --git a/examples/sum_orc.jl b/examples/sum_orc.jl index 8e7ab4fa..09d47aeb 100644 --- a/examples/sum_orc.jl +++ b/examples/sum_orc.jl @@ -41,51 +41,21 @@ function codegen!(mod::LLVM.Module, name, tm) end tm = JITTargetMachine() -if LLVM.has_orc_v2() - # XXX: LLJIT calls TargetMachineBuilder which disposes the TargetMachine - jit = LLJIT(; tm=JITTargetMachine()) - - @dispose ts_ctx=ThreadSafeContext() begin - ts_mod = ThreadSafeModule("jit") - name = "sum_orc.jl" - ts_mod() do mod - codegen!(mod, name, tm) - end - - jd = JITDylib(jit) - add!(jit, jd, ts_mod) - addr = lookup(jit, name) - - @eval call_sum(x, y) = ccall($(pointer(addr)), Int32, (Int32, Int32), x, y) - end -else - jit = OrcJIT(tm) - register!(jit, GDBRegistrationListener()) +# XXX: LLJIT calls TargetMachineBuilder which disposes the TargetMachine +jit = LLJIT(; tm=JITTargetMachine()) - @dispose ctx=Context() begin - mod = LLVM.Module("jit") - name = mangle(jit, "sum_orc.jl") +@dispose ts_ctx=ThreadSafeContext() begin + ts_mod = ThreadSafeModule("jit") + name = "sum_orc.jl" + ts_mod() do mod codegen!(mod, name, tm) - - # For debugging: - # asm = String(convert(Vector{UInt8}, emit(tm, mod, LLVM.API.LLVMAssemblyFile))) - # write(stdout, asm) - - jitted_mod = compile!(jit, mod) - - addr = address(jit, name) - addr2 = addressin(jit, jitted_mod, name) - @test addr == addr2 - @test addr.ptr != 0 - - # For debugging: - # ccall(:jl_breakpoint, Cvoid, (Any,), pointer(addr)) - # Then in GDB - # b *(*(uint64_t*)v) - @eval call_sum(x, y) = ccall($(pointer(addr)), Int32, (Int32, Int32), x, y) end - unregister!(jit, GDBRegistrationListener()) + jd = JITDylib(jit) + add!(jit, jd, ts_mod) + addr = lookup(jit, name) + + @eval call_sum(x, y) = ccall($(pointer(addr)), Int32, (Int32, Int32), x, y) end @test call_sum(x, y) == x + y diff --git a/src/LLVM.jl b/src/LLVM.jl index 27bb74f5..b433d732 100644 --- a/src/LLVM.jl +++ b/src/LLVM.jl @@ -48,6 +48,9 @@ include(joinpath(@__DIR__, "..", "lib", "libLLVM_julia.jl")) end # module API +has_newpm() = LLVM.version() >= v"15" +has_julia_ojit() = VERSION >= v"1.10.0-DEV.1395" + # LLVM API wrappers include("support.jl") include("types.jl") @@ -72,19 +75,7 @@ include("debuginfo.jl") include("dibuilder.jl") include("jitevents.jl") include("utils.jl") - -has_orc_v1() = v"8" <= LLVM.version() < v"12" -if has_orc_v1() - include("orc.jl") -end - -has_orc_v2() = v"12" <= LLVM.version() -has_julia_ojit() = VERSION >= v"1.10.0-DEV.1395" -if has_orc_v2() - include("orcv2.jl") -end - -has_newpm() = v"15" <= LLVM.version() +include("orc.jl") if has_newpm() include("newpm.jl") end diff --git a/src/core/attributes.jl b/src/core/attributes.jl index 65a24713..767f146e 100644 --- a/src/core/attributes.jl +++ b/src/core/attributes.jl @@ -30,12 +30,9 @@ function Attribute(ref::API.LLVMAttributeRef) return EnumAttribute(ref) elseif convert(Core.Bool, API.LLVMIsStringAttribute(ref)) return StringAttribute(ref) + elseif convert(Core.Bool, API.LLVMIsTypeAttribute(ref)) + return TypeAttribute(ref) else - @static if LLVM.version() >= v"12" - if convert(Core.Bool, API.LLVMIsTypeAttribute(ref)) - return TypeAttribute(ref) - end - end error("unknown attribute kind") end end diff --git a/src/interop/base.jl b/src/interop/base.jl index f7e4325c..3f5445d6 100644 --- a/src/interop/base.jl +++ b/src/interop/base.jl @@ -33,16 +33,9 @@ function call_function(llvmf::LLVM.Function, rettyp::Type=Nothing, argtyp::Type= ir = string(mod) fn = LLVM.name(llvmf) @assert !isempty(fn) - if VERSION >= v"1.8.0-DEV.410" - quote - Base.@inline - Base.llvmcall(($ir,$fn), $rettyp, $argtyp, $(args...)) - end - else - quote - Base.@_inline_meta - Base.llvmcall(($ir,$fn), $rettyp, $argtyp, $(args...)) - end + quote + Base.@inline + Base.llvmcall(($ir,$fn), $rettyp, $argtyp, $(args...)) end end diff --git a/src/interop/passes.jl b/src/interop/passes.jl index 0dd0e472..0643c322 100644 --- a/src/interop/passes.jl +++ b/src/interop/passes.jl @@ -35,8 +35,4 @@ remove_ni!(pm::PassManager) = API.LLVMAddRemoveNIPass(pm) julia_licm!(pm::PassManager) = API.LLVMAddJuliaLICMPass(pm) -if VERSION >= v"1.8.0-DEV.1120" - cpu_features!(pm::PassManager) = API.LLVMAddCPUFeaturesPass(pm) -else - cpu_features!(pm::PassManager) = nothing -end +cpu_features!(pm::PassManager) = API.LLVMAddCPUFeaturesPass(pm) diff --git a/src/orc.jl b/src/orc.jl index 8efa0868..bfb24a6a 100644 --- a/src/orc.jl +++ b/src/orc.jl @@ -1,160 +1,431 @@ -export OrcJIT, OrcModule, OrcTargetAddress -export dispose, errormsg, compile!, remove!, add!, - mangle, address, addressin, create_stub!, set_stub!, - register!, unregister!, callback! +export LLJITBuilder, LLJIT, ExecutionSession, JITDylib, + ThreadSafeModule, ThreadSafeContext, OrcTargetAddress +export TargetMachineBuilder, targetmachinebuilder!, linkinglayercreator! +export mangle, lookup, intern +export ObjectLinkingLayer, register! -@checked struct OrcJIT - ref::API.LLVMOrcJITStackRef +include("executionengine/utils.jl") + +@checked struct TargetMachineBuilder + ref::API.LLVMOrcJITTargetMachineBuilderRef end +Base.unsafe_convert(::Type{API.LLVMOrcJITTargetMachineBuilderRef}, + tmb::TargetMachineBuilder) = tmb.ref -Base.unsafe_convert(::Type{API.LLVMOrcJITStackRef}, orc::OrcJIT) = orc.ref -Base.unsafe_convert(::Type{Ptr{Cvoid}}, orc::OrcJIT) = Base.unsafe_convert(Ptr{Cvoid}, orc.ref) -OrcJIT(ref::Ptr{Cvoid}) = OrcJIT(Base.unsafe_convert(API.LLVMOrcJITStackRef, ref)) +function TargetMachineBuilder() + ref = Ref{API.LLVMOrcJITTargetMachineBuilderRef}() + @check API.LLVMOrcJITTargetMachineBuilderDetectHost(ref) + TargetMachineBuilder(ref[]) +end -""" - OrcJIT(::TargetMachine) +function TargetMachineBuilder(tm::TargetMachine) + tmb = API.LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm) + TargetMachineBuilder(tmb) +end + +function dispose(tmb::TargetMachineBuilder) + API.LLVMOrcDisposeJITTargetMachineBuilder(tmb) +end + +include("executionengine/lljit.jl") + +@checked struct ExecutionSession + ref::API.LLVMOrcExecutionSessionRef +end +Base.unsafe_convert(::Type{API.LLVMOrcExecutionSessionRef}, es::ExecutionSession) = es.ref + +function ExecutionSession(lljit::LLJIT) + es = API.LLVMOrcLLJITGetExecutionSession(lljit) + ExecutionSession(es) +end + +@checked struct ObjectLinkingLayer + ref::API.LLVMOrcObjectLayerRef +end +Base.unsafe_convert(::Type{API.LLVMOrcObjectLayerRef}, oll::ObjectLinkingLayer) = oll.ref + +function ObjectLinkingLayer(es::ExecutionSession) + ref = API.LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(es) + ObjectLinkingLayer(ref) +end -Creates a OrcJIT stack based on the provided target machine. +function dispose(oll::ObjectLinkingLayer) + API.LLVMOrcDisposeObjectLayer(oll) +end + +function register!(oll::ObjectLinkingLayer, listener::JITEventListener) + API.LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(oll, listener) +end + +mutable struct ObjectLinkingLayerCreator + cb +end + +function ollc_callback(ctx::Ptr{Cvoid}, es::API.LLVMOrcExecutionSessionRef, triple::Ptr{Cchar}) + es = ExecutionSession(es) + triple = Base.unsafe_string(triple) + + ollc = Base.unsafe_pointer_to_objref(ctx)::ObjectLinkingLayerCreator + oll = ollc.cb(es, triple)::ObjectLinkingLayer + return oll.ref +end + +""" + linkinglayercreator!(builder::LLJITBuilder, creator::ObjectLinkingLayerCreator) !!! warning - Takes ownership of the provided target machine. + The creator object needs to be rooted by the caller for the lifetime of the + builder argument. """ -function OrcJIT(tm::TargetMachine) - OrcJIT(API.LLVMOrcCreateInstance(tm)) +function linkinglayercreator!(builder::LLJITBuilder, creator::ObjectLinkingLayerCreator) + cb = @cfunction(ollc_callback, + API.LLVMOrcObjectLayerRef, + (Ptr{Cvoid}, API.LLVMOrcExecutionSessionRef, Ptr{Cchar})) + linkinglayercreator!(builder, cb, Base.pointer_from_objref(creator)) end -function dispose(orc::OrcJIT) - API.LLVMOrcDisposeInstance(orc) +include("executionengine/ts_module.jl") + +@checked struct LLVMSymbol + ref::API.LLVMOrcSymbolStringPoolEntryRef end +Base.unsafe_convert(::Type{API.LLVMOrcSymbolStringPoolEntryRef}, sym::LLVMSymbol) = sym.ref +Base.convert(::Type{API.LLVMOrcSymbolStringPoolEntryRef}, sym::LLVMSymbol) = sym.ref -function OrcJIT(f::Core.Function, tm::TargetMachine) - orc = OrcJIT(tm) - try - f(orc) - finally - dispose(orc) - end +function Base.cconvert(::Type{Cstring}, sym::LLVMSymbol) + return API.LLVMOrcSymbolStringPoolEntryStr(sym) +end + +function Base.string(sym::LLVMSymbol) + cstr = API.LLVMOrcSymbolStringPoolEntryStr(sym) + Base.unsafe_string(cstr) +end + +function intern(es::ExecutionSession, string) + entry = API.LLVMOrcExecutionSessionIntern(es, string) + LLVMSymbol(entry) +end + +function release(sym::LLVMSymbol) + API.LLVMOrcReleaseSymbolStringPoolEntry(sym) +end + +function retain(sym::LLVMSymbol) + API.LLVMOrcRetainSymbolStringPoolEntry(sym) end -function errormsg(orc::OrcJIT) - # The error message is owned by `orc`, and will - # be disposed along-side the OrcJIT. - unsafe_string(API.LLVMOrcGetErrorMsg(orc)) +# ORC always uses linker-mangled symbols internally (including for lookups, responsibility object maps, etc). +# IR uses non-linker-mangled names. +# If you're synthesizing IR from a requested-symbols map you'll need to demangle the name. +# Unfortunately we don't have a generic utility for that yet, but on MacOS it just means +# dropping the leading '_' if there is one, or prepending a \01 prefix (see https://llvm.org/docs/LangRef.html#identifiers) + +function mangle(lljit::LLJIT, name) + entry = API.LLVMOrcLLJITMangleAndIntern(lljit, name) + return LLVMSymbol(entry) end -struct OrcModule - handle::API.LLVMOrcModuleHandle +@checked struct JITDylib + ref::API.LLVMOrcJITDylibRef end -Base.convert(::Type{API.LLVMOrcModuleHandle}, mod::OrcModule) = mod.handle +Base.unsafe_convert(::Type{API.LLVMOrcJITDylibRef}, jd::JITDylib) = jd.ref """ - resolver(name, ctx) + JITDylib(lljit::LLJIT) -Lookup the symbol `name`. Iff `ctx` is passed to this function it should be a -pointer to the OrcJIT we are compiling for. +Get the main JITDylib """ -function resolver(name, ctx) - name = unsafe_string(name) - ## Step 0: Should have already resolved it iff it was in the - ## same module - ## Step 1: See if it's something known to the execution engine - ptr = C_NULL - if ctx != C_NULL - orc = OrcJIT(ctx) - ptr = pointer(address(orc, name)) - end +function JITDylib(lljit::LLJIT) + ref = API.LLVMOrcLLJITGetMainJITDylib(lljit) + JITDylib(ref) +end - ## Step 2: Search the program symbols - if ptr == C_NULL - # - # SearchForAddressOfSymbol expects an unmangled 'C' symbol name. - # Iff we are on Darwin, strip the leading '_' off. - @static if Sys.isapple() - if name[1] == '_' - name = name[2:end] - end - end - ptr = LLVM.find_symbol(name) - end - ## Step 4: Lookup in libatomic - # TODO: Do we need to do this? +""" + JITDylib(es::ExecutionSession, name; bare=false) - if ptr == C_NULL - error("OrcJIT: Symbol `$name` lookup failed. Aborting!") +Adds a new JITDylib to the ExecutionSession. The name must be unique and +the `bare=true` no standard platform symbols are made available. +""" +function JITDylib(es::ExecutionSession, name; bare=false) + if bare + ref = API.LLVMOrcExecutionSessionCreateBareJITDylib(es, name) + else + ref = Ref{API.LLVMOrcJITDylibRef}() + @check API.LLVMOrcExecutionSessionCreateJITDylib(es, ref, name) + ref = ref[] end + JITDylib(ref) +end +if version() >= v"13" +Base.string(jd::JITDylib) = unsafe_message(API.LLVMExtraDumpJitDylibToString(jd)) - return UInt64(reinterpret(UInt, ptr)) +function Base.show(io::IO, jd::JITDylib) + output = string(jd) + print(io, output) +end end +@checked struct DefinitionGenerator + ref::API.LLVMOrcDefinitionGeneratorRef +end +Base.unsafe_convert(::Type{API.LLVMOrcDefinitionGeneratorRef}, dg::DefinitionGenerator) = dg.ref -function compile!(orc::OrcJIT, mod::Module, resolver = @cfunction(resolver, UInt64, (Cstring, Ptr{Cvoid})), resolver_ctx = orc; lazy=false) - r_mod = Ref{API.LLVMOrcModuleHandle}() - if lazy - API.LLVMOrcAddLazilyCompiledIR(orc, r_mod, mod, resolver, resolver_ctx) - else - API.LLVMOrcAddEagerlyCompiledIR(orc, r_mod, mod, resolver, resolver_ctx) +function add!(jd::JITDylib, dg::DefinitionGenerator) + API.LLVMOrcJITDylibAddGenerator(jd, dg) +end + +function CreateDynamicLibrarySearchGeneratorForProcess(prefix) + ref = Ref{API.LLVMOrcDefinitionGeneratorRef}() + @check API.LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(ref, prefix, C_NULL, C_NULL) + DefinitionGenerator(ref[]) +end + +# LLVMOrcCreateCustomCAPIDefinitionGenerator(F, Ctx) + +function lookup_dylib(es::ExecutionSession, name) + ref = API.LLVMOrcExecutionSessionGetJITDylibByName(es, name) + if ref == C_NULL + return nothing end - OrcModule(r_mod[]) + JITDylib(ref) end -function Base.delete!(orc::OrcJIT, mod::OrcModule) - API.LLVMOrcRemoveModule(orc, mod) +function add!(lljit::LLJIT, jd::JITDylib, obj::MemoryBuffer) + @check API.LLVMOrcLLJITAddObjectFile(lljit, jd, obj) + return nothing end -function add!(orc::OrcJIT, obj::MemoryBuffer, resolver = @cfunction(resolver, UInt64, (Cstring, Ptr{Cvoid})), resolver_ctx = orc) - r_mod = Ref{API.LLVMOrcModuleHandle}() - API.LLVMOrcAddObjectFile(orc, r_mod, obj, resolver, resolver_ctx) - return OrcModule(r_mod[]) +# LLVMOrcLLJITAddObjectFileWithRT(J, RT, ObjBuffer) + +function add!(lljit::LLJIT, jd::JITDylib, mod::ThreadSafeModule) + @check API.LLVMOrcLLJITAddLLVMIRModule(lljit, jd, mod) + return nothing end -function mangle(orc::OrcJIT, name) - r_symbol = Ref{Cstring}() - API.LLVMOrcGetMangledSymbol(orc, r_symbol, name) - symbol = unsafe_string(r_symbol[]) - API.LLVMOrcDisposeMangledSymbol(r_symbol[]) - return symbol +# LLVMOrcLLJITAddLLVMIRModuleWithRT(J, JD, TSM) + +function Base.empty!(jd::JITDylib) + API.LLVMOrcJITDylibClear(jd) end struct OrcTargetAddress - ptr::API.LLVMOrcTargetAddress + ptr::API.LLVMOrcJITTargetAddress end -Base.convert(::Type{API.LLVMOrcTargetAddress}, addr::OrcTargetAddress) = addr.ptr +Base.convert(::Type{API.LLVMOrcJITTargetAddress}, addr::OrcTargetAddress) = addr.ptr Base.pointer(addr::OrcTargetAddress) = reinterpret(Ptr{Cvoid}, addr.ptr % UInt) # LLVMOrcTargetAddress is UInt64 even on 32-bit OrcTargetAddress(ptr::Ptr{Cvoid}) = OrcTargetAddress(reinterpret(UInt, ptr)) -function create_stub!(orc::OrcJIT, name, initial) - API.LLVMOrcCreateIndirectStub(orc, name, initial) +""" + lookup(lljit::LLJIT, name) + +Takes an unmangled symbol names and searches for it in the LLJIT. +""" +function lookup(lljit::LLJIT, name) + result = Ref{API.LLVMOrcJITTargetAddress}() + @check API.LLVMOrcLLJITLookup(lljit, result, name) + OrcTargetAddress(result[]) +end + +@checked struct IRTransformLayer + ref::API.LLVMOrcIRTransformLayerRef +end +Base.unsafe_convert(::Type{API.LLVMOrcIRTransformLayerRef}, il::IRTransformLayer) = il.ref + +function IRTransformLayer(lljit::LLJIT) + ref = API.LLVMOrcLLJITGetIRTransformLayer(lljit) + IRTransformLayer(ref) +end + +function set_transform!(il::IRTransformLayer) + API.LLVMOrcIRTransformLayerSetTransform(il) +end + + +@checked struct MaterializationResponsibility + ref::API.LLVMOrcMaterializationResponsibilityRef +end +Base.unsafe_convert(::Type{API.LLVMOrcMaterializationResponsibilityRef}, mr::MaterializationResponsibility) = mr.ref + +function emit(il::IRTransformLayer, mr::MaterializationResponsibility, tsm::ThreadSafeModule) + API.LLVMOrcIRTransformLayerEmit(il, mr, tsm) +end + + +function get_requested_symbols(mr::MaterializationResponsibility) + N = Ref{Csize_t}() + ptr = API.LLVMOrcMaterializationResponsibilityGetRequestedSymbols(mr, N) + syms = map(LLVMSymbol, Base.unsafe_wrap(Array, ptr, N[], own=false)) + API.LLVMOrcDisposeSymbols(ptr) + return syms +end + +abstract type AbstractMaterializationUnit end + +function define(jd::JITDylib, mu::AbstractMaterializationUnit) + API.LLVMOrcJITDylibDefine(jd, mu) +end + +@checked struct MaterializationUnit <: AbstractMaterializationUnit + ref::API.LLVMOrcMaterializationUnitRef +end +Base.unsafe_convert(::Type{API.LLVMOrcMaterializationUnitRef}, mu::MaterializationUnit) = mu.ref + + +mutable struct CustomMaterializationUnit <: AbstractMaterializationUnit + materialize + discard + mu::MaterializationUnit + function CustomMaterializationUnit(materialize, discard) + new(materialize, discard) + end +end +Base.cconvert(::Type{API.LLVMOrcMaterializationUnitRef}, mu::CustomMaterializationUnit) = mu.mu + +const CUSTOM_MU_ROOTS = Base.IdSet{CustomMaterializationUnit}() + +function __materialize(ctx::Ptr{Cvoid}, mr::API.LLVMOrcMaterializationResponsibilityRef) + mu = Base.unsafe_pointer_to_objref(ctx)::CustomMaterializationUnit + try + mu.materialize(MaterializationResponsibility(mr)) + catch err + bt = catch_backtrace() + showerror(stderr, err, bt) + API.LLVMOrcMaterializationResponsibilityFailMaterialization(mr) + end + nothing +end + +function __discard(ctx::Ptr{Cvoid}, jd::API.LLVMOrcJITDylibRef, symbol::API.LLVMOrcSymbolStringPoolEntryRef) + mu = Base.unsafe_pointer_to_objref(ctx)::CustomMaterializationUnit + try + mu.discard(JITDylib(jd), LLVMSymbol(symbol)) + catch err + bt = catch_backtrace() + showerror(stderr, err, bt) + end + nothing +end + +function __destroy(ctx::Ptr{Cvoid}) + mu = Base.unsafe_pointer_to_objref(ctx)::CustomMaterializationUnit + delete!(CUSTOM_MU_ROOTS, mu) + nothing +end + +function CustomMaterializationUnit(name, symbols, materialize, discard, init=C_NULL) + this = CustomMaterializationUnit(materialize, discard) + push!(CUSTOM_MU_ROOTS, this) + + ref = API.LLVMOrcCreateCustomMaterializationUnit( + name, + Base.pointer_from_objref(this), # escaping this, rooted in CUSTOM_MU_ROOTS + symbols, + length(symbols), + init, + @cfunction(__materialize, Cvoid, (Ptr{Cvoid}, API.LLVMOrcMaterializationResponsibilityRef)), + @cfunction(__discard, Cvoid, (Ptr{Cvoid}, API.LLVMOrcJITDylibRef, API.LLVMOrcSymbolStringPoolEntryRef) ), + @cfunction(__destroy, Cvoid, (Ptr{Cvoid},)) + ) + this.mu = MaterializationUnit(ref) + return this +end + +function absolute_symbols(symbols) + ref = API.LLVMOrcAbsoluteSymbols(symbols, length(symbols)) + MaterializationUnit(ref) +end + +@checked struct IndirectStubsManager + ref::API.LLVMOrcIndirectStubsManagerRef +end +Base.unsafe_convert(::Type{API.LLVMOrcIndirectStubsManagerRef}, ism::IndirectStubsManager) = ism.ref + +function LocalIndirectStubsManager(triple) + ref = API.LLVMOrcCreateLocalIndirectStubsManager(triple) + IndirectStubsManager(ref) +end + +function dispose(ism::IndirectStubsManager) + API.LLVMOrcDisposeIndirectStubsManager(ism) +end + +@checked mutable struct LazyCallThroughManager + ref::API.LLVMOrcLazyCallThroughManagerRef end +Base.unsafe_convert(::Type{API.LLVMOrcLazyCallThroughManagerRef}, lcm::LazyCallThroughManager) = lcm.ref -function set_stub!(orc::OrcJIT, name, new) - API.LLVMOrcSetIndirectStubPointer(orc, name, new) +function LocalLazyCallThroughManager(triple, es) + ref = Ref{API.LLVMOrcLazyCallThroughManagerRef}() + @check API.LLVMOrcCreateLocalLazyCallThroughManager(triple, es, C_NULL, ref) + LazyCallThroughManager(ref[]) end -function address(orc::OrcJIT, name) - r_address = Ref{API.LLVMOrcTargetAddress}() - API.LLVMOrcGetSymbolAddress(orc, r_address, name) - OrcTargetAddress(r_address[]) +function dispose(lcm::LazyCallThroughManager) + API.LLVMOrcDisposeLazyCallThroughManager(lcm) end -function addressin(orc::OrcJIT, mod::OrcModule, name) - r_address = Ref{API.LLVMOrcTargetAddress}() - API.LLVMOrcGetSymbolAddressIn(orc, r_address, mod, name) - OrcTargetAddress(r_address[]) +function reexports(lctm::LazyCallThroughManager, ism::IndirectStubsManager, jd::JITDylib, symbols) + ref = API.LLVMOrcLazyReexports(lctm, ism, jd, symbols, length(symbols)) + MaterializationUnit(ref) end -function callback!(orc::OrcJIT, callback, ctx) - r_address = Ref{API.LLVMOrcTargetAddress}() - API.LLVMOrcCreateLazyCompileCallback(orc, r_address, callback, ctx) - return OrcTargetAddress(r_address[]) +#JuliaOJIT +if has_julia_ojit() + +function ExecutionSession(jljit::JuliaOJIT) + es = API.JLJITGetLLVMOrcExecutionSession(jljit) + ExecutionSession(es) end -function register!(orc::OrcJIT, listener::JITEventListener) - API.LLVMOrcRegisterJITEventListener(orc, listener) +function mangle(jljit::JuliaOJIT, name) + entry = API.JLJITMangleAndIntern(jljit, name) + return LLVMSymbol(entry) end -function unregister!(orc::OrcJIT, listener::JITEventListener) - API.LLVMOrcUnregisterJITEventListener(orc, listener) +""" + JITDylib(jljit::JuliaOJIT) + +Get the external JITDylib from the Julia JIT +""" +function JITDylib(jljit::JuliaOJIT) + ref = API.JLJITGetExternalJITDylib(jljit) + JITDylib(ref) +end + +function add!(jljit::JuliaOJIT, jd::JITDylib, obj::MemoryBuffer) + @check API.JLJITAddObjectFile(jljit, jd, obj) + return nothing +end + +function add!(jljit::JuliaOJIT, jd::JITDylib, mod::ThreadSafeModule) + @check API.JLJITAddLLVMIRModule(jljit, jd, mod) + return nothing +end + +function lookup(jljit::JuliaOJIT, name, external_jd=true) + result = Ref{API.LLVMOrcJITTargetAddress}() + @check API.JLJITLookup(jljit, result, name, external_jd) + OrcTargetAddress(result[]) +end + +@checked struct IRCompileLayer + ref::API.LLVMOrcIRCompileLayerRef +end + +Base.unsafe_convert(::Type{API.LLVMOrcIRCompileLayerRef}, il::IRCompileLayer) = il.ref + +function emit(il::IRCompileLayer, mr::MaterializationResponsibility, tsm::ThreadSafeModule) + API.LLVMExtraOrcIRCompileLayerEmit(il, mr, tsm) +end + +function IRCompileLayer(jljit::JuliaOJIT) + ref = API.JLJITGetIRCompileLayer(jljit) + IRCompileLayer(ref) +end + +export JuliaOJIT + end diff --git a/src/orcv2.jl b/src/orcv2.jl deleted file mode 100644 index bfb24a6a..00000000 --- a/src/orcv2.jl +++ /dev/null @@ -1,431 +0,0 @@ -export LLJITBuilder, LLJIT, ExecutionSession, JITDylib, - ThreadSafeModule, ThreadSafeContext, OrcTargetAddress -export TargetMachineBuilder, targetmachinebuilder!, linkinglayercreator! -export mangle, lookup, intern -export ObjectLinkingLayer, register! - -include("executionengine/utils.jl") - -@checked struct TargetMachineBuilder - ref::API.LLVMOrcJITTargetMachineBuilderRef -end -Base.unsafe_convert(::Type{API.LLVMOrcJITTargetMachineBuilderRef}, - tmb::TargetMachineBuilder) = tmb.ref - - -function TargetMachineBuilder() - ref = Ref{API.LLVMOrcJITTargetMachineBuilderRef}() - @check API.LLVMOrcJITTargetMachineBuilderDetectHost(ref) - TargetMachineBuilder(ref[]) -end - -function TargetMachineBuilder(tm::TargetMachine) - tmb = API.LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(tm) - TargetMachineBuilder(tmb) -end - -function dispose(tmb::TargetMachineBuilder) - API.LLVMOrcDisposeJITTargetMachineBuilder(tmb) -end - -include("executionengine/lljit.jl") - -@checked struct ExecutionSession - ref::API.LLVMOrcExecutionSessionRef -end -Base.unsafe_convert(::Type{API.LLVMOrcExecutionSessionRef}, es::ExecutionSession) = es.ref - -function ExecutionSession(lljit::LLJIT) - es = API.LLVMOrcLLJITGetExecutionSession(lljit) - ExecutionSession(es) -end - -@checked struct ObjectLinkingLayer - ref::API.LLVMOrcObjectLayerRef -end -Base.unsafe_convert(::Type{API.LLVMOrcObjectLayerRef}, oll::ObjectLinkingLayer) = oll.ref - -function ObjectLinkingLayer(es::ExecutionSession) - ref = API.LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(es) - ObjectLinkingLayer(ref) -end - -function dispose(oll::ObjectLinkingLayer) - API.LLVMOrcDisposeObjectLayer(oll) -end - -function register!(oll::ObjectLinkingLayer, listener::JITEventListener) - API.LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(oll, listener) -end - -mutable struct ObjectLinkingLayerCreator - cb -end - -function ollc_callback(ctx::Ptr{Cvoid}, es::API.LLVMOrcExecutionSessionRef, triple::Ptr{Cchar}) - es = ExecutionSession(es) - triple = Base.unsafe_string(triple) - - ollc = Base.unsafe_pointer_to_objref(ctx)::ObjectLinkingLayerCreator - oll = ollc.cb(es, triple)::ObjectLinkingLayer - return oll.ref -end - -""" - linkinglayercreator!(builder::LLJITBuilder, creator::ObjectLinkingLayerCreator) - -!!! warning - The creator object needs to be rooted by the caller for the lifetime of the - builder argument. -""" -function linkinglayercreator!(builder::LLJITBuilder, creator::ObjectLinkingLayerCreator) - cb = @cfunction(ollc_callback, - API.LLVMOrcObjectLayerRef, - (Ptr{Cvoid}, API.LLVMOrcExecutionSessionRef, Ptr{Cchar})) - linkinglayercreator!(builder, cb, Base.pointer_from_objref(creator)) -end - -include("executionengine/ts_module.jl") - -@checked struct LLVMSymbol - ref::API.LLVMOrcSymbolStringPoolEntryRef -end -Base.unsafe_convert(::Type{API.LLVMOrcSymbolStringPoolEntryRef}, sym::LLVMSymbol) = sym.ref -Base.convert(::Type{API.LLVMOrcSymbolStringPoolEntryRef}, sym::LLVMSymbol) = sym.ref - -function Base.cconvert(::Type{Cstring}, sym::LLVMSymbol) - return API.LLVMOrcSymbolStringPoolEntryStr(sym) -end - -function Base.string(sym::LLVMSymbol) - cstr = API.LLVMOrcSymbolStringPoolEntryStr(sym) - Base.unsafe_string(cstr) -end - -function intern(es::ExecutionSession, string) - entry = API.LLVMOrcExecutionSessionIntern(es, string) - LLVMSymbol(entry) -end - -function release(sym::LLVMSymbol) - API.LLVMOrcReleaseSymbolStringPoolEntry(sym) -end - -function retain(sym::LLVMSymbol) - API.LLVMOrcRetainSymbolStringPoolEntry(sym) -end - -# ORC always uses linker-mangled symbols internally (including for lookups, responsibility object maps, etc). -# IR uses non-linker-mangled names. -# If you're synthesizing IR from a requested-symbols map you'll need to demangle the name. -# Unfortunately we don't have a generic utility for that yet, but on MacOS it just means -# dropping the leading '_' if there is one, or prepending a \01 prefix (see https://llvm.org/docs/LangRef.html#identifiers) - -function mangle(lljit::LLJIT, name) - entry = API.LLVMOrcLLJITMangleAndIntern(lljit, name) - return LLVMSymbol(entry) -end - -@checked struct JITDylib - ref::API.LLVMOrcJITDylibRef -end -Base.unsafe_convert(::Type{API.LLVMOrcJITDylibRef}, jd::JITDylib) = jd.ref - -""" - JITDylib(lljit::LLJIT) - -Get the main JITDylib -""" -function JITDylib(lljit::LLJIT) - ref = API.LLVMOrcLLJITGetMainJITDylib(lljit) - JITDylib(ref) -end - - -""" - JITDylib(es::ExecutionSession, name; bare=false) - -Adds a new JITDylib to the ExecutionSession. The name must be unique and -the `bare=true` no standard platform symbols are made available. -""" -function JITDylib(es::ExecutionSession, name; bare=false) - if bare - ref = API.LLVMOrcExecutionSessionCreateBareJITDylib(es, name) - else - ref = Ref{API.LLVMOrcJITDylibRef}() - @check API.LLVMOrcExecutionSessionCreateJITDylib(es, ref, name) - ref = ref[] - end - JITDylib(ref) -end -if version() >= v"13" -Base.string(jd::JITDylib) = unsafe_message(API.LLVMExtraDumpJitDylibToString(jd)) - -function Base.show(io::IO, jd::JITDylib) - output = string(jd) - print(io, output) -end -end -@checked struct DefinitionGenerator - ref::API.LLVMOrcDefinitionGeneratorRef -end -Base.unsafe_convert(::Type{API.LLVMOrcDefinitionGeneratorRef}, dg::DefinitionGenerator) = dg.ref - -function add!(jd::JITDylib, dg::DefinitionGenerator) - API.LLVMOrcJITDylibAddGenerator(jd, dg) -end - -function CreateDynamicLibrarySearchGeneratorForProcess(prefix) - ref = Ref{API.LLVMOrcDefinitionGeneratorRef}() - @check API.LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(ref, prefix, C_NULL, C_NULL) - DefinitionGenerator(ref[]) -end - -# LLVMOrcCreateCustomCAPIDefinitionGenerator(F, Ctx) - -function lookup_dylib(es::ExecutionSession, name) - ref = API.LLVMOrcExecutionSessionGetJITDylibByName(es, name) - if ref == C_NULL - return nothing - end - JITDylib(ref) -end - -function add!(lljit::LLJIT, jd::JITDylib, obj::MemoryBuffer) - @check API.LLVMOrcLLJITAddObjectFile(lljit, jd, obj) - return nothing -end - -# LLVMOrcLLJITAddObjectFileWithRT(J, RT, ObjBuffer) - -function add!(lljit::LLJIT, jd::JITDylib, mod::ThreadSafeModule) - @check API.LLVMOrcLLJITAddLLVMIRModule(lljit, jd, mod) - return nothing -end - -# LLVMOrcLLJITAddLLVMIRModuleWithRT(J, JD, TSM) - -function Base.empty!(jd::JITDylib) - API.LLVMOrcJITDylibClear(jd) -end - -struct OrcTargetAddress - ptr::API.LLVMOrcJITTargetAddress -end -Base.convert(::Type{API.LLVMOrcJITTargetAddress}, addr::OrcTargetAddress) = addr.ptr - -Base.pointer(addr::OrcTargetAddress) = reinterpret(Ptr{Cvoid}, addr.ptr % UInt) # LLVMOrcTargetAddress is UInt64 even on 32-bit - -OrcTargetAddress(ptr::Ptr{Cvoid}) = OrcTargetAddress(reinterpret(UInt, ptr)) - -""" - lookup(lljit::LLJIT, name) - -Takes an unmangled symbol names and searches for it in the LLJIT. -""" -function lookup(lljit::LLJIT, name) - result = Ref{API.LLVMOrcJITTargetAddress}() - @check API.LLVMOrcLLJITLookup(lljit, result, name) - OrcTargetAddress(result[]) -end - -@checked struct IRTransformLayer - ref::API.LLVMOrcIRTransformLayerRef -end -Base.unsafe_convert(::Type{API.LLVMOrcIRTransformLayerRef}, il::IRTransformLayer) = il.ref - -function IRTransformLayer(lljit::LLJIT) - ref = API.LLVMOrcLLJITGetIRTransformLayer(lljit) - IRTransformLayer(ref) -end - -function set_transform!(il::IRTransformLayer) - API.LLVMOrcIRTransformLayerSetTransform(il) -end - - -@checked struct MaterializationResponsibility - ref::API.LLVMOrcMaterializationResponsibilityRef -end -Base.unsafe_convert(::Type{API.LLVMOrcMaterializationResponsibilityRef}, mr::MaterializationResponsibility) = mr.ref - -function emit(il::IRTransformLayer, mr::MaterializationResponsibility, tsm::ThreadSafeModule) - API.LLVMOrcIRTransformLayerEmit(il, mr, tsm) -end - - -function get_requested_symbols(mr::MaterializationResponsibility) - N = Ref{Csize_t}() - ptr = API.LLVMOrcMaterializationResponsibilityGetRequestedSymbols(mr, N) - syms = map(LLVMSymbol, Base.unsafe_wrap(Array, ptr, N[], own=false)) - API.LLVMOrcDisposeSymbols(ptr) - return syms -end - -abstract type AbstractMaterializationUnit end - -function define(jd::JITDylib, mu::AbstractMaterializationUnit) - API.LLVMOrcJITDylibDefine(jd, mu) -end - -@checked struct MaterializationUnit <: AbstractMaterializationUnit - ref::API.LLVMOrcMaterializationUnitRef -end -Base.unsafe_convert(::Type{API.LLVMOrcMaterializationUnitRef}, mu::MaterializationUnit) = mu.ref - - -mutable struct CustomMaterializationUnit <: AbstractMaterializationUnit - materialize - discard - mu::MaterializationUnit - function CustomMaterializationUnit(materialize, discard) - new(materialize, discard) - end -end -Base.cconvert(::Type{API.LLVMOrcMaterializationUnitRef}, mu::CustomMaterializationUnit) = mu.mu - -const CUSTOM_MU_ROOTS = Base.IdSet{CustomMaterializationUnit}() - -function __materialize(ctx::Ptr{Cvoid}, mr::API.LLVMOrcMaterializationResponsibilityRef) - mu = Base.unsafe_pointer_to_objref(ctx)::CustomMaterializationUnit - try - mu.materialize(MaterializationResponsibility(mr)) - catch err - bt = catch_backtrace() - showerror(stderr, err, bt) - API.LLVMOrcMaterializationResponsibilityFailMaterialization(mr) - end - nothing -end - -function __discard(ctx::Ptr{Cvoid}, jd::API.LLVMOrcJITDylibRef, symbol::API.LLVMOrcSymbolStringPoolEntryRef) - mu = Base.unsafe_pointer_to_objref(ctx)::CustomMaterializationUnit - try - mu.discard(JITDylib(jd), LLVMSymbol(symbol)) - catch err - bt = catch_backtrace() - showerror(stderr, err, bt) - end - nothing -end - -function __destroy(ctx::Ptr{Cvoid}) - mu = Base.unsafe_pointer_to_objref(ctx)::CustomMaterializationUnit - delete!(CUSTOM_MU_ROOTS, mu) - nothing -end - -function CustomMaterializationUnit(name, symbols, materialize, discard, init=C_NULL) - this = CustomMaterializationUnit(materialize, discard) - push!(CUSTOM_MU_ROOTS, this) - - ref = API.LLVMOrcCreateCustomMaterializationUnit( - name, - Base.pointer_from_objref(this), # escaping this, rooted in CUSTOM_MU_ROOTS - symbols, - length(symbols), - init, - @cfunction(__materialize, Cvoid, (Ptr{Cvoid}, API.LLVMOrcMaterializationResponsibilityRef)), - @cfunction(__discard, Cvoid, (Ptr{Cvoid}, API.LLVMOrcJITDylibRef, API.LLVMOrcSymbolStringPoolEntryRef) ), - @cfunction(__destroy, Cvoid, (Ptr{Cvoid},)) - ) - this.mu = MaterializationUnit(ref) - return this -end - -function absolute_symbols(symbols) - ref = API.LLVMOrcAbsoluteSymbols(symbols, length(symbols)) - MaterializationUnit(ref) -end - -@checked struct IndirectStubsManager - ref::API.LLVMOrcIndirectStubsManagerRef -end -Base.unsafe_convert(::Type{API.LLVMOrcIndirectStubsManagerRef}, ism::IndirectStubsManager) = ism.ref - -function LocalIndirectStubsManager(triple) - ref = API.LLVMOrcCreateLocalIndirectStubsManager(triple) - IndirectStubsManager(ref) -end - -function dispose(ism::IndirectStubsManager) - API.LLVMOrcDisposeIndirectStubsManager(ism) -end - -@checked mutable struct LazyCallThroughManager - ref::API.LLVMOrcLazyCallThroughManagerRef -end -Base.unsafe_convert(::Type{API.LLVMOrcLazyCallThroughManagerRef}, lcm::LazyCallThroughManager) = lcm.ref - -function LocalLazyCallThroughManager(triple, es) - ref = Ref{API.LLVMOrcLazyCallThroughManagerRef}() - @check API.LLVMOrcCreateLocalLazyCallThroughManager(triple, es, C_NULL, ref) - LazyCallThroughManager(ref[]) -end - -function dispose(lcm::LazyCallThroughManager) - API.LLVMOrcDisposeLazyCallThroughManager(lcm) -end - -function reexports(lctm::LazyCallThroughManager, ism::IndirectStubsManager, jd::JITDylib, symbols) - ref = API.LLVMOrcLazyReexports(lctm, ism, jd, symbols, length(symbols)) - MaterializationUnit(ref) -end - -#JuliaOJIT -if has_julia_ojit() - -function ExecutionSession(jljit::JuliaOJIT) - es = API.JLJITGetLLVMOrcExecutionSession(jljit) - ExecutionSession(es) -end - -function mangle(jljit::JuliaOJIT, name) - entry = API.JLJITMangleAndIntern(jljit, name) - return LLVMSymbol(entry) -end - -""" - JITDylib(jljit::JuliaOJIT) - -Get the external JITDylib from the Julia JIT -""" -function JITDylib(jljit::JuliaOJIT) - ref = API.JLJITGetExternalJITDylib(jljit) - JITDylib(ref) -end - -function add!(jljit::JuliaOJIT, jd::JITDylib, obj::MemoryBuffer) - @check API.JLJITAddObjectFile(jljit, jd, obj) - return nothing -end - -function add!(jljit::JuliaOJIT, jd::JITDylib, mod::ThreadSafeModule) - @check API.JLJITAddLLVMIRModule(jljit, jd, mod) - return nothing -end - -function lookup(jljit::JuliaOJIT, name, external_jd=true) - result = Ref{API.LLVMOrcJITTargetAddress}() - @check API.JLJITLookup(jljit, result, name, external_jd) - OrcTargetAddress(result[]) -end - -@checked struct IRCompileLayer - ref::API.LLVMOrcIRCompileLayerRef -end - -Base.unsafe_convert(::Type{API.LLVMOrcIRCompileLayerRef}, il::IRCompileLayer) = il.ref - -function emit(il::IRCompileLayer, mr::MaterializationResponsibility, tsm::ThreadSafeModule) - API.LLVMExtraOrcIRCompileLayerEmit(il, mr, tsm) -end - -function IRCompileLayer(jljit::JuliaOJIT) - ref = API.JLJITGetIRCompileLayer(jljit) - IRCompileLayer(ref) -end - -export JuliaOJIT - -end diff --git a/src/state.jl b/src/state.jl index 928640e3..498cf2f5 100644 --- a/src/state.jl +++ b/src/state.jl @@ -44,8 +44,6 @@ end ## thread-safe contexts -if LLVM.has_orc_v2() - export ts_context, activate, deactivate, ts_context! _has_ts_context() = haskey(task_local_storage(), :LLVMTSContext) && @@ -80,5 +78,3 @@ function ts_context!(f, ts_ctx::ThreadSafeContext) deactivate(ts_ctx) end end - -end diff --git a/test/core_tests.jl b/test/core_tests.jl index 46e8c126..2203e37a 100644 --- a/test/core_tests.jl +++ b/test/core_tests.jl @@ -33,8 +33,6 @@ Context() do ctx end @test supports_typed_pointers(ctx) isa Bool if LLVM.version() > v"17" @test supports_typed_pointers(ctx) == false - elseif LLVM.version() < v"13" - @test supports_typed_pointers(ctx) == true end end @@ -345,11 +343,9 @@ end @test val isa LLVM.Constant end - if LLVM.version() >= v"12" - let val = PoisonValue(typ) - @test ispoison(val) - @test val isa LLVM.Constant - end + let val = PoisonValue(typ) + @test ispoison(val) + @test val isa LLVM.Constant end end @@ -1250,17 +1246,15 @@ end @test length(attrs) == 0 end - if LLVM.version() >= v"12" - let attr = TypeAttribute("sret", LLVM.Int32Type()) - @test kind(attr) != 0 - @test value(attr) == LLVM.Int32Type() + let attr = TypeAttribute("sret", LLVM.Int32Type()) + @test kind(attr) != 0 + @test value(attr) == LLVM.Int32Type() - push!(attrs, attr) - @test collect(attrs) == [attr] + push!(attrs, attr) + @test collect(attrs) == [attr] - delete!(attrs, attr) - @test length(attrs) == 0 - end + delete!(attrs, attr) + @test length(attrs) == 0 end end diff --git a/test/debuginfo_tests.jl b/test/debuginfo_tests.jl index b976804c..efa5e512 100644 --- a/test/debuginfo_tests.jl +++ b/test/debuginfo_tests.jl @@ -47,16 +47,15 @@ DEBUG_METADATA_VERSION() foo = functions(mod)["foo"] - if LLVM.version() >= v"8.0" - sp = LLVM.get_subprogram(foo) - @test sp !== nothing - @test LLVM.line(sp) == 1 - - bar = functions(mod)["bar"] - @test LLVM.get_subprogram(bar) === nothing - LLVM.set_subprogram!(bar, sp) - @test LLVM.get_subprogram(bar) == sp - end + let sp = LLVM.get_subprogram(foo) + @test sp !== nothing + @test LLVM.line(sp) == 1 + + bar = functions(mod)["bar"] + @test LLVM.get_subprogram(bar) === nothing + LLVM.set_subprogram!(bar, sp) + @test LLVM.get_subprogram(bar) == sp + end bb = entry(foo) diff --git a/test/jljit_tests.jl b/test/jljit_tests.jl index f2d5c993..92c43cda 100644 --- a/test/jljit_tests.jl +++ b/test/jljit_tests.jl @@ -181,9 +181,7 @@ end data[] = -1 @test ccall(pointer(addr), Int32, ()) == -1 - if LLVM.version() < v"13" - LLVM.release(name) - end + LLVM.release(name) end empty!(jd) @test_throws LLVMException lookup(jljit, sym) diff --git a/test/orc_tests.jl b/test/orc_tests.jl index a277251d..f38087fd 100644 --- a/test/orc_tests.jl +++ b/test/orc_tests.jl @@ -1,288 +1,211 @@ -@static if LLVM.has_orc_v1() && !LLVM.is_asserts() # XXX: dangling references abort @testitem "orc" begin -let tm = JITTargetMachine() - let orc = OrcJIT(tm) - dispose(orc) - end - - OrcJIT(tm) do orc - end +let lljit=LLJIT() + dispose(lljit) end -@testset "Undefined Symbol" begin - tm = JITTargetMachine() - @dispose orc=OrcJIT(tm) ctx=Context() begin - mod = LLVM.Module("jit") - T_Int32 = LLVM.Int32Type() - ft = LLVM.FunctionType(T_Int32, [T_Int32, T_Int32]) - fn = LLVM.Function(mod, "mysum", ft) - linkage!(fn, LLVM.API.LLVMExternalLinkage) - - fname = mangle(orc, "wrapper") - wrapper = LLVM.Function(mod, fname, ft) - # generate IR - @dispose builder=IRBuilder() begin - entry = BasicBlock(wrapper, "entry") - position!(builder, entry) - - tmp = call!(builder, ft, fn, [parameters(wrapper)...]) - ret!(builder, tmp) - end - - triple!(mod, triple(tm)) - @dispose pm=ModulePassManager() begin - add_library_info!(pm, triple(mod)) - add_transform_info!(pm, tm) - run!(pm, mod) - end - verify(mod) - - orc_mod = compile!(orc, mod) - @test_throws ErrorException address(orc, fname) == C_NULL - - delete!(orc, orc_mod) - end +LLJIT() do lljit end -@testset "Custom Resolver" begin - tm = JITTargetMachine() - @dispose orc=OrcJIT(tm) ctx=Context() begin - known_functions = Dict{String, OrcTargetAddress}() - fnames = Dict{String, Int}() - function lookup(name, ctx) - name = unsafe_string(name) - try - if !haskey(fnames, name) - fnames[name] = 0 - end - fnames[name] += 1 +let ctx = ThreadSafeContext() + dispose(ctx) +end - return known_functions[name].ptr - catch ex - @error "Exception during lookup" name exception=(ex, catch_backtrace()) - error("OrcJIT: Could not find symbol") - end - end +ThreadSafeContext() do ctx +end - mod = LLVM.Module("jit") - T_Int32 = LLVM.Int32Type() - ft = LLVM.FunctionType(T_Int32, [T_Int32, T_Int32]) - fn = LLVM.Function(mod, "mysum", ft) - linkage!(fn, LLVM.API.LLVMExternalLinkage) - - fname = mangle(orc, "wrapper") - wrapper = LLVM.Function(mod, fname, ft) - # generate IR - @dispose builder=IRBuilder() begin - entry = BasicBlock(wrapper, "entry") - position!(builder, entry) - - tmp = call!(builder, ft, fn, [parameters(wrapper)...]) - ret!(builder, tmp) +@testset "ThreadSafeModule" begin + @dispose ts_ctx=ThreadSafeContext() begin + ts_mod = ThreadSafeModule("jit") + @test_throws LLVMException ts_mod() do mod + error("Error") end - - triple!(mod, triple(tm)) - @dispose pm=ModulePassManager() begin - add_library_info!(pm, triple(mod)) - add_transform_info!(pm, tm) - run!(pm, mod) + run = Ref{Bool}(false) + ts_mod() do mod + run[] = true end - verify(mod) + @test run[] + end +end - mysum_name = mangle(orc, "mysum") - known_functions[mysum_name] = OrcTargetAddress(@cfunction(+, Int32, (Int32, Int32))) +@testset "JITDylib" begin + @dispose ts_ctx=ThreadSafeContext() lljit=LLJIT() begin + es = ExecutionSession(lljit) - f_lookup = @cfunction($lookup, UInt64, (Cstring, Ptr{Cvoid})) - GC.@preserve f_lookup begin - orc_mod = compile!(orc, mod, f_lookup, C_NULL, lazy=true) # will capture f_lookup + @test LLVM.lookup_dylib(es, "my.so") === nothing - addr = address(orc, fname) - @test errormsg(orc) == "" - addr2 = addressin(orc, orc_mod, fname) + jd = JITDylib(es, "my.so") + jd_bare = JITDylib(es, "mybare.so", bare=true) - @test addr == addr2 - @test addr.ptr != 0 - @test !haskey(fnames, mysum_name) + @test LLVM.lookup_dylib(es, "my.so") === jd - r = ccall(pointer(addr), Int32, (Int32, Int32), 1, 2) # uses f_lookup - @test r == 3 - end + jd_main = JITDylib(lljit) - @test haskey(fnames, mysum_name) - @test fnames[mysum_name] == 1 + prefix = LLVM.get_prefix(lljit) + dg = LLVM.CreateDynamicLibrarySearchGeneratorForProcess(prefix) + add!(jd_main, dg) - empty!(fnames) - delete!(orc, orc_mod) + addr = lookup(lljit, "jl_apply_generic") + @test pointer(addr) != C_NULL end end -@testset "Default Resolver + Stub" begin - tm = JITTargetMachine() - @dispose orc=OrcJIT(tm) ctx=Context() begin - mod = LLVM.Module("jit") - T_Int32 = LLVM.Int32Type() - ft = LLVM.FunctionType(T_Int32, [T_Int32, T_Int32]) - fn = LLVM.Function(mod, "mysum", ft) - linkage!(fn, LLVM.API.LLVMExternalLinkage) - - fname = mangle(orc, "wrapper") - wrapper = LLVM.Function(mod, fname, ft) - # generate IR - @dispose builder=IRBuilder() begin - entry = BasicBlock(wrapper, "entry") - position!(builder, entry) - - tmp = call!(builder, ft, fn, [parameters(wrapper)...]) - ret!(builder, tmp) - end - - triple!(mod, triple(tm)) - @dispose pm=ModulePassManager() begin - add_library_info!(pm, triple(mod)) - add_transform_info!(pm, tm) - run!(pm, mod) - end - verify(mod) +@testset "Undefined Symbol" begin + @dispose lljit=LLJIT() begin + @test_throws LLVMException lookup(lljit, string(gensym())) + end - create_stub!(orc, mangle(orc, "mysum"), OrcTargetAddress(@cfunction(+, Int32, (Int32, Int32)))) + @dispose ts_ctx=ThreadSafeContext() lljit=LLJIT(;tm=JITTargetMachine()) begin + jd = JITDylib(lljit) - orc_mod = compile!(orc, mod) + ts_mod = ThreadSafeModule("jit") - addr = address(orc, fname) - @test errormsg(orc) == "" + # build the module + fname = "wrapper" + ts_mod() do mod + T_Int32 = LLVM.Int32Type() + ft = LLVM.FunctionType(T_Int32, [T_Int32, T_Int32]) + fn = LLVM.Function(mod, "mysum", ft) + linkage!(fn, LLVM.API.LLVMExternalLinkage) - r = ccall(pointer(addr), Int32, (Int32, Int32), 1, 2) - @test r == 3 + wrapper = LLVM.Function(mod, fname, ft) + # generate IR + @dispose builder=IRBuilder() begin + entry = BasicBlock(wrapper, "entry") + position!(builder, entry) - delete!(orc, orc_mod) - end -end + tmp = call!(builder, ft, fn, [parameters(wrapper)...]) + ret!(builder, tmp) + end -@testset "Default Resolver + Global Symbol" begin - tm = JITTargetMachine() - @dispose orc=OrcJIT(tm) ctx=Context() begin - mod = LLVM.Module("jit") - T_Int32 = LLVM.Int32Type() - ft = LLVM.FunctionType(T_Int32, [T_Int32, T_Int32]) - mysum = mangle(orc, "mysum") - fn = LLVM.Function(mod, mysum, ft) - linkage!(fn, LLVM.API.LLVMExternalLinkage) - - fname = mangle(orc, "wrapper") - wrapper = LLVM.Function(mod, fname, ft) - # generate IR - @dispose builder=IRBuilder() begin - entry = BasicBlock(wrapper, "entry") - position!(builder, entry) - - tmp = call!(builder, ft, fn, [parameters(wrapper)...]) - ret!(builder, tmp) + # TODO: Get TM from lljit? + tm = JITTargetMachine() + triple!(mod, triple(lljit)) + @dispose pm=ModulePassManager() begin + add_library_info!(pm, triple(mod)) + add_transform_info!(pm, tm) + run!(pm, mod) + end + verify(mod) end - triple!(mod, triple(tm)) - @dispose pm=ModulePassManager() begin - add_library_info!(pm, triple(mod)) - add_transform_info!(pm, tm) - run!(pm, mod) + add!(lljit, jd, ts_mod) + @test_throws LLVMException redirect_stderr(devnull) do + # XXX: this reports an unhandled JIT session error; + # can we handle it instead? + lookup(lljit, fname) end - verify(mod) - - # Should do pretty much the same as `@ccallable` - LLVM.add_symbol(mysum, @cfunction(+, Int32, (Int32, Int32))) - ptr = LLVM.find_symbol(mysum) - @test ptr !== C_NULL - @test ccall(ptr, Int32, (Int32, Int32), 1, 2) == 3 - - orc_mod = compile!(orc, mod, lazy=true) - - addr = address(orc, fname) - @test errormsg(orc) == "" - - r = ccall(pointer(addr), Int32, (Int32, Int32), 1, 2) - @test r == 3 - - delete!(orc, orc_mod) end end @testset "Loading ObjectFile" begin - tm = JITTargetMachine() - @dispose orc=OrcJIT(tm) ctx=Context() begin - sym = mangle(orc, "SomeFunction") - - mod = LLVM.Module("jit") - ft = LLVM.FunctionType(LLVM.VoidType()) - fn = LLVM.Function(mod, sym, ft) - - @dispose builder=IRBuilder() begin - entry = BasicBlock(fn, "entry") - position!(builder, entry) - ret!(builder) + @dispose lljit=LLJIT(;tm=JITTargetMachine()) begin + jd = JITDylib(lljit) + + sym = "SomeFunction" + obj = @dispose ctx=Context() begin + mod = LLVM.Module("jit") + ft = LLVM.FunctionType(LLVM.VoidType()) + fn = LLVM.Function(mod, sym, ft) + + @dispose builder=IRBuilder() begin + entry = BasicBlock(fn, "entry") + position!(builder, entry) + ret!(builder) + end + verify(mod) + + tm = JITTargetMachine() + emit(tm, mod, LLVM.API.LLVMObjectFile) end - verify(mod) + add!(lljit, jd, MemoryBuffer(obj)) - obj = emit(tm, mod, LLVM.API.LLVMObjectFile) + addr = lookup(lljit, sym) - orc_m = add!(orc, MemoryBuffer(obj)) - addr = address(orc, sym) + @test pointer(addr) != C_NULL - @test addr.ptr != 0 - delete!(orc, orc_m) + empty!(jd) + @test_throws LLVMException lookup(lljit, sym) end -end -@testset "Stubs" begin - tm = JITTargetMachine() - @dispose orc=OrcJIT(tm) ctx=Context() begin - toggle = Ref{Bool}(false) - on() = (toggle[] = true; nothing) - off() = (toggle[] = false; nothing) + @dispose lljit=LLJIT(;tm=JITTargetMachine()) begin + jd = JITDylib(lljit) - # Note that `CFunction` objects can be GC'd (???) - # and we capture them below. - func_on = @cfunction($on, Cvoid, ()) - GC.@preserve func_on begin - ptr = Base.unsafe_convert(Ptr{Cvoid}, func_on) + sym = "SomeFunction" + obj = @dispose ctx=Context() begin + mod = LLVM.Module("jit") + ft = LLVM.FunctionType(LLVM.Int32Type()) + fn = LLVM.Function(mod, sym, ft) - create_stub!(orc, "mystub", OrcTargetAddress(ptr)) - addr = address(orc, "mystub") + gv = LLVM.GlobalVariable(mod, LLVM.Int32Type(), "gv") + LLVM.extinit!(gv, true) - @test addr.ptr != 0 - @test toggle[] == false + @dispose builder=IRBuilder() begin + entry = BasicBlock(fn, "entry") + position!(builder, entry) + val = load!(builder, LLVM.Int32Type(), gv) + ret!(builder, val) + end + verify(mod) - ccall(pointer(addr), Cvoid, ()) - @test toggle[] == true + tm = JITTargetMachine() + emit(tm, mod, LLVM.API.LLVMObjectFile) end - func_off = @cfunction($off, Cvoid, ()) - GC.@preserve func_off begin - ptr = Base.unsafe_convert(Ptr{Cvoid}, func_off) + data = Ref{Int32}(42) + GC.@preserve data begin + address = LLVM.API.LLVMOrcJITTargetAddress( + reinterpret(UInt, Base.unsafe_convert(Ptr{Int32}, data))) + flags = LLVM.API.LLVMJITSymbolFlags( + LLVM.API.LLVMJITSymbolGenericFlagsExported, 0) + name = mangle(lljit, "gv") + symbol = LLVM.API.LLVMJITEvaluatedSymbol(address, flags) + gv = if LLVM.version() >= v"15" + LLVM.API.LLVMOrcCSymbolMapPair(name, symbol) + else + LLVM.API.LLVMJITCSymbolMapPair(name, symbol) + end + + mu = LLVM.absolute_symbols(Ref(gv)) + LLVM.define(jd, mu) - set_stub!(orc, "mystub", OrcTargetAddress(ptr)) + add!(lljit, jd, MemoryBuffer(obj)) - @test addr == address(orc, "mystub") - @test toggle[] == true + addr = lookup(lljit, sym) + @test pointer(addr) != C_NULL - ccall(pointer(addr), Cvoid, ()) - @test toggle[] == false + @test ccall(pointer(addr), Int32, ()) == 42 + data[] = -1 + @test ccall(pointer(addr), Int32, ()) == -1 + + LLVM.release(name) end + empty!(jd) + @test_throws LLVMException lookup(lljit, sym) end end -@testset "callback!" begin - tm = JITTargetMachine() - @dispose orc=OrcJIT(tm) begin - triggered = Ref{Bool}(false) +@testset "ObjectLinkingLayer" begin + called_oll = Ref{Int}(0) + + ollc = LLVM.ObjectLinkingLayerCreator() do es, triple + oll = ObjectLinkingLayer(es) + register!(oll, GDBRegistrationListener()) + called_oll[] += 1 + return oll + end - # Setup the lazy callback for creating a module - function callback(orc_ref::LLVM.API.LLVMOrcJITStackRef, callback_ctx::Ptr{Cvoid}) - orc = OrcJIT(orc_ref) - sym = mangle(orc, "SomeFunction") + GC.@preserve ollc begin + builder = LLJITBuilder() + linkinglayercreator!(builder, ollc) + @dispose ts_ctx=ThreadSafeContext() lljit=LLJIT(builder) begin + jd = JITDylib(lljit) - # 1. IRGen & Optimize the module - orc_mod = @dispose ctx=Context() begin - mod = LLVM.Module("jit") + ts_mod = ThreadSafeModule("jit") + sym = "SomeFunctionOLL" + + # build the module + ts_mod() do mod ft = LLVM.FunctionType(LLVM.VoidType()) fn = LLVM.Function(mod, sym, ft) @@ -292,41 +215,88 @@ end ret!(builder) end verify(mod) + end - triple!(mod, triple(tm)) - @dispose pm=ModulePassManager() begin - add_library_info!(pm, triple(mod)) - add_transform_info!(pm, tm) - run!(pm, mod) - end - verify(mod) + add!(lljit, jd, ts_mod) + addr = lookup(lljit, sym) + @test pointer(addr) != C_NULL + end + end + @test called_oll[] >= 1 +end - # 2. Add the IR module to the JIT - compile!(orc, mod) - end +@testset "Lazy" begin + @dispose ts_ctx=ThreadSafeContext() lljit=LLJIT() begin + jd = JITDylib(lljit) + es = ExecutionSession(lljit) + + lctm = LLVM.LocalLazyCallThroughManager(triple(lljit), es) + ism = LLVM.LocalIndirectStubsManager(triple(lljit)) + try + # 1. define entry symbol + entry_sym = "foo_entry" + flags = LLVM.API.LLVMJITSymbolFlags( + LLVM.API.LLVMJITSymbolGenericFlagsCallable | + LLVM.API.LLVMJITSymbolGenericFlagsExported, 0) + entry = LLVM.API.LLVMOrcCSymbolAliasMapPair( + mangle(lljit, entry_sym), + LLVM.API.LLVMOrcCSymbolAliasMapEntry( + mangle(lljit, "foo"), flags)) + + mu = LLVM.reexports(lctm, ism, jd, Ref(entry)) + LLVM.define(jd, mu) + + # 2. Lookup address of entry symbol + addr = lookup(lljit, entry_sym) + @test pointer(addr) != C_NULL + + # 3. add MU that will call back into the compiler + sym = LLVM.API.LLVMOrcCSymbolFlagsMapPair(mangle(lljit, "foo"), flags) + + function materialize(mr) + syms = LLVM.get_requested_symbols(mr) + @assert length(syms) == 1 + + # syms contains mangled symbols + # we need to emit an unmangled one + + ts_mod = ThreadSafeModule("jit") + ts_mod() do mod + LLVM.apply_datalayout!(lljit, mod) + + T_Int32 = LLVM.Int32Type() + ft = LLVM.FunctionType(T_Int32, [T_Int32, T_Int32]) + + fn = LLVM.Function(mod, "foo", ft) + + # generate IR + @dispose builder=IRBuilder() begin + entry = BasicBlock(fn, "entry") + position!(builder, entry) + + tmp = add!(builder, parameters(fn)...) + ret!(builder, tmp) + end + end - # 3. Obtain address of compiled module - addr = addressin(orc, orc_mod, sym) + il = LLVM.IRTransformLayer(lljit) + LLVM.emit(il, mr, ts_mod) - # 4. Update the stub pointer to point to the recently compiled module - set_stub!(orc, "lazystub", addr) + return nothing + end - # 5. Return the address of tie implementation, since we are going to call it now - triggered[] = true - return addr.ptr - end - c_callback = @cfunction($callback, UInt64, (LLVM.API.LLVMOrcJITStackRef, Ptr{Cvoid})) + function discard(jd, sym) + end - GC.@preserve c_callback begin - initial_addr = callback!(orc, c_callback, C_NULL) - create_stub!(orc, "lazystub", initial_addr) - addr = address(orc, "lazystub") + mu = LLVM.CustomMaterializationUnit("fooMU", Ref(sym), materialize, discard) + LLVM.define(jd, mu) - ccall(pointer(addr), Cvoid, ()) # Triggers compilation + @test ccall(pointer(addr), Int32, (Int32, Int32), 1, 2) == 3 + finally + dispose(lctm) + dispose(ism) end - @test triggered[] end end end -end diff --git a/test/orcv2_tests.jl b/test/orcv2_tests.jl deleted file mode 100644 index 4c47c884..00000000 --- a/test/orcv2_tests.jl +++ /dev/null @@ -1,306 +0,0 @@ -@static if LLVM.has_orc_v2() -@testitem "orcv2" begin - -let lljit=LLJIT() - dispose(lljit) -end - -LLJIT() do lljit -end - -let ctx = ThreadSafeContext() - dispose(ctx) -end - -ThreadSafeContext() do ctx -end - -@testset "ThreadSafeModule" begin - @dispose ts_ctx=ThreadSafeContext() begin - ts_mod = ThreadSafeModule("jit") - @test_throws LLVMException ts_mod() do mod - error("Error") - end - run = Ref{Bool}(false) - ts_mod() do mod - run[] = true - end - @test run[] - end -end - -@testset "JITDylib" begin - @dispose ts_ctx=ThreadSafeContext() lljit=LLJIT() begin - es = ExecutionSession(lljit) - - @test LLVM.lookup_dylib(es, "my.so") === nothing - - jd = JITDylib(es, "my.so") - jd_bare = JITDylib(es, "mybare.so", bare=true) - - @test LLVM.lookup_dylib(es, "my.so") === jd - - jd_main = JITDylib(lljit) - - prefix = LLVM.get_prefix(lljit) - dg = LLVM.CreateDynamicLibrarySearchGeneratorForProcess(prefix) - add!(jd_main, dg) - - addr = lookup(lljit, "jl_apply_generic") - @test pointer(addr) != C_NULL - end -end - -@testset "Undefined Symbol" begin - @dispose lljit=LLJIT() begin - @test_throws LLVMException lookup(lljit, string(gensym())) - end - - @dispose ts_ctx=ThreadSafeContext() lljit=LLJIT(;tm=JITTargetMachine()) begin - jd = JITDylib(lljit) - - ts_mod = ThreadSafeModule("jit") - - # build the module - fname = "wrapper" - ts_mod() do mod - T_Int32 = LLVM.Int32Type() - ft = LLVM.FunctionType(T_Int32, [T_Int32, T_Int32]) - fn = LLVM.Function(mod, "mysum", ft) - linkage!(fn, LLVM.API.LLVMExternalLinkage) - - wrapper = LLVM.Function(mod, fname, ft) - # generate IR - @dispose builder=IRBuilder() begin - entry = BasicBlock(wrapper, "entry") - position!(builder, entry) - - tmp = call!(builder, ft, fn, [parameters(wrapper)...]) - ret!(builder, tmp) - end - - # TODO: Get TM from lljit? - tm = JITTargetMachine() - triple!(mod, triple(lljit)) - @dispose pm=ModulePassManager() begin - add_library_info!(pm, triple(mod)) - add_transform_info!(pm, tm) - run!(pm, mod) - end - verify(mod) - end - - add!(lljit, jd, ts_mod) - @test_throws LLVMException redirect_stderr(devnull) do - # XXX: this reports an unhandled JIT session error; - # can we handle it instead? - lookup(lljit, fname) - end - end -end - -@testset "Loading ObjectFile" begin - @dispose lljit=LLJIT(;tm=JITTargetMachine()) begin - jd = JITDylib(lljit) - - sym = "SomeFunction" - obj = @dispose ctx=Context() begin - mod = LLVM.Module("jit") - ft = LLVM.FunctionType(LLVM.VoidType()) - fn = LLVM.Function(mod, sym, ft) - - @dispose builder=IRBuilder() begin - entry = BasicBlock(fn, "entry") - position!(builder, entry) - ret!(builder) - end - verify(mod) - - tm = JITTargetMachine() - emit(tm, mod, LLVM.API.LLVMObjectFile) - end - add!(lljit, jd, MemoryBuffer(obj)) - - addr = lookup(lljit, sym) - - @test pointer(addr) != C_NULL - - empty!(jd) - @test_throws LLVMException lookup(lljit, sym) - end - - @dispose lljit=LLJIT(;tm=JITTargetMachine()) begin - jd = JITDylib(lljit) - - sym = "SomeFunction" - obj = @dispose ctx=Context() begin - mod = LLVM.Module("jit") - ft = LLVM.FunctionType(LLVM.Int32Type()) - fn = LLVM.Function(mod, sym, ft) - - gv = LLVM.GlobalVariable(mod, LLVM.Int32Type(), "gv") - LLVM.extinit!(gv, true) - - @dispose builder=IRBuilder() begin - entry = BasicBlock(fn, "entry") - position!(builder, entry) - val = load!(builder, LLVM.Int32Type(), gv) - ret!(builder, val) - end - verify(mod) - - tm = JITTargetMachine() - emit(tm, mod, LLVM.API.LLVMObjectFile) - end - - data = Ref{Int32}(42) - GC.@preserve data begin - address = LLVM.API.LLVMOrcJITTargetAddress( - reinterpret(UInt, Base.unsafe_convert(Ptr{Int32}, data))) - flags = LLVM.API.LLVMJITSymbolFlags( - LLVM.API.LLVMJITSymbolGenericFlagsExported, 0) - name = mangle(lljit, "gv") - symbol = LLVM.API.LLVMJITEvaluatedSymbol(address, flags) - gv = if LLVM.version() >= v"15" - LLVM.API.LLVMOrcCSymbolMapPair(name, symbol) - else - LLVM.API.LLVMJITCSymbolMapPair(name, symbol) - end - - mu = LLVM.absolute_symbols(Ref(gv)) - LLVM.define(jd, mu) - - add!(lljit, jd, MemoryBuffer(obj)) - - addr = lookup(lljit, sym) - @test pointer(addr) != C_NULL - - @test ccall(pointer(addr), Int32, ()) == 42 - data[] = -1 - @test ccall(pointer(addr), Int32, ()) == -1 - - if LLVM.version() < v"13" - LLVM.release(name) - end - end - empty!(jd) - @test_throws LLVMException lookup(lljit, sym) - end -end - -@testset "ObjectLinkingLayer" begin - called_oll = Ref{Int}(0) - - ollc = LLVM.ObjectLinkingLayerCreator() do es, triple - oll = ObjectLinkingLayer(es) - register!(oll, GDBRegistrationListener()) - called_oll[] += 1 - return oll - end - - GC.@preserve ollc begin - builder = LLJITBuilder() - linkinglayercreator!(builder, ollc) - @dispose ts_ctx=ThreadSafeContext() lljit=LLJIT(builder) begin - jd = JITDylib(lljit) - - ts_mod = ThreadSafeModule("jit") - sym = "SomeFunctionOLL" - - # build the module - ts_mod() do mod - ft = LLVM.FunctionType(LLVM.VoidType()) - fn = LLVM.Function(mod, sym, ft) - - @dispose builder=IRBuilder() begin - entry = BasicBlock(fn, "entry") - position!(builder, entry) - ret!(builder) - end - verify(mod) - end - - add!(lljit, jd, ts_mod) - addr = lookup(lljit, sym) - @test pointer(addr) != C_NULL - end - end - @test called_oll[] >= 1 -end - -@testset "Lazy" begin - @dispose ts_ctx=ThreadSafeContext() lljit=LLJIT() begin - jd = JITDylib(lljit) - es = ExecutionSession(lljit) - - lctm = LLVM.LocalLazyCallThroughManager(triple(lljit), es) - ism = LLVM.LocalIndirectStubsManager(triple(lljit)) - try - # 1. define entry symbol - entry_sym = "foo_entry" - flags = LLVM.API.LLVMJITSymbolFlags( - LLVM.API.LLVMJITSymbolGenericFlagsCallable | - LLVM.API.LLVMJITSymbolGenericFlagsExported, 0) - entry = LLVM.API.LLVMOrcCSymbolAliasMapPair( - mangle(lljit, entry_sym), - LLVM.API.LLVMOrcCSymbolAliasMapEntry( - mangle(lljit, "foo"), flags)) - - mu = LLVM.reexports(lctm, ism, jd, Ref(entry)) - LLVM.define(jd, mu) - - # 2. Lookup address of entry symbol - addr = lookup(lljit, entry_sym) - @test pointer(addr) != C_NULL - - # 3. add MU that will call back into the compiler - sym = LLVM.API.LLVMOrcCSymbolFlagsMapPair(mangle(lljit, "foo"), flags) - - function materialize(mr) - syms = LLVM.get_requested_symbols(mr) - @assert length(syms) == 1 - - # syms contains mangled symbols - # we need to emit an unmangled one - - ts_mod = ThreadSafeModule("jit") - ts_mod() do mod - LLVM.apply_datalayout!(lljit, mod) - - T_Int32 = LLVM.Int32Type() - ft = LLVM.FunctionType(T_Int32, [T_Int32, T_Int32]) - - fn = LLVM.Function(mod, "foo", ft) - - # generate IR - @dispose builder=IRBuilder() begin - entry = BasicBlock(fn, "entry") - position!(builder, entry) - - tmp = add!(builder, parameters(fn)...) - ret!(builder, tmp) - end - end - - il = LLVM.IRTransformLayer(lljit) - LLVM.emit(il, mr, ts_mod) - - return nothing - end - - function discard(jd, sym) - end - - mu = LLVM.CustomMaterializationUnit("fooMU", Ref(sym), materialize, discard) - LLVM.define(jd, mu) - - @test ccall(pointer(addr), Int32, (Int32, Int32), 1, 2) == 3 - finally - dispose(lctm) - dispose(ism) - end - end -end - -end -end diff --git a/test/runtests.jl b/test/runtests.jl index 1d635fef..a48c2e00 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,13 +1,3 @@ -# Work around JuliaLang/Pkg.jl#2500 -if VERSION < v"1.8-" - test_project = first(Base.load_path()) - preferences_file = "LocalPreferences.toml" - test_preferences_file = joinpath(dirname(test_project), "LocalPreferences.toml") - if isfile(preferences_file) && !isfile(test_preferences_file) - cp(preferences_file, test_preferences_file) - end -end - using LLVM if Base.JLOptions().debug_level < 2 diff --git a/test/transform_tests.jl b/test/transform_tests.jl index 36da139f..ca1fdda1 100644 --- a/test/transform_tests.jl +++ b/test/transform_tests.jl @@ -33,9 +33,7 @@ end bit_tracking_dce!(pm) alignment_from_assumptions!(pm) cfgsimplification!(pm) - if LLVM.version() >= v"12" - cfgsimplification!(pm; hoist_common_insts=true) - end + cfgsimplification!(pm; hoist_common_insts=true) dead_store_elimination!(pm) scalarizer!(pm) merged_load_store_motion!(pm) @@ -68,9 +66,6 @@ end scalar_repl_aggregates_ssa!(pm) simplify_lib_calls!(pm) tail_call_elimination!(pm) - if LLVM.version() < v"12" - constant_propagation!(pm) - end demote_memory_to_register!(pm) verifier!(pm) correlated_value_propagation!(pm) @@ -96,9 +91,6 @@ end always_inliner!(pm) global_dce!(pm) global_optimizer!(pm) - if LLVM.version() < v"12" - ipconstant_propagation!(pm) - end prune_eh!(pm) ipsccp!(pm) strip_dead_prototypes!(pm)