Skip to content

Commit 4773269

Browse files
authored
also compile ccalls to dynamic pointers (#317)
1 parent 98c5a13 commit 4773269

File tree

2 files changed

+23
-29
lines changed

2 files changed

+23
-29
lines changed

src/optimize.jl

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -163,37 +163,14 @@ function optimize!(code::CodeInfo, scope)
163163
# Check for :llvmcall
164164
arg1 = stmt.args[1]
165165
if (arg1 == :llvmcall || lookup_stmt(code.code, arg1) == Base.llvmcall) && isempty(sparams) && scope isa Method
166-
uuid = uuid1(rng)
167-
ustr = replace(string(uuid), '-'=>'_')
168-
methname = Symbol("llvmcall_", ustr)
169166
nargs = length(stmt.args)-4
170-
delete_idx = build_compiled_call!(stmt, methname, Base.llvmcall, stmt.args[2:4], code, idx, nargs, sparams, evalmod)
167+
delete_idx = build_compiled_call!(stmt, Base.llvmcall, stmt.args[2:4], code, idx, nargs, sparams, evalmod)
171168
push!(foreigncalls_idx, idx)
172169
append!(delete_idxs, delete_idx)
173170
end
174171
elseif isexpr(stmt, :foreigncall) && scope isa Method
175-
f = lookup_stmt(code.code, stmt.args[1])
176-
if isa(f, Ptr)
177-
f = string(uuid1(rng))
178-
elseif isexpr(f, :call)
179-
length(f.args) == 3 || continue
180-
if !(f.args[1] === tuple || f.args[1] == :($(QuoteNode(tuple))))
181-
continue
182-
end
183-
lib = f.args[3] isa String ? f.args[3] : f.args[3].value
184-
prefix = f.args[2] isa String ? f.args[2] : f.args[2].value
185-
f = Symbol(prefix, '_', lib)
186-
end
187-
# Punt on non literal ccall arguments for now
188-
if !(isa(f, String) || isa(f, Symbol) || isa(f, Ptr))
189-
continue
190-
end
191-
# TODO: Only compile one ccall per call and argument types
192-
uuid = uuid1(rng)
193-
ustr = replace(string(uuid), '-'=>'_')
194-
methname = Symbol("ccall", '_', f, '_', ustr)
195172
nargs = stmt.args[5]
196-
delete_idx = build_compiled_call!(stmt, methname, :ccall, stmt.args[1:3], code, idx, nargs, sparams, evalmod)
173+
delete_idx = build_compiled_call!(stmt, :ccall, stmt.args[1:3], code, idx, nargs, sparams, evalmod)
197174
push!(foreigncalls_idx, idx)
198175
append!(delete_idxs, delete_idx)
199176
end
@@ -250,7 +227,7 @@ function parametric_type_to_expr(t::Type)
250227
end
251228

252229
# Handle :llvmcall & :foreigncall (issue #28)
253-
function build_compiled_call!(stmt, methname, fcall, typargs, code, idx, nargs, sparams, evalmod)
230+
function build_compiled_call!(stmt, fcall, typargs, code, idx, nargs, sparams, evalmod)
254231
TVal = evalmod == Core.Compiler ? Core.Compiler.Val : Val
255232
argnames = Any[Symbol("arg", string(i)) for i = 1:nargs]
256233
delete_idx = Int[]
@@ -292,27 +269,39 @@ function build_compiled_call!(stmt, methname, fcall, typargs, code, idx, nargs,
292269
cfunc, RetType, ArgType = @lookup(frame, stmt.args[2]), @lookup(frame, stmt.args[3]), @lookup(frame, stmt.args[4])
293270
args = stmt.args[5:end]
294271
end
272+
dynamic_ccall = false
295273
if isa(cfunc, Expr) # specification by tuple, e.g., (:clock, "libc")
296274
cfunc = eval(cfunc)
297275
end
298276
if isa(cfunc, Symbol)
299277
cfunc = QuoteNode(cfunc)
278+
elseif isa(cfunc, String) || isa(cfunc, Ptr) || isa(cfunc, Tuple)
279+
# do nothing
280+
else
281+
dynamic_ccall = true
282+
oldcfunc = cfunc
283+
cfunc = gensym("ptr")
300284
end
301285
if isa(RetType, SimpleVector)
302286
@assert length(RetType) == 1
303287
RetType = RetType[1]
304288
end
305-
cc_key = (cfunc, RetType, ArgType, evalmod) # compiled call key
289+
# When the ccall is dynamic we pass the pointer as an argument so can reuse the function
290+
cc_key = (dynamic_ccall ? :ptr : cfunc, RetType, ArgType, evalmod) # compiled call key
306291
f = get(compiled_calls, cc_key, nothing)
307292
if f === nothing
308293
if fcall == :ccall
309294
ArgType = Expr(:tuple, [parametric_type_to_expr(t) for t in ArgType]...)
310295
end
311296
RetType = parametric_type_to_expr(RetType)
312297
wrapargs = copy(argnames)
298+
if dynamic_ccall
299+
pushfirst!(wrapargs, cfunc)
300+
end
313301
for sparam in sparams
314302
push!(wrapargs, :(::$TVal{$sparam}))
315303
end
304+
methname = gensym("compiledcall")
316305
if stmt.args[4] == :(:llvmcall)
317306
def = :(
318307
function $methname($(wrapargs...)) where {$(sparams...)}
@@ -335,6 +324,9 @@ function build_compiled_call!(stmt, methname, fcall, typargs, code, idx, nargs,
335324
stmt.args[1] = QuoteNode(f)
336325
stmt.head = :call
337326
deleteat!(stmt.args, 2:length(stmt.args))
327+
if dynamic_ccall
328+
push!(stmt.args, oldcfunc)
329+
end
338330
append!(stmt.args, args)
339331
for i in 1:length(sparams)
340332
push!(stmt.args, :($TVal($(Expr(:static_parameter, i)))))

test/interpret.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,8 @@ function call_cf()
480480
ccall(cf[1], Int, (Int, Int), 1, 2)
481481
end
482482
@test (@interpret call_cf()) == call_cf()
483+
frame = JuliaInterpreter.enter_call(call_cf)
484+
@test frame.framecode.methodtables[2] == Compiled()
483485

484486
# ccall with integer static parameter
485487
f_N() = Array{Float64, 4}(undef, 1, 3, 2, 1)
@@ -490,8 +492,8 @@ f() = ccall((:clock, "libc"), Int32, ())
490492
try @interpret f()
491493
catch
492494
end
493-
compiled_calls = names(JuliaInterpreter.CompiledCalls; all=true)
494-
@test any(x -> startswith(string(x), "ccall_clock_libc"), compiled_calls)
495+
frame = JuliaInterpreter.enter_call(f)
496+
@test frame.framecode.methodtables[1] == Compiled()
495497

496498
# https://github.com/JuliaDebug/JuliaInterpreter.jl/issues/194
497499
f() = Meta.lower(Main, Meta.parse("(a=1,0)"))

0 commit comments

Comments
 (0)