From 716c4727e4e66af26ded8c7086e4979a9d76ee03 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 4 Sep 2023 10:46:00 +0200 Subject: [PATCH 1/6] Switch to ReTestItems.jl. --- ...{Kaleidoscope.jl => Kaleidoscope_tests.jl} | 2 +- test/Project.toml | 1 + test/{analysis.jl => analysis_tests.jl} | 2 +- test/{bitcode.jl => bitcode_tests.jl} | 2 +- test/{buffer.jl => buffer_tests.jl} | 2 +- test/{core.jl => core_tests.jl} | 4 +- test/{datalayout.jl => datalayout_tests.jl} | 2 +- test/{debuginfo.jl => debuginfo_tests.jl} | 4 +- test/essential_tests.jl | 38 ++++++++ test/{examples.jl => examples_tests.jl} | 2 +- test/{execution.jl => execution_tests.jl} | 2 +- test/{helpers.jl => helpers_testsetup.jl} | 8 ++ ...{instructions.jl => instructions_tests.jl} | 4 + test/{interop.jl => interop_tests.jl} | 7 +- test/{ir.jl => ir_tests.jl} | 2 +- test/{jljit.jl => jljit_tests.jl} | 4 +- test/{linker.jl => linker_tests.jl} | 2 +- ...uleprovider.jl => moduleprovider_tests.jl} | 9 +- test/{newpm.jl => newpm_tests.jl} | 22 +++-- test/{orc.jl => orc_tests.jl} | 4 +- test/{orcv2.jl => orcv2_tests.jl} | 4 +- test/{pass.jl => pass_tests.jl} | 2 +- test/{passmanager.jl => passmanager_tests.jl} | 2 +- test/runtests.jl | 89 ++----------------- test/{support.jl => support_tests.jl} | 2 +- test/{target.jl => target_tests.jl} | 2 +- ...argetmachine.jl => targetmachine_tests.jl} | 2 +- test/{transform.jl => transform_tests.jl} | 4 +- test/{utils.jl => util_tests.jl} | 2 +- 29 files changed, 115 insertions(+), 117 deletions(-) rename test/{Kaleidoscope.jl => Kaleidoscope_tests.jl} (97%) rename test/{analysis.jl => analysis_tests.jl} (96%) rename test/{bitcode.jl => bitcode_tests.jl} (97%) rename test/{buffer.jl => buffer_tests.jl} (96%) rename test/{core.jl => core_tests.jl} (99%) rename test/{datalayout.jl => datalayout_tests.jl} (97%) rename test/{debuginfo.jl => debuginfo_tests.jl} (98%) create mode 100644 test/essential_tests.jl rename test/{examples.jl => examples_tests.jl} (96%) rename test/{execution.jl => execution_tests.jl} (99%) rename test/{helpers.jl => helpers_testsetup.jl} (64%) rename test/{instructions.jl => instructions_tests.jl} (99%) rename test/{interop.jl => interop_tests.jl} (99%) rename test/{ir.jl => ir_tests.jl} (97%) rename test/{jljit.jl => jljit_tests.jl} (99%) rename test/{linker.jl => linker_tests.jl} (96%) rename test/{moduleprovider.jl => moduleprovider_tests.jl} (71%) rename test/{newpm.jl => newpm_tests.jl} (97%) rename test/{orc.jl => orc_tests.jl} (98%) rename test/{orcv2.jl => orcv2_tests.jl} (99%) rename test/{pass.jl => pass_tests.jl} (98%) rename test/{passmanager.jl => passmanager_tests.jl} (93%) rename test/{support.jl => support_tests.jl} (92%) rename test/{target.jl => target_tests.jl} (95%) rename test/{targetmachine.jl => targetmachine_tests.jl} (97%) rename test/{transform.jl => transform_tests.jl} (97%) rename test/{utils.jl => util_tests.jl} (99%) diff --git a/test/Kaleidoscope.jl b/test/Kaleidoscope_tests.jl similarity index 97% rename from test/Kaleidoscope.jl rename to test/Kaleidoscope_tests.jl index 9d2170a3..a344117e 100644 --- a/test/Kaleidoscope.jl +++ b/test/Kaleidoscope_tests.jl @@ -1,4 +1,4 @@ -@testset "Kaleidoscope" begin +@testitem "Kaleidoscope" begin include(joinpath(@__DIR__, "..", "examples", "Kaleidoscope", "Kaleidoscope.jl")) diff --git a/test/Project.toml b/test/Project.toml index 6dd5450d..17352403 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,6 @@ [deps] InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" LLVMExtra_jll = "dad2f222-ce93-54a1-a47d-0025e8a3acab" +ReTestItems = "817f1d60-ba6b-4fd5-9520-3cf149f6a823" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" diff --git a/test/analysis.jl b/test/analysis_tests.jl similarity index 96% rename from test/analysis.jl rename to test/analysis_tests.jl index 5be9baf7..4fbbca16 100644 --- a/test/analysis.jl +++ b/test/analysis_tests.jl @@ -1,4 +1,4 @@ -@testset "analysis" begin +@testitem "analysis" begin @dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("SomeModule") begin ft = LLVM.FunctionType(LLVM.Int32Type()) diff --git a/test/bitcode.jl b/test/bitcode_tests.jl similarity index 97% rename from test/bitcode.jl rename to test/bitcode_tests.jl index 1c4c93c9..dbb52fb2 100644 --- a/test/bitcode.jl +++ b/test/bitcode_tests.jl @@ -1,4 +1,4 @@ -@testset "bitcode" begin +@testitem "bitcode" begin @dispose ctx=Context() begin invalid_bitcode = "invalid" diff --git a/test/buffer.jl b/test/buffer_tests.jl similarity index 96% rename from test/buffer.jl rename to test/buffer_tests.jl index 966eb2ef..c3a353f8 100644 --- a/test/buffer.jl +++ b/test/buffer_tests.jl @@ -1,4 +1,4 @@ -@testset "buffer" begin +@testitem "buffer" begin data = rand(UInt8, 8) diff --git a/test/core.jl b/test/core_tests.jl similarity index 99% rename from test/core.jl rename to test/core_tests.jl index 6f5158c9..46e8c126 100644 --- a/test/core.jl +++ b/test/core_tests.jl @@ -1,3 +1,5 @@ +@testitem "core" setup=[TestHelpers] begin + struct TestStruct x::Bool y::Int64 @@ -11,8 +13,6 @@ end struct TestSingleton end -@testset "core" begin - @testset "context" begin @test context(; throw_error=false) === nothing diff --git a/test/datalayout.jl b/test/datalayout_tests.jl similarity index 97% rename from test/datalayout.jl rename to test/datalayout_tests.jl index 4111406c..112209e0 100644 --- a/test/datalayout.jl +++ b/test/datalayout_tests.jl @@ -1,4 +1,4 @@ -@testset "datalayout" begin +@testitem "datalayout" begin dlstr = "E-p:32:32-f128:128:128" diff --git a/test/debuginfo.jl b/test/debuginfo_tests.jl similarity index 98% rename from test/debuginfo.jl rename to test/debuginfo_tests.jl index 3a381973..b976804c 100644 --- a/test/debuginfo.jl +++ b/test/debuginfo_tests.jl @@ -1,6 +1,4 @@ -using LLVM,Test - -@testset "debuginfo" begin +@testitem "debuginfo" begin DEBUG_METADATA_VERSION() diff --git a/test/essential_tests.jl b/test/essential_tests.jl new file mode 100644 index 00000000..b7ab8702 --- /dev/null +++ b/test/essential_tests.jl @@ -0,0 +1,38 @@ +@testitem "essentials" begin + +@testset "types" begin + @test convert(Bool, LLVM.True) == true + @test convert(Bool, LLVM.False) == false + + @test_throws ArgumentError LLVM.convert(Bool, LLVM.API.LLVMBool(2)) + + @test convert(LLVM.Bool, true) == LLVM.True + @test convert(LLVM.Bool, false) == LLVM.False +end + +@testset "pass registry" begin + passreg = GlobalPassRegistry() + + @test version() isa VersionNumber + @test ismultithreaded() isa Bool + + InitializeCore(passreg) + InitializeTransformUtils(passreg) + InitializeScalarOpts(passreg) + InitializeObjCARCOpts(passreg) + InitializeVectorization(passreg) + InitializeInstCombine(passreg) + InitializeIPO(passreg) + InitializeInstrumentation(passreg) + InitializeAnalysis(passreg) + InitializeIPA(passreg) + InitializeCodeGen(passreg) + InitializeTarget(passreg) + + InitializeNativeTarget() + InitializeAllTargetInfos() + InitializeAllTargetMCs() + InitializeNativeAsmPrinter() +end + +end diff --git a/test/examples.jl b/test/examples_tests.jl similarity index 96% rename from test/examples.jl rename to test/examples_tests.jl index 181a05db..37afd7bd 100644 --- a/test/examples.jl +++ b/test/examples_tests.jl @@ -1,4 +1,4 @@ -@testset "examples" begin +@testitem "examples" begin function find_sources(path::String, sources=String[]) if isdir(path) diff --git a/test/execution.jl b/test/execution_tests.jl similarity index 99% rename from test/execution.jl rename to test/execution_tests.jl index d1372ae5..6d9e3c5a 100644 --- a/test/execution.jl +++ b/test/execution_tests.jl @@ -1,4 +1,4 @@ -@testset "execution" begin +@testitem "execution" begin @testset "generic values" begin diff --git a/test/helpers.jl b/test/helpers_testsetup.jl similarity index 64% rename from test/helpers.jl rename to test/helpers_testsetup.jl index bf5b1ef6..1ee4da1d 100644 --- a/test/helpers.jl +++ b/test/helpers_testsetup.jl @@ -1,6 +1,14 @@ +@testsetup module TestHelpers + +using Test + +export @check_ir + macro check_ir(inst, str) quote inst = string($(esc(inst))) @test occursin($(str), inst) end end + +end diff --git a/test/instructions.jl b/test/instructions_tests.jl similarity index 99% rename from test/instructions.jl rename to test/instructions_tests.jl index f0e4aae4..74366403 100644 --- a/test/instructions.jl +++ b/test/instructions_tests.jl @@ -1,3 +1,5 @@ +@testitem "instructions" setup=[TestHelpers] begin + @testset "irbuilder" begin @dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("SomeModule") begin @@ -501,3 +503,5 @@ end end end end + +end diff --git a/test/interop.jl b/test/interop_tests.jl similarity index 99% rename from test/interop.jl rename to test/interop_tests.jl index 6765803c..9e7e7b22 100644 --- a/test/interop.jl +++ b/test/interop_tests.jl @@ -1,8 +1,8 @@ +@testitem "interop" begin + using LLVM.Interop using InteractiveUtils -@testset "interop" begin - # many of these tests don't use explicit contexts, as they rely on high-level functionality. # that functionality should be using default context options, so query those here. supports_typed_ptrs = @dispose ctx=Context() begin @@ -120,7 +120,6 @@ end @testset "passes" begin - @dispose ctx=Context() mod=LLVM.Module("SomeModule") pm=ModulePassManager() begin demote_float16!(pm) @@ -143,6 +142,8 @@ cpu_features!(pm) end +@test "we didn't crash!" != "" + end diff --git a/test/ir.jl b/test/ir_tests.jl similarity index 97% rename from test/ir.jl rename to test/ir_tests.jl index 2a988e48..ac207e46 100644 --- a/test/ir.jl +++ b/test/ir_tests.jl @@ -1,4 +1,4 @@ -@testset "ir" begin +@testitem "ir" begin @dispose ctx=Context() begin invalid_ir = "invalid" diff --git a/test/jljit.jl b/test/jljit_tests.jl similarity index 99% rename from test/jljit.jl rename to test/jljit_tests.jl index 4059d0d7..f2d5c993 100644 --- a/test/jljit.jl +++ b/test/jljit_tests.jl @@ -1,4 +1,5 @@ -@testset "jljit" begin +@static if LLVM.has_julia_ojit() +@testitem "jljit" begin let jljit=JuliaOJIT() dispose(jljit) @@ -265,3 +266,4 @@ end end end +end diff --git a/test/linker.jl b/test/linker_tests.jl similarity index 96% rename from test/linker.jl rename to test/linker_tests.jl index 12056b26..a4cd4066 100644 --- a/test/linker.jl +++ b/test/linker_tests.jl @@ -1,4 +1,4 @@ -@testset "linker" begin +@testitem "linker" begin @dispose ctx=Context() builder=IRBuilder() begin mod1 = let diff --git a/test/moduleprovider.jl b/test/moduleprovider_tests.jl similarity index 71% rename from test/moduleprovider.jl rename to test/moduleprovider_tests.jl index 23ad5187..37684a1b 100644 --- a/test/moduleprovider.jl +++ b/test/moduleprovider_tests.jl @@ -1,22 +1,27 @@ -@testset "moduleprovider" begin +@testitem "moduleprovider" begin @dispose ctx=Context() begin mod = LLVM.Module("SomeModule") mp = ModuleProvider(mod) dispose(mp) + + @test "we didn't crash!" != "" end @dispose ctx=Context() begin mod = LLVM.Module("SomeModule") ModuleProvider(mod) do md end + + @test "we didn't crash!" != "" end @dispose ctx=Context() begin mod = LLVM.Module("SomeModule") @dispose mp=ModuleProvider(mod) begin - end + + @test "we didn't crash!" != "" end end diff --git a/test/newpm.jl b/test/newpm_tests.jl similarity index 97% rename from test/newpm.jl rename to test/newpm_tests.jl index 7d86d2c2..9dc35213 100644 --- a/test/newpm.jl +++ b/test/newpm_tests.jl @@ -1,3 +1,8 @@ +@static if LLVM.has_newpm() +@testitem "newpm" begin + +using InteractiveUtils # for subtypes + @testset "newpm pass managers" begin let mpm = NewPMModulePassManager() @@ -197,22 +202,22 @@ host_t = Target(triple=host_triple) end @test "Successfully added custom module and function passes!" != "" - + @dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("test") begin pa = run!(mpm, mod, mam) @test observed_modules == 1 @test observed_functions == 0 @test are_all_preserved(pa) - - + + ft = LLVM.FunctionType(LLVM.VoidType()) fn = LLVM.Function(mod, "SomeFunction", ft) - + entry = BasicBlock(fn, "entry") position!(builder, entry) - + ret!(builder) - + pa = run!(mpm, mod, mam) @test observed_modules == 2 @test observed_functions == 1 @@ -222,4 +227,7 @@ host_t = Target(triple=host_triple) end end -end # testset "newpm custom passes" +end # testset "newpm passes" + +end +end diff --git a/test/orc.jl b/test/orc_tests.jl similarity index 98% rename from test/orc.jl rename to test/orc_tests.jl index c83d9799..a277251d 100644 --- a/test/orc.jl +++ b/test/orc_tests.jl @@ -1,4 +1,5 @@ -@testset "orc" begin +@static if LLVM.has_orc_v1() && !LLVM.is_asserts() # XXX: dangling references abort +@testitem "orc" begin let tm = JITTargetMachine() let orc = OrcJIT(tm) @@ -328,3 +329,4 @@ end end end +end diff --git a/test/orcv2.jl b/test/orcv2_tests.jl similarity index 99% rename from test/orcv2.jl rename to test/orcv2_tests.jl index cde8661b..4c47c884 100644 --- a/test/orcv2.jl +++ b/test/orcv2_tests.jl @@ -1,4 +1,5 @@ -@testset "orcv2" begin +@static if LLVM.has_orc_v2() +@testitem "orcv2" begin let lljit=LLJIT() dispose(lljit) @@ -302,3 +303,4 @@ end end end +end diff --git a/test/pass.jl b/test/pass_tests.jl similarity index 98% rename from test/pass.jl rename to test/pass_tests.jl index 9d0f1645..ca313a76 100644 --- a/test/pass.jl +++ b/test/pass_tests.jl @@ -1,4 +1,4 @@ -@testset "pass" begin +@testitem "pass" begin @dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("SomeModule") begin ft = LLVM.FunctionType(LLVM.VoidType()) diff --git a/test/passmanager.jl b/test/passmanager_tests.jl similarity index 93% rename from test/passmanager.jl rename to test/passmanager_tests.jl index 47ef2b5f..334933e6 100644 --- a/test/passmanager.jl +++ b/test/passmanager_tests.jl @@ -1,4 +1,4 @@ -@testset "passmanager" begin +@testitem "passmanager" begin let mpm = ModulePassManager() diff --git a/test/runtests.jl b/test/runtests.jl index 135788fa..1d635fef 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,7 +9,6 @@ if VERSION < v"1.8-" end using LLVM -using Test if Base.JLOptions().debug_level < 2 @warn "It is recommended to run the LLVM.jl test suite with -g2" @@ -18,86 +17,14 @@ end using InteractiveUtils @info "System information:\n" * sprint(io->versioninfo(io)) -@testset "LLVM" begin +worker_init_expr = quote + using LLVM -# HACK: if a test throws within a Context() do block, displaying the LLVM value may crash -# because the context has been disposed already. avoid that by disabling `dispose`, -# and only have it pop the context off the stack (but not destroy it). -LLVM.dispose(ctx::Context) = LLVM.deactivate(ctx) - -include("helpers.jl") - -@testset "types" begin - @test convert(Bool, LLVM.True) == true - @test convert(Bool, LLVM.False) == false - - @test_throws ArgumentError LLVM.convert(Bool, LLVM.API.LLVMBool(2)) - - @test convert(LLVM.Bool, true) == LLVM.True - @test convert(LLVM.Bool, false) == LLVM.False -end - -@testset "pass registry" begin - passreg = GlobalPassRegistry() - - version() - ismultithreaded() - InitializeCore(passreg) - InitializeTransformUtils(passreg) - InitializeScalarOpts(passreg) - InitializeObjCARCOpts(passreg) - InitializeVectorization(passreg) - InitializeInstCombine(passreg) - InitializeIPO(passreg) - InitializeInstrumentation(passreg) - InitializeAnalysis(passreg) - InitializeIPA(passreg) - InitializeCodeGen(passreg) - InitializeTarget(passreg) - - InitializeNativeTarget() - InitializeAllTargetInfos() - InitializeAllTargetMCs() - InitializeNativeAsmPrinter() -end - -include("support.jl") -include("core.jl") -include("linker.jl") -include("instructions.jl") -include("buffer.jl") -include("bitcode.jl") -include("ir.jl") -include("analysis.jl") -include("moduleprovider.jl") -include("passmanager.jl") -include("pass.jl") -include("execution.jl") -include("transform.jl") -include("target.jl") -include("targetmachine.jl") -include("datalayout.jl") -include("debuginfo.jl") -include("utils.jl") - -if LLVM.has_orc_v1() && !LLVM.is_asserts() - # XXX: dangling references abort - include("orc.jl") -end -if LLVM.has_orc_v2() - include("orcv2.jl") -end -if LLVM.has_newpm() - include("newpm.jl") + # HACK: if a test throws within a Context() do block, displaying the LLVM value may + # crash because the context has been disposed already. avoid that by disabling + # `dispose`, and only have it pop the context off the stack (but not destroy it). + LLVM.dispose(ctx::Context) = LLVM.deactivate(ctx) end -if LLVM.has_julia_ojit() - include("jljit.jl") -end -include("Kaleidoscope.jl") - -include("examples.jl") - -include("interop.jl") - -end +using ReTestItems +runtests(LLVM; worker_init_expr, nworkers=min(Sys.CPU_THREADS,4), nworker_threads=1) diff --git a/test/support.jl b/test/support_tests.jl similarity index 92% rename from test/support.jl rename to test/support_tests.jl index 81aedf24..be7a6305 100644 --- a/test/support.jl +++ b/test/support_tests.jl @@ -1,4 +1,4 @@ -@testset "support" begin +@testitem "support" begin @testset "command-line options" begin diff --git a/test/target.jl b/test/target_tests.jl similarity index 95% rename from test/target.jl rename to test/target_tests.jl index f755d790..1f477a94 100644 --- a/test/target.jl +++ b/test/target_tests.jl @@ -1,4 +1,4 @@ -@testset "target" begin +@testitem "target" begin @test_throws ArgumentError Target(triple="invalid") @test_throws ArgumentError Target(name="invalid") diff --git a/test/targetmachine.jl b/test/targetmachine_tests.jl similarity index 97% rename from test/targetmachine.jl rename to test/targetmachine_tests.jl index aa8b707e..7ea0b924 100644 --- a/test/targetmachine.jl +++ b/test/targetmachine_tests.jl @@ -1,4 +1,4 @@ -@testset "targetmachine" begin +@testitem "targetmachine" begin host_triple = triple() host_t = Target(triple=host_triple) diff --git a/test/transform.jl b/test/transform_tests.jl similarity index 97% rename from test/transform.jl rename to test/transform_tests.jl index 07719a4d..36da139f 100644 --- a/test/transform.jl +++ b/test/transform_tests.jl @@ -1,4 +1,4 @@ -@testset "transform" begin +@testitem "transform" begin let pmb = PassManagerBuilder() @@ -109,4 +109,6 @@ end internalize!(pm, ["SomeFunction", "SomeOtherFunction"]) end +@test "we didn't crash!" != "" + end diff --git a/test/utils.jl b/test/util_tests.jl similarity index 99% rename from test/utils.jl rename to test/util_tests.jl index d19aebcf..089f29ae 100644 --- a/test/utils.jl +++ b/test/util_tests.jl @@ -1,4 +1,4 @@ -@testset "utils" begin +@testitem "utils" begin @testset "function cloning" begin @dispose ctx=Context() begin From 64438eccd8d9984c4410f835faef09dcf8d887aa Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 4 Sep 2023 11:06:14 +0200 Subject: [PATCH 2/6] 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 | 482 ++++++++++++++++++--------------------- test/orcv2_tests.jl | 306 ------------------------- test/runtests.jl | 10 - test/transform_tests.jl | 10 +- 18 files changed, 653 insertions(+), 1237 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..e60ac646 100644 --- a/test/jljit_tests.jl +++ b/test/jljit_tests.jl @@ -180,10 +180,6 @@ end @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(jljit, sym) diff --git a/test/orc_tests.jl b/test/orc_tests.jl index a277251d..543ad36b 100644 --- a/test/orc_tests.jl +++ b/test/orc_tests.jl @@ -1,288 +1,209 @@ -@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 - set_stub!(orc, "mystub", OrcTargetAddress(ptr)) + mu = LLVM.absolute_symbols(Ref(gv)) + LLVM.define(jd, mu) - @test addr == address(orc, "mystub") - @test toggle[] == true + add!(lljit, jd, MemoryBuffer(obj)) - ccall(pointer(addr), Cvoid, ()) - @test toggle[] == false + addr = lookup(lljit, sym) + @test pointer(addr) != C_NULL + + @test ccall(pointer(addr), Int32, ()) == 42 + data[] = -1 + @test ccall(pointer(addr), Int32, ()) == -1 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 +213,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) From d305a9695f9585b305ffd748cf9719f26b96056a Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 4 Sep 2023 11:41:01 +0200 Subject: [PATCH 3/6] Adapt test regexes to naming change. --- test/interop_tests.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/interop_tests.jl b/test/interop_tests.jl index 9e7e7b22..56980a03 100644 --- a/test/interop_tests.jl +++ b/test/interop_tests.jl @@ -220,15 +220,15 @@ end end end if supports_typed_ptrs - @test contains(ir, r"load i64, i64\* %\d+, align 1") + @test contains(ir, r"load i64, i64\* %.+?, align 1") else - @test contains(ir, r"load i64, ptr %\d+, align 1") + @test contains(ir, r"load i64, ptr %.+?, align 1") end ir = sprint(io->code_llvm(io, unsafe_load, Tuple{typeof(ptr), Int, Val{4}})) if supports_typed_ptrs - @test contains(ir, r"load i64, i64\* %\d+, align 4") + @test contains(ir, r"load i64, i64\* %.+?, align 4") else - @test contains(ir, r"load i64, ptr %\d+, align 4") + @test contains(ir, r"load i64, ptr %.+?, align 4") end end @@ -239,15 +239,15 @@ end ir = sprint(io->code_llvm(io, LLVM.Interop.addrspacecast, Tuple{Type{T_dest}, typeof(ptr)})) if supports_typed_ptrs if AS_dest == 3 - @test contains(ir, r"addrspacecast i8 addrspace\(4\)\* %\d+ to i8 addrspace\(3\)\*") + @test contains(ir, r"addrspacecast i8 addrspace\(4\)\* %.+? to i8 addrspace\(3\)\*") else - @test !contains(ir, r"addrspacecast i8 addrspace\(4\)\* %\d+ to i8 addrspace\(3\)\*") + @test !contains(ir, r"addrspacecast i8 addrspace\(4\)\* %.+? to i8 addrspace\(3\)\*") end else if AS_dest == 3 - @test contains(ir, r"addrspacecast ptr addrspace\(4\) %\d+ to ptr addrspace\(3\)") + @test contains(ir, r"addrspacecast ptr addrspace\(4\) %.+? to ptr addrspace\(3\)") else - @test !contains(ir, r"addrspacecast ptr addrspace\(4\) %\d+ to ptr addrspace\(3\)") + @test !contains(ir, r"addrspacecast ptr addrspace\(4\) %.+? to ptr addrspace\(3\)") end end end From fdd1558c0dddba6777f1108b943b2567f04cc162 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 4 Sep 2023 12:04:57 +0200 Subject: [PATCH 4/6] Clone Julia outside of the LLVM.jl checkout. --- .github/workflows/ci.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 921c99a6..d33c6bdf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,20 +134,21 @@ jobs: # compile Julia - name: Compile Julia run: | - sed -i.bak 's/exit 2/exit 0/g' julia/deps/tools/jlchecksum - make -C julia -j $(nproc) FORCE_ASSERTIONS=1 LLVM_ASSERTIONS=1 JULIA_PRECOMPILE=0 - echo $PWD/julia/usr/bin >> $GITHUB_PATH + mv julia ../ # move julia checkout out of the way, for ReTestItems.jl + sed -i.bak 's/exit 2/exit 0/g' ../julia/deps/tools/jlchecksum + make -C ../julia -j $(nproc) FORCE_ASSERTIONS=1 LLVM_ASSERTIONS=1 JULIA_PRECOMPILE=0 + echo $PWD/../julia/usr/bin >> $GITHUB_PATH if: runner.os != 'Windows' - name: Compile Julia (in msys2) shell: msys2 {0} run: | - echo $PWD - sed -i.bak 's/exit 2/exit 0/g' julia/deps/tools/jlchecksum + mv julia ../ # move julia checkout out of the way, for ReTestItems.jl + sed -i.bak 's/exit 2/exit 0/g' ../julia/deps/tools/jlchecksum # XXX: workaround for JuliaLang/julia#48081 - make -C julia/deps install-csl && \ - cp ${MINGW_PREFIX}/lib/libmsvcrt.a ./julia/usr/lib/libmsvcrt.a && \ - make -C julia -j $(nproc) FORCE_ASSERTIONS=1 LLVM_ASSERTIONS=1 JULIA_PRECOMPILE=0 - echo $PWD/julia/usr/bin >> $GITHUB_PATH + make -C ../julia/deps install-csl && \ + cp ${MINGW_PREFIX}/lib/libmsvcrt.a ../julia/usr/lib/libmsvcrt.a && \ + make -C ../julia -j $(nproc) FORCE_ASSERTIONS=1 LLVM_ASSERTIONS=1 JULIA_PRECOMPILE=0 + echo $PWD/../julia/usr/bin >> $GITHUB_PATH if: runner.os == 'Windows' # set-up packages From d12dcc6294b40b6b2e7bb68ea0d8aac47fe61b33 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 4 Sep 2023 12:21:19 +0200 Subject: [PATCH 5/6] Exclude Windows + release-1.8. --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d33c6bdf..da5c337f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,6 +114,10 @@ jobs: - branch: 'master' os: 'macOS-latest' arch: 'x64' + # compilation failure + - branch: 'release-1.8' + os: 'windows-latest' + arch: 'x64' steps: - uses: actions/checkout@v3 with: From b7d00f88d8828e8ef242d9e449f8677e55d7aeaa Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 4 Sep 2023 13:21:35 +0200 Subject: [PATCH 6/6] Skip jljit tests on Windows, for now. --- test/jljit_tests.jl | 2 -- test/newpm_tests.jl | 2 -- test/runtests.jl | 15 ++++++++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/test/jljit_tests.jl b/test/jljit_tests.jl index e60ac646..30676cc2 100644 --- a/test/jljit_tests.jl +++ b/test/jljit_tests.jl @@ -1,4 +1,3 @@ -@static if LLVM.has_julia_ojit() @testitem "jljit" begin let jljit=JuliaOJIT() @@ -262,4 +261,3 @@ end end end -end diff --git a/test/newpm_tests.jl b/test/newpm_tests.jl index 9dc35213..e6b42dcc 100644 --- a/test/newpm_tests.jl +++ b/test/newpm_tests.jl @@ -1,4 +1,3 @@ -@static if LLVM.has_newpm() @testitem "newpm" begin using InteractiveUtils # for subtypes @@ -230,4 +229,3 @@ end end # testset "newpm passes" end -end diff --git a/test/runtests.jl b/test/runtests.jl index a48c2e00..b0903b72 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -17,4 +17,17 @@ worker_init_expr = quote end using ReTestItems -runtests(LLVM; worker_init_expr, nworkers=min(Sys.CPU_THREADS,4), nworker_threads=1) +runtests(LLVM; worker_init_expr, nworkers=min(Sys.CPU_THREADS,4), nworker_threads=1, + testitem_timeout=60) do ti + if ti.name == "jljit" + LLVM.has_julia_ojit() || return false + # XXX: hangs on Windows + Sys.iswindows() && return false + end + + if ti.name == "newpm" + LLVM.has_newpm() || return false + end + + true +end