Skip to content

Commit b0780fa

Browse files
authored
Merge pull request #207 from maleadt/vc/orc
Implement ORC api
2 parents dd3eaf2 + 2f84b6d commit b0780fa

File tree

9 files changed

+380
-16
lines changed

9 files changed

+380
-16
lines changed

.appveyor.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ environment:
55
- julia_version: 1.2
66
- julia_version: 1.3
77
- julia_version: 1.4
8+
- julia_version: 1.5
89
- julia_version: latest
910

1011
platform:

COVERAGE.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,19 +1135,19 @@ ErrorHandling
11351135
ORC JIT
11361136
-------
11371137

1138-
- [ ] LLVMOrcCreateInstance
1139-
- [ ] LLVMOrcGetErrorMsg
1140-
- [ ] LLVMOrcGetMangledSymbol
1141-
- [ ] LLVMOrcDisposeMangledSymbol
1142-
- [ ] LLVMOrcCreateLazyCompileCallback
1143-
- [ ] LLVMOrcCreateIndirectStub
1144-
- [ ] LLVMOrcSetIndirectStubPointer
1145-
- [ ] LLVMOrcAddEagerlyCompiledIR
1146-
- [ ] LLVMOrcAddLazilyCompiledIR
1147-
- [ ] LLVMOrcAddObjectFile
1148-
- [ ] LLVMOrcRemoveModule
1149-
- [ ] LLVMOrcGetSymbolAddress
1150-
- [ ] LLVMOrcDisposeInstance
1138+
- [x] LLVMOrcCreateInstance
1139+
- [x] LLVMOrcGetErrorMsg
1140+
- [x] LLVMOrcGetMangledSymbol
1141+
- [x] LLVMOrcDisposeMangledSymbol
1142+
- [x] LLVMOrcCreateLazyCompileCallback
1143+
- [x] LLVMOrcCreateIndirectStub
1144+
- [x] LLVMOrcSetIndirectStubPointer
1145+
- [x] LLVMOrcAddEagerlyCompiledIR
1146+
- [x] LLVMOrcAddLazilyCompiledIR
1147+
- [x] LLVMOrcAddObjectFile
1148+
- [x] LLVMOrcRemoveModule
1149+
- [x] LLVMOrcGetSymbolAddress
1150+
- [x] LLVMOrcDisposeInstance
11511151

11521152

11531153

examples/sum_orc.jl

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# same as `sum.jl`, but using the OrcJIT to compile the code and executing it via ccall.
2+
3+
using Test
4+
5+
using LLVM
6+
7+
if !LLVM.has_orc_v1()
8+
exit()
9+
end
10+
11+
if length(ARGS) == 2
12+
x, y = parse.([Int32], ARGS[1:2])
13+
else
14+
x = Int32(1)
15+
y = Int32(2)
16+
end
17+
18+
Context() do ctx
19+
# Setup jit
20+
tm = JITTargetMachine()
21+
22+
orc = OrcJIT(tm)
23+
register!(orc, GDBRegistrationListener())
24+
25+
param_types = [LLVM.Int32Type(ctx), LLVM.Int32Type(ctx)]
26+
ret_type = LLVM.Int32Type(ctx)
27+
28+
name = mangle(orc, "sum_orc.jl")
29+
mod = LLVM.Module("jit", ctx)
30+
triple!(mod, triple(tm))
31+
32+
ft = LLVM.FunctionType(ret_type, param_types)
33+
sum = LLVM.Function(mod, name, ft)
34+
35+
# generate IR
36+
Builder(ctx) do builder
37+
entry = BasicBlock(sum, "entry", ctx)
38+
position!(builder, entry)
39+
40+
tmp = add!(builder, parameters(sum)[1], parameters(sum)[2], "tmp")
41+
ret!(builder, tmp)
42+
end
43+
44+
verify(mod)
45+
46+
ModulePassManager() do pm
47+
add_library_info!(pm, triple(mod))
48+
add_transform_info!(pm, tm)
49+
run!(pm, mod)
50+
end
51+
52+
verify(mod)
53+
54+
# For debugging:
55+
# asm = String(convert(Vector{UInt8}, emit(tm, mod, LLVM.API.LLVMAssemblyFile)))
56+
# write(stdout, asm)
57+
58+
jitted_mod = compile!(orc, mod)
59+
60+
addr = address(orc, name)
61+
addr2 = addressin(orc, jitted_mod, name)
62+
@test addr == addr2
63+
@test addr.ptr != 0
64+
65+
unregister!(orc, GDBRegistrationListener())
66+
67+
# For debugging:
68+
# ccall(:jl_breakpoint, Cvoid, (Any,), pointer(addr))
69+
# Then in GDB
70+
# b *(*(uint64_t*)v)
71+
@eval call_sum(x, y) = ccall($(pointer(addr)), Int32, (Int32, Int32), x, y)
72+
end
73+
74+
@test call_sum(x, y) == x + y

