From 66994b10077b1ad94a98a935fea31ff8a509c354 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Wed, 25 Oct 2023 09:57:12 +0200 Subject: [PATCH 1/4] Default to creating contexts that use typed pointers. --- deps/LLVMExtra/include/LLVMExtra.h | 1 + deps/LLVMExtra/lib/llvm-api.cpp | 3 +++ lib/libLLVM_extra.jl | 3 +++ src/core/context.jl | 28 +++++++++++++++++++++++----- src/executionengine/ts_module.jl | 12 +++++++++--- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/deps/LLVMExtra/include/LLVMExtra.h b/deps/LLVMExtra/include/LLVMExtra.h index 5bca5b52..d5879100 100644 --- a/deps/LLVMExtra/include/LLVMExtra.h +++ b/deps/LLVMExtra/include/LLVMExtra.h @@ -185,6 +185,7 @@ void LLVMReplaceMDNodeOperandWith(LLVMMetadataRef MD, unsigned I, LLVMMetadataRe #if LLVM_VERSION_MAJOR >= 13 LLVMBool LLVMContextSupportsTypedPointers(LLVMContextRef C); +LLVMBool LLVMContextHasSetOpaquePointersValue(LLVMContextRef C); #endif // constant data diff --git a/deps/LLVMExtra/lib/llvm-api.cpp b/deps/LLVMExtra/lib/llvm-api.cpp index e08a6c70..41344e49 100644 --- a/deps/LLVMExtra/lib/llvm-api.cpp +++ b/deps/LLVMExtra/lib/llvm-api.cpp @@ -618,6 +618,9 @@ void LLVMReplaceMDNodeOperandWith(LLVMMetadataRef MD, unsigned I, LLVMMetadataRe LLVMBool LLVMContextSupportsTypedPointers(LLVMContextRef C) { return unwrap(C)->supportsTypedPointers(); } +LLVMBool LLVMContextHasSetOpaquePointersValue(LLVMContextRef C) { + return unwrap(C)->hasSetOpaquePointersValue(); +} #endif LLVMValueRef LLVMConstDataArray(LLVMTypeRef ElementTy, const void *Data, unsigned NumElements) { diff --git a/lib/libLLVM_extra.jl b/lib/libLLVM_extra.jl index faf1d25e..9e75beaa 100644 --- a/lib/libLLVM_extra.jl +++ b/lib/libLLVM_extra.jl @@ -456,6 +456,9 @@ if version() > v"12" function LLVMContextSupportsTypedPointers(Ctx) ccall((:LLVMContextSupportsTypedPointers, libLLVMExtra), LLVMBool, (LLVMContextRef,), Ctx) end +function LLVMContextHasSetOpaquePointersValue(Ctx) + ccall((:LLVMContextHasSetOpaquePointersValue, libLLVMExtra), LLVMBool, (LLVMContextRef,), Ctx) +end end function LLVMConstDataArray(ElementTy, Data, NumElements) diff --git a/src/core/context.jl b/src/core/context.jl index feb24be6..0ed033c8 100644 --- a/src/core/context.jl +++ b/src/core/context.jl @@ -1,6 +1,6 @@ # Contexts are execution states for the core LLVM IR system. -export Context, dispose, GlobalContext, typed_pointers, opaque_pointers! +export Context, dispose, GlobalContext, typed_pointers @checked struct Context ref::API.LLVMContextRef @@ -8,8 +8,19 @@ end Base.unsafe_convert(::Type{API.LLVMContextRef}, ctx::Context) = ctx.ref -function Context() +function Context(; opaque_pointers=false) ctx = Context(API.LLVMContextCreate()) + @static if v"13" <= version() < v"17" + # during the transition to opaque pointers, contexts can be configured to use + # typed or opaque pointers. this can lead to incompatibilities: opaque IR cannot + # be used in a typed context. the reverse is not true though, so we make sure to + # configure LLVM.jl contexts to use typed pointers by default, resulting in simple + # `Context()` constructors (e.g. as used in LLVM.jl-based generators) generating IR + # that's compatible regardless of the compiler's choice of pointers. + if opaque_pointers !== nothing && !has_set_opaque_pointers_value(ctx) + opaque_pointers!(ctx, opaque_pointers) + end + end _install_handlers(ctx) activate(ctx) ctx @@ -20,8 +31,8 @@ function dispose(ctx::Context) API.LLVMContextDispose(ctx) end -function Context(f::Core.Function) - ctx = Context() +function Context(f::Core.Function; kwargs...) + ctx = Context(; kwargs...) try f(ctx) finally @@ -35,8 +46,15 @@ if version() >= v"13" typed_pointers(ctx::Context) = convert(Core.Bool, API.LLVMContextSupportsTypedPointers(ctx)) - opaque_pointers!(ctx::Context, enable::Core.Bool) = + has_set_opaque_pointers_value(ctx::Context) = + convert(Core.Bool, API.LLVMContextHasSetOpaquePointersValue(ctx)) + + function opaque_pointers!(ctx::Context, enable::Core.Bool) + if has_set_opaque_pointers_value(ctx) + error("Opaque pointers value has already been set!") + end API.LLVMContextSetOpaquePointers(ctx, enable) + end else typed_pointers(ctx::Context) = true diff --git a/src/executionengine/ts_module.jl b/src/executionengine/ts_module.jl index 15ed48a0..be5d2f02 100644 --- a/src/executionengine/ts_module.jl +++ b/src/executionengine/ts_module.jl @@ -3,14 +3,20 @@ end Base.unsafe_convert(::Type{API.LLVMOrcThreadSafeContextRef}, ctx::ThreadSafeContext) = ctx.ref -function ThreadSafeContext() +function ThreadSafeContext(; opaque_pointers=false) ts_ctx = ThreadSafeContext(API.LLVMOrcCreateNewThreadSafeContext()) + @static if v"13" <= version() < v"17" + ctx = context(ts_ctx) + if opaque_pointers !== nothing && !has_set_opaque_pointers_value(ctx) + opaque_pointers!(ctx, opaque_pointers) + end + end activate(ts_ctx) ts_ctx end -function ThreadSafeContext(f::Core.Function) - ctx = ThreadSafeContext() +function ThreadSafeContext(f::Core.Function; kwargs...) + ctx = ThreadSafeContext(; kwargs...) try f(ctx) finally From c6c31b5663431296e73c6b5365a052baeffa295a Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Wed, 25 Oct 2023 10:24:16 +0200 Subject: [PATCH 2/4] Rework. --- deps/LLVMExtra/include/LLVMExtra.h | 2 + deps/LLVMExtra/lib/llvm-api.cpp | 2 + lib/libLLVM_extra.jl | 4 +- src/core/context.jl | 103 ++++++++++++++++++++--------- src/executionengine/ts_module.jl | 7 +- 5 files changed, 79 insertions(+), 39 deletions(-) diff --git a/deps/LLVMExtra/include/LLVMExtra.h b/deps/LLVMExtra/include/LLVMExtra.h index d5879100..15dbc6b3 100644 --- a/deps/LLVMExtra/include/LLVMExtra.h +++ b/deps/LLVMExtra/include/LLVMExtra.h @@ -185,6 +185,8 @@ void LLVMReplaceMDNodeOperandWith(LLVMMetadataRef MD, unsigned I, LLVMMetadataRe #if LLVM_VERSION_MAJOR >= 13 LLVMBool LLVMContextSupportsTypedPointers(LLVMContextRef C); +#endif +#if LLVM_VERSION_MAJOR >= 15 LLVMBool LLVMContextHasSetOpaquePointersValue(LLVMContextRef C); #endif diff --git a/deps/LLVMExtra/lib/llvm-api.cpp b/deps/LLVMExtra/lib/llvm-api.cpp index 41344e49..cb333b0a 100644 --- a/deps/LLVMExtra/lib/llvm-api.cpp +++ b/deps/LLVMExtra/lib/llvm-api.cpp @@ -618,6 +618,8 @@ void LLVMReplaceMDNodeOperandWith(LLVMMetadataRef MD, unsigned I, LLVMMetadataRe LLVMBool LLVMContextSupportsTypedPointers(LLVMContextRef C) { return unwrap(C)->supportsTypedPointers(); } +#endif +#if LLVM_VERSION_MAJOR >= 15 LLVMBool LLVMContextHasSetOpaquePointersValue(LLVMContextRef C) { return unwrap(C)->hasSetOpaquePointersValue(); } diff --git a/lib/libLLVM_extra.jl b/lib/libLLVM_extra.jl index 9e75beaa..62baf598 100644 --- a/lib/libLLVM_extra.jl +++ b/lib/libLLVM_extra.jl @@ -452,10 +452,12 @@ function LLVMPostDominatorTreeInstructionDominates(Tree, InstA, InstB) ccall((:LLVMPostDominatorTreeInstructionDominates, libLLVMExtra), LLVMBool, (LLVMPostDominatorTreeRef, LLVMValueRef, LLVMValueRef), Tree, InstA, InstB) end -if version() > v"12" +if version() >= v"13" function LLVMContextSupportsTypedPointers(Ctx) ccall((:LLVMContextSupportsTypedPointers, libLLVMExtra), LLVMBool, (LLVMContextRef,), Ctx) end +end +if version() >= v"15" function LLVMContextHasSetOpaquePointersValue(Ctx) ccall((:LLVMContextHasSetOpaquePointersValue, libLLVMExtra), LLVMBool, (LLVMContextRef,), Ctx) end diff --git a/src/core/context.jl b/src/core/context.jl index 0ed033c8..c20a8a18 100644 --- a/src/core/context.jl +++ b/src/core/context.jl @@ -1,6 +1,6 @@ # Contexts are execution states for the core LLVM IR system. -export Context, dispose, GlobalContext, typed_pointers +export Context, dispose, GlobalContext @checked struct Context ref::API.LLVMContextRef @@ -9,18 +9,15 @@ end Base.unsafe_convert(::Type{API.LLVMContextRef}, ctx::Context) = ctx.ref function Context(; opaque_pointers=false) + # during the transition to opaque pointers, contexts can be configured to use + # typed or opaque pointers. this can lead to incompatibilities: opaque IR cannot + # be used in a typed context. the reverse is not true though, so we make sure to + # configure LLVM.jl contexts to use typed pointers by default, resulting in simple + # `Context()` constructors (e.g. as used in LLVM.jl-based generators) generating IR + # that's compatible regardless of the compiler's choice of pointers. + ctx = Context(API.LLVMContextCreate()) - @static if v"13" <= version() < v"17" - # during the transition to opaque pointers, contexts can be configured to use - # typed or opaque pointers. this can lead to incompatibilities: opaque IR cannot - # be used in a typed context. the reverse is not true though, so we make sure to - # configure LLVM.jl contexts to use typed pointers by default, resulting in simple - # `Context()` constructors (e.g. as used in LLVM.jl-based generators) generating IR - # that's compatible regardless of the compiler's choice of pointers. - if opaque_pointers !== nothing && !has_set_opaque_pointers_value(ctx) - opaque_pointers!(ctx, opaque_pointers) - end - end + opaque_pointers!(ctx, opaque_pointers) _install_handlers(ctx) activate(ctx) ctx @@ -42,26 +39,6 @@ end GlobalContext() = Context(API.LLVMGetGlobalContext()) -if version() >= v"13" - typed_pointers(ctx::Context) = - convert(Core.Bool, API.LLVMContextSupportsTypedPointers(ctx)) - - has_set_opaque_pointers_value(ctx::Context) = - convert(Core.Bool, API.LLVMContextHasSetOpaquePointersValue(ctx)) - - function opaque_pointers!(ctx::Context, enable::Core.Bool) - if has_set_opaque_pointers_value(ctx) - error("Opaque pointers value has already been set!") - end - API.LLVMContextSetOpaquePointers(ctx, enable) - end -else - typed_pointers(ctx::Context) = true - - opaque_pointers!(ctx::Context, enable::Bool) = - error("Opaque pointers not supported") -end - function Base.show(io::IO, ctx::Context) @printf(io, "LLVM.Context(%p", ctx.ref) if ctx == GlobalContext() @@ -82,6 +59,68 @@ end argument, or use an environment that sypports typed pointers.""") +## opaque pointer handling + +export typed_pointers + +if version() >= v"13" + typed_pointers(ctx::Context) = + convert(Core.Bool, API.LLVMContextSupportsTypedPointers(ctx)) + + if version() >= v"15" + has_set_opaque_pointers_value(ctx::Context) = + convert(Core.Bool, API.LLVMContextHasSetOpaquePointersValue(ctx)) + end + + function unsafe_opaque_pointers!(ctx::Context, enable::Core.Bool) + @static if version() >= v"15" + if has_set_opaque_pointers_value(ctx) + error("Opaque pointers value has already been set!") + end + end + API.LLVMContextSetOpaquePointers(ctx, enable) + end +else + typed_pointers(ctx::Context) = true +end + +function opaque_pointers!(ctx::Context, opaque_pointers) + if opaque_pointers === nothing + # the user explicitly opted out of configuring the context + return + end + + @static if version() < v"13" + if opaque_pointers + error("LLVM <13 does not support opaque pointers") + end + end + + @static if version() >= v"17" + if !opaque_pointers + error("LLVM >=17 does not support typed pointers") + end + end + + @static if v"13" <= version() < v"17" + # the opaque pointer setting can only be set once + @static if version() >= v"15" + # on LLVM 15, we can check whether the context has been configured already + if has_set_opaque_pointers_value(ctx) + return + end + else + # we also know that Julia used to set this value to `false` by default + if VERSION < v"1.11-" + return + end + end + + unsafe_opaque_pointers!(ctx, opaque_pointers) + end +end + + ## wrapper exception type export LLVMException diff --git a/src/executionengine/ts_module.jl b/src/executionengine/ts_module.jl index be5d2f02..96204f8f 100644 --- a/src/executionengine/ts_module.jl +++ b/src/executionengine/ts_module.jl @@ -5,12 +5,7 @@ Base.unsafe_convert(::Type{API.LLVMOrcThreadSafeContextRef}, ctx::ThreadSafeCont function ThreadSafeContext(; opaque_pointers=false) ts_ctx = ThreadSafeContext(API.LLVMOrcCreateNewThreadSafeContext()) - @static if v"13" <= version() < v"17" - ctx = context(ts_ctx) - if opaque_pointers !== nothing && !has_set_opaque_pointers_value(ctx) - opaque_pointers!(ctx, opaque_pointers) - end - end + opaque_pointers!(context(ts_ctx), opaque_pointers) activate(ts_ctx) ts_ctx end From d6aefdcbf8d10189f111d4518b101311a037872c Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Wed, 25 Oct 2023 13:47:24 +0200 Subject: [PATCH 3/4] Improve error handling. --- src/core/context.jl | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/core/context.jl b/src/core/context.jl index c20a8a18..51e6a3b5 100644 --- a/src/core/context.jl +++ b/src/core/context.jl @@ -74,8 +74,8 @@ if version() >= v"13" function unsafe_opaque_pointers!(ctx::Context, enable::Core.Bool) @static if version() >= v"15" - if has_set_opaque_pointers_value(ctx) - error("Opaque pointers value has already been set!") + if has_set_opaque_pointers_value(ctx) && typed_pointers(ctx) != !enable + error("Cannot $(enable ? "enable" : "disable") opaque pointers, as the context has already been configured to use $(typed_pointers(ctx) ? "typed" : "opaque") pointers") end end API.LLVMContextSetOpaquePointers(ctx, enable) @@ -103,19 +103,6 @@ function opaque_pointers!(ctx::Context, opaque_pointers) end @static if v"13" <= version() < v"17" - # the opaque pointer setting can only be set once - @static if version() >= v"15" - # on LLVM 15, we can check whether the context has been configured already - if has_set_opaque_pointers_value(ctx) - return - end - else - # we also know that Julia used to set this value to `false` by default - if VERSION < v"1.11-" - return - end - end - unsafe_opaque_pointers!(ctx, opaque_pointers) end end From 4af61fc8d0a7730d9adbe3f450fe2bc3074226a1 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Wed, 25 Oct 2023 13:51:27 +0200 Subject: [PATCH 4/4] Disable default behavior now that Julia will change the default. --- src/core/context.jl | 20 +++++--------------- src/executionengine/ts_module.jl | 6 ++++-- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/core/context.jl b/src/core/context.jl index 51e6a3b5..1d2ae384 100644 --- a/src/core/context.jl +++ b/src/core/context.jl @@ -8,16 +8,11 @@ end Base.unsafe_convert(::Type{API.LLVMContextRef}, ctx::Context) = ctx.ref -function Context(; opaque_pointers=false) - # during the transition to opaque pointers, contexts can be configured to use - # typed or opaque pointers. this can lead to incompatibilities: opaque IR cannot - # be used in a typed context. the reverse is not true though, so we make sure to - # configure LLVM.jl contexts to use typed pointers by default, resulting in simple - # `Context()` constructors (e.g. as used in LLVM.jl-based generators) generating IR - # that's compatible regardless of the compiler's choice of pointers. - +function Context(; opaque_pointers=nothing) ctx = Context(API.LLVMContextCreate()) - opaque_pointers!(ctx, opaque_pointers) + if opaque_pointers !== nothing + opaque_pointers!(ctx, opaque_pointers) + end _install_handlers(ctx) activate(ctx) ctx @@ -84,12 +79,7 @@ else typed_pointers(ctx::Context) = true end -function opaque_pointers!(ctx::Context, opaque_pointers) - if opaque_pointers === nothing - # the user explicitly opted out of configuring the context - return - end - +function opaque_pointers!(ctx::Context, opaque_pointers::Core.Bool) @static if version() < v"13" if opaque_pointers error("LLVM <13 does not support opaque pointers") diff --git a/src/executionengine/ts_module.jl b/src/executionengine/ts_module.jl index 96204f8f..fa679992 100644 --- a/src/executionengine/ts_module.jl +++ b/src/executionengine/ts_module.jl @@ -3,9 +3,11 @@ end Base.unsafe_convert(::Type{API.LLVMOrcThreadSafeContextRef}, ctx::ThreadSafeContext) = ctx.ref -function ThreadSafeContext(; opaque_pointers=false) +function ThreadSafeContext(; opaque_pointers=nothing) ts_ctx = ThreadSafeContext(API.LLVMOrcCreateNewThreadSafeContext()) - opaque_pointers!(context(ts_ctx), opaque_pointers) + if opaque_pointers !== nothing + opaque_pointers!(context(ts_ctx), opaque_pointers) + end activate(ts_ctx) ts_ctx end