Skip to content

Commit 6cef553

Browse files
authored
Add support for using the native runtime if available (#306)
* NativeCompilerTarget should support throwing * don't link in the Runtime when the Julia runtime can be used * use Julia's legalization when the Julia runtime is available
1 parent dedce75 commit 6cef553

File tree

7 files changed

+67
-9
lines changed

7 files changed

+67
-9
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
1414

1515
[compat]
1616
ExprTools = "0.1"
17-
LLVM = "4.7"
17+
LLVM = "4.8"
1818
TimerOutputs = "0.5"
1919
julia = "1.6"

src/driver.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ const __llvm_initialized = Ref(false)
209209

210210
# always preload the runtime, and do so early; it cannot be part of any timing block
211211
# because it recurses into the compiler
212-
if libraries
212+
if !uses_julia_runtime(job) && libraries
213213
runtime = load_runtime(job; ctx)
214214
runtime_fns = LLVM.name.(defs(runtime))
215215
runtime_intrinsics = ["julia.gc_alloc_obj"]
@@ -222,7 +222,7 @@ const __llvm_initialized = Ref(false)
222222
@timeit_debug to "target libraries" link_libraries!(job, ir, undefined_fns)
223223

224224
# GPU run-time library
225-
if any(fn -> fn in runtime_fns || fn in runtime_intrinsics, undefined_fns)
225+
if !uses_julia_runtime(job) && any(fn -> fn in runtime_fns || fn in runtime_intrinsics, undefined_fns)
226226
@timeit_debug to "runtime library" link_library!(ir, runtime)
227227
end
228228
end

src/interface.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ end
143143

144144
## interfaces and fallback definitions
145145

146+
# Has the runtime available and does not require special handling
147+
uses_julia_runtime(@nospecialize(job::CompilerJob)) = false
148+
149+
# Should emit PTLS lookup that can be relocated
150+
dump_native(@nospecialize(job::CompilerJob)) = false
151+
146152
# the Julia module to look up target-specific runtime functions in (this includes both
147153
# target-specific functions from the GPU runtime library, like `malloc`, but also
148154
# replacements functions for operations like `Base.sin`)
@@ -157,7 +163,7 @@ get_interpreter(@nospecialize(job::CompilerJob)) =
157163

158164
# does this target support throwing Julia exceptions with jl_throw?
159165
# if not, calls to throw will be replaced with calls to the GPU runtime
160-
can_throw(@nospecialize(job::CompilerJob)) = false
166+
can_throw(@nospecialize(job::CompilerJob)) = uses_julia_runtime(job)
161167

162168
# generate a string that represents the type of compilation, for selecting a compiled
163169
# instance of the runtime library. this slug should encode everything that affects

src/native.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Base.@kwdef struct NativeCompilerTarget <: AbstractCompilerTarget
88
cpu::String=(LLVM.version() < v"8") ? "" : unsafe_string(LLVM.API.LLVMGetHostCPUName())
99
features::String=(LLVM.version() < v"8") ? "" : unsafe_string(LLVM.API.LLVMGetHostCPUFeatures())
1010
always_inline::Bool=false # will mark the job function as always inline
11+
jlruntime::Bool=true # Use Julia runtime for throwing errors, instead of the GPUCompiler support
1112
end
1213

1314
llvm_triple(::NativeCompilerTarget) = Sys.MACHINE
@@ -33,4 +34,5 @@ end
3334

3435
## job
3536

36-
runtime_slug(job::CompilerJob{NativeCompilerTarget}) = "native_$(job.target.cpu)-$(hash(job.target.features))"
37+
runtime_slug(job::CompilerJob{NativeCompilerTarget}) = "native_$(job.target.cpu)-$(hash(job.target.features))$(job.target.jlruntime ? "-jlrt" : "")"
38+
uses_julia_runtime(job::CompilerJob{NativeCompilerTarget}) = job.target.jlruntime

src/optim.jl

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ function optimize!(@nospecialize(job::CompilerJob), mod::LLVM.Module)
185185
ModulePassManager() do pm
186186
addTargetPasses!(pm, tm, triple)
187187

188-
add!(pm, FunctionPass("LowerGCFrame", lower_gc_frame!))
188+
if !uses_julia_runtime(job)
189+
add!(pm, FunctionPass("LowerGCFrame", lower_gc_frame!))
190+
end
189191

190192
if job.source.kernel
191193
# GC lowering is the last pass that may introduce calls to the runtime library,
@@ -194,16 +196,38 @@ function optimize!(@nospecialize(job::CompilerJob), mod::LLVM.Module)
194196
add!(pm, ModulePass("CleanupKernelState", cleanup_kernel_state!))
195197
end
196198

197-
# remove dead uses of ptls
198-
aggressive_dce!(pm)
199-
add!(pm, ModulePass("LowerPTLS", lower_ptls!))
199+
if !uses_julia_runtime(job)
200+
# remove dead uses of ptls
201+
aggressive_dce!(pm)
202+
add!(pm, ModulePass("LowerPTLS", lower_ptls!))
203+
end
200204

205+
if uses_julia_runtime(job)
206+
lower_exc_handlers!(pm)
207+
end
201208
# the Julia GC lowering pass also has some clean-up that is required
202209
late_lower_gc_frame!(pm)
210+
if uses_julia_runtime(job)
211+
final_lower_gc!(pm)
212+
end
203213

204214
remove_ni!(pm)
205215
remove_julia_addrspaces!(pm)
206216

217+
if uses_julia_runtime(job)
218+
# We need these two passes and the instcombine below
219+
# after GC lowering to let LLVM do some constant propagation on the tags.
220+
# and remove some unnecessary write barrier checks.
221+
gvn!(pm)
222+
sccp!(pm)
223+
# Remove dead use of ptls
224+
dce!(pm)
225+
LLVM.Interop.lower_ptls!(pm, dump_native(job))
226+
instruction_combining!(pm)
227+
# Clean up write barrier and ptls lowering
228+
cfgsimplification!(pm)
229+
end
230+
207231
# Julia's operand bundles confuse the inliner, so repeat here now they are gone.
208232
# FIXME: we should fix the inliner so that inlined code gets optimized early-on
209233
always_inliner!(pm)

test/definitions/native.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,24 @@ module LazyCodegen
132132
end
133133
else # LLVM >=12
134134

135+
function absolute_symbol_materialization(name, ptr)
136+
address = LLVM.API.LLVMOrcJITTargetAddress(reinterpret(UInt, ptr))
137+
flags = LLVM.API.LLVMJITSymbolFlags(LLVM.API.LLVMJITSymbolGenericFlagsExported, 0)
138+
symbol = LLVM.API.LLVMJITEvaluatedSymbol(address, flags)
139+
gv = LLVM.API.LLVMJITCSymbolMapPair(name, symbol)
140+
141+
return LLVM.absolute_symbols(Ref(gv))
142+
end
143+
144+
function define_absolute_symbol(jd, name)
145+
ptr = LLVM.find_symbol(name)
146+
if ptr !== C_NULL
147+
LLVM.define(jd, absolute_symbol_materialization(name, ptr))
148+
return true
149+
end
150+
return false
151+
end
152+
135153
struct CompilerInstance
136154
jit::LLVM.LLJIT
137155
lctm::LLVM.LazyCallThroughManager
@@ -151,6 +169,10 @@ module LazyCodegen
151169
prefix = LLVM.get_prefix(lljit)
152170
dg = LLVM.CreateDynamicLibrarySearchGeneratorForProcess(prefix)
153171
add!(jd_main, dg)
172+
if Sys.iswindows() && Int === Int64
173+
# TODO can we check isGNU?
174+
define_absolute_symbol(jd_main, mangle(lljit, "___chkstk_ms"))
175+
end
154176

155177
es = ExecutionSession(lljit)
156178

test/native.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,10 @@ end
345345
else
346346
@test_broken call_delayed(complex, 1.0, 2.0) == 1.0+2.0im
347347
end
348+
349+
throws(arr, i) = arr[i]
350+
@test call_delayed(throws, [1], 1) == 1
351+
@test_throws BoundsError call_delayed(throws, [1], 0)
348352
end
349353

350354
############################################################################################

0 commit comments

Comments
 (0)