src/LLVM.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ include("bitcode.jl")
4444
include("transform.jl")
4545
include("debuginfo.jl")
4646

47+
has_orc_v1() = v"8" <= LLVM.version() < v"12"
48+
include("orc.jl")
49+
4750
include("interop.jl")
4851

4952
include("deprecated.jl")

src/orc.jl

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
export OrcJIT, OrcModule, OrcTargetAddress
2+
export JITEventListener, GDBRegistrationListener, IntelJITEventListener,
3+
OProfileJITEventListener, PerfJITEventListener
4+
export dispose, errormsg, compile!, remove!, add!,
5+
mangle, address, addressin, create_stub!, set_stub!,
6+
register!, unregister!, callback!
7+
export JITTargetMachine
8+
9+
@checked struct OrcJIT
10+
ref::API.LLVMOrcJITStackRef
11+
end
12+
13+
Base.unsafe_convert(::Type{API.LLVMOrcJITStackRef}, orc::OrcJIT) = orc.ref
14+
15+
"""
16+
OrcJIT(::TargetMachine)
17+
18+
Creates a OrcJIT stack based on the provided target machine.
19+
20+
!!! warning
21+
Takes ownership of the provided target machine.
22+
"""
23+
function OrcJIT(tm::TargetMachine)
24+
OrcJIT(API.LLVMOrcCreateInstance(tm))
25+
end
26+
27+
function dispose(orc::OrcJIT)
28+
API.LLVMOrcDisposeInstance(orc)
29+
end
30+
31+
function errormsg(orc::OrcJIT)
32+
# The error message is owned by `orc`, and will
33+
# be disposed along-side the OrcJIT.
34+
unsafe_string(LLVM.API.LLVMOrcGetErrorMsg(orc))
35+
end
36+
37+
struct OrcModule
38+
handle::API.LLVMOrcModuleHandle
39+
end
40+
Base.convert(::Type{API.LLVMOrcModuleHandle}, mod::OrcModule) = mod.handle
41+
42+
function compile!(orc::OrcJIT, mod::Module, resolver = C_NULL, ctx = C_NULL; lazy=false)
43+
r_mod = Ref{API.LLVMOrcModuleHandle}()
44+
if lazy
45+
API.LLVMOrcAddLazilyCompiledIR(orc, r_mod, mod, resolver, ctx)
46+
else
47+
API.LLVMOrcAddEagerlyCompiledIR(orc, r_mod, mod, resolver, ctx)
48+
end
49+
OrcModule(r_mod[])
50+
end
51+
52+
function Base.delete!(orc::OrcJIT, mod::OrcModule)
53+
LLVM.API.LLVMOrcRemoveModule(orc, mod)
54+
end
55+
56+
function add!(orc::OrcJIT, obj::MemoryBuffer, resolver = C_NULL, ctx = C_NULL)
57+
r_mod = Ref{API.LLVMOrcModuleHandle}()
58+
API.LLVMOrcAddObjectFile(orc, r_mod, obj, resolver, ctx)
59+
return OrcModule(r_mod[])
60+
end
61+
62+
function mangle(orc::OrcJIT, name)
63+
r_symbol = Ref{Cstring}()
64+
LLVM.API.LLVMOrcGetMangledSymbol(orc, r_symbol, name)
65+
symbol = unsafe_string(r_symbol[])
66+
LLVM.API.LLVMOrcDisposeMangledSymbol(r_symbol[])
67+
return symbol
68+
end
69+
70+
struct OrcTargetAddress
71+
ptr::API.LLVMOrcTargetAddress
72+
end
73+
Base.convert(::Type{API.LLVMOrcTargetAddress}, addr::OrcTargetAddress) = addr.ptr
74+
75+
Base.pointer(addr::OrcTargetAddress) = reinterpret(Ptr{Cvoid}, addr.ptr % UInt) # LLVMOrcTargetAddress is UInt64 even on 32-bit
76+
77+
OrcTargetAddress(ptr::Ptr{Cvoid}) = OrcTargetAddress(reinterpret(UInt, ptr))
78+
79+
function create_stub!(orc::OrcJIT, name, initial)
80+
LLVM.API.LLVMOrcCreateIndirectStub(orc, name, initial)
81+
end
82+
83+
function set_stub!(orc::OrcJIT, name, new)
84+
LLVM.API.LLVMOrcSetIndirectStubPointer(orc, name, new)
85+
end
86+
87+
function address(orc::OrcJIT, name)
88+
r_address = Ref{API.LLVMOrcTargetAddress}()
89+
API.LLVMOrcGetSymbolAddress(orc, r_address, name)
90+
OrcTargetAddress(r_address[])
91+
end
92+
93+
function addressin(orc::OrcJIT, mod::OrcModule, name)
94+
r_address = Ref{API.LLVMOrcTargetAddress}()
95+
API.LLVMOrcGetSymbolAddressIn(orc, r_address, mod, name)
96+
OrcTargetAddress(r_address[])
97+
end
98+
99+
function callback!(orc::OrcJIT, callback, ctx)
100+
r_address = Ref{API.LLVMOrcTargetAddress}()
101+
LLVM.API.LLVMOrcLazyCompileCallback(orc, r_address, callback, ctx)
102+
return OrcTargetAddress(r_address[])
103+
end
104+
105+
@checked struct JITEventListener
106+
ref::API.LLVMJITEventListenerRef
107+
end
108+
Base.unsafe_convert(::Type{API.LLVMJITEventListenerRef}, listener::JITEventListener) = listener.ref
109+
110+
function register!(orc::OrcJIT, listener::JITEventListener)
111+
LLVM.API.LLVMOrcRegisterJITEventListener(orc, listener)
112+
end
113+
114+
function unregister!(orc::OrcJIT, listener::JITEventListener)
115+
LLVM.API.LLVMOrcUnregisterJITEventListener(orc, listener)
116+
end
117+
118+
GDBRegistrationListener() = JITEventListener(LLVM.API.LLVMCreateGDBRegistrationListener())
119+
IntelJITEventListener() = JITEventListener(LLVM.API.LLVMCreateIntelJITEventListener())
120+
OProfileJITEventListener() = JITEventListener(LLVM.API.LLVMCreateOProfileJITEventListener())
121+
PerfJITEventListener() = JITEventListener(LLVM.API.LLVMCreatePerfJITEventListener())
122+
123+
function JITTargetMachine(;triple = LLVM.triple(),
124+
cpu = "", features = "",
125+
optlevel = LLVM.API.LLVMCodeGenLevelDefault)
126+
127+
# Force ELF on windows,
128+
# Note: Without this call to normalize Orc get's confused
129+
# and chooses the x86_64 SysV ABI on Win x64
130+
triple = LLVM.normalize(triple)
131+
if Sys.iswindows()
132+
triple *= "-elf"
133+
end
134+
target = LLVM.Target(triple=triple)
135+
@debug "Configuring OrcJIT with" triple cpu features optlevel
136+
137+
tm = TargetMachine(target, triple, cpu, features,
138+
optlevel,
139+
LLVM.API.LLVMRelocStatic, # Generate simpler code for JIT
140+
LLVM.API.LLVMCodeModelJITDefault, # Required to init TM as JIT
141+
)
142+
return tm
143+
end

src/targetmachine.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ end
3131
target(tm::TargetMachine) = Target(API.LLVMGetTargetMachineTarget(tm))
3232
triple(tm::TargetMachine) = unsafe_message(API.LLVMGetTargetMachineTriple(tm))
3333
triple() = unsafe_message(API.LLVMGetDefaultTargetTriple())
34+
normalize(triple) = unsafe_message(API.LLVMNormalizeTargetTriple(triple))
3435
cpu(tm::TargetMachine) = unsafe_message(API.LLVMGetTargetMachineCPU(tm))
3536
features(tm::TargetMachine) = unsafe_message(API.LLVMGetTargetMachineFeatureString(tm))
3637

test/interop.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,11 @@ end
191191
@test unsafe_load(ptr) == 2
192192

193193
ir = sprint(io->code_llvm(io, unsafe_load, Tuple{typeof(ptr)}))
194-
if VERSION >= v"1.6-" && Sys.iswindows() && Sys.WORD_SIZE == 32
194+
if VERSION >= v"1.5.2" && Sys.iswindows() && Sys.WORD_SIZE == 32
195195
# FIXME: Win32 nightly emits a i64*, even though bitstype_to_llvm uses T_int8
196-
@test_broken contains(ir, r"@julia_unsafe_load_\d+\(i8\*\)")
196+
@test_broken contains(ir, r"@julia_unsafe_load_\d+\(i8\*")
197197
else
198-
@test contains(ir, r"@julia_unsafe_load_\d+\(i8\*\)")
198+
@test contains(ir, r"@julia_unsafe_load_\d+\(i8\*")
199199
end
200200
@test contains(ir, r"load i64, i64\* %\d+, align 1")
201201

0 commit comments

Comments
 (0)