1
- const calllike = (:call , :foreigncall )
2
-
3
1
const compiled_calls = Dict {Any,Any} ()
4
2
5
- function extract_inner_call! (stmt:: Expr , idx, once:: Bool = false )
6
- (stmt. head === :toplevel || stmt. head === :thunk ) && return nothing
7
- once |= stmt. head ∈ calllike
8
- for (i, a) in enumerate (stmt. args)
9
- isa (a, Expr) || continue
10
- # Make sure we don't "damage" special syntax that requires literals
11
- if i == 1 && stmt. head === :foreigncall
12
- continue
13
- end
14
- if i == 2 && stmt. head === :call && stmt. args[1 ] === :cglobal
15
- continue
16
- end
17
- ret = extract_inner_call! (a, idx, once) # doing this first extracts innermost calls
18
- ret != = nothing && return ret
19
- iscalllike = a. head ∈ calllike
20
- if once && iscalllike
21
- stmt. args[i] = NewSSAValue (idx)
22
- return a
23
- end
24
- end
25
- return nothing
26
- end
27
-
28
- function replace_ssa (stmt:: Expr , ssalookup)
29
- return Expr (stmt. head, Any[
30
- if isa (a, SSAValue)
31
- SSAValue (ssalookup[a. id])
32
- elseif isa (a, NewSSAValue)
33
- SSAValue (a. id)
34
- elseif isa (a, Expr)
35
- replace_ssa (a, ssalookup)
36
- else
37
- a
38
- end
39
- for a in stmt. args
40
- ]. .. )
41
- end
42
-
43
- function renumber_ssa! (stmts:: Vector{Any} , ssalookup)
44
- # When updating jumps, when lines get split into multiple lines
45
- # (see "Un-nest :call expressions" below), we need to jump to the first of them.
46
- # Consequently we use the previous "old-code" offset and add one.
47
- # Fixes #455.
48
- jumplookup (l, idx) = idx > 1 ? l[idx- 1 ] + 1 : idx
49
-
50
- for (i, stmt) in enumerate (stmts)
51
- if isa (stmt, GotoNode)
52
- stmts[i] = GotoNode (jumplookup (ssalookup, stmt. label))
53
- elseif isa (stmt, SSAValue)
54
- stmts[i] = SSAValue (ssalookup[stmt. id])
55
- elseif isa (stmt, NewSSAValue)
56
- stmts[i] = SSAValue (stmt. id)
57
- elseif isexpr (stmt, :enter )
58
- stmt. args[end ] = jumplookup (ssalookup, stmt. args[1 ]:: Int )
59
- elseif isa (stmt, Expr)
60
- stmts[i] = replace_ssa (stmt, ssalookup)
61
- elseif isa (stmt, GotoIfNot)
62
- cond = stmt. cond
63
- if isa (cond, SSAValue)
64
- cond = SSAValue (ssalookup[cond. id])
65
- end
66
- stmts[i] = GotoIfNot (cond, jumplookup (ssalookup, stmt. dest))
67
- elseif isa (stmt, ReturnNode)
68
- val = stmt. val
69
- if isa (val, SSAValue)
70
- stmts[i] = ReturnNode (SSAValue (ssalookup[val. id]))
71
- end
72
- elseif @static (isdefined (Core. IR, :EnterNode ) && true ) && isa (stmt, Core. IR. EnterNode)
73
- stmts[i] = Core. IR. EnterNode (jumplookup (ssalookup, stmt. catch_dest))
74
- end
75
- end
76
- return stmts
77
- end
78
-
79
- function compute_ssa_mapping_delete_statements! (code:: CodeInfo , stmts:: Vector{Int} )
80
- stmts = unique! (sort! (stmts))
81
- ssalookup = collect (1 : length (codelocs (code)))
82
- cnt = 1
83
- for i in 1 : length (stmts)
84
- start = stmts[i] + 1
85
- stop = i == length (stmts) ? length (codelocs (code)) : stmts[i+ 1 ]
86
- ssalookup[start: stop] .- = cnt
87
- cnt += 1
88
- end
89
- return ssalookup
90
- end
91
-
92
3
# Pre-frame-construction lookup
93
4
function lookup_stmt (stmts, arg)
94
5
if isa (arg, SSAValue)
@@ -179,7 +90,8 @@ function optimize!(code::CodeInfo, scope)
179
90
180
91
# Replace :llvmcall and :foreigncall with compiled variants. See
181
92
# https://github.com/JuliaDebug/JuliaInterpreter.jl/issues/13#issuecomment-464880123
182
- foreigncalls_idx = Int[]
93
+ # Insert the foreigncall wrappers at the updated idxs
94
+ methodtables = Vector {Union{Compiled,DispatchableMethod}} (undef, length (code. code))
183
95
for (idx, stmt) in enumerate (code. code)
184
96
# Foregincalls can be rhs of assignments
185
97
if isexpr (stmt, :(= ))
@@ -192,47 +104,16 @@ function optimize!(code::CodeInfo, scope)
192
104
if (arg1 === :llvmcall || lookup_stmt (code. code, arg1) === Base. llvmcall) && isempty (sparams) && scope isa Method
193
105
# Call via `invokelatest` to avoid compiling it until we need it
194
106
Base. invokelatest (build_compiled_llvmcall!, stmt, code, idx, evalmod)
195
- push! (foreigncalls_idx, idx)
107
+ methodtables[ idx] = Compiled ( )
196
108
end
197
109
elseif stmt. head === :foreigncall && scope isa Method
198
110
# Call via `invokelatest` to avoid compiling it until we need it
199
111
Base. invokelatest (build_compiled_foreigncall!, stmt, code, sparams, evalmod)
200
- push! (foreigncalls_idx, idx)
112
+ methodtables[ idx] = Compiled ( )
201
113
end
202
114
end
203
115
end
204
116
205
- # # Un-nest :call expressions (so that there will be only one :call per line)
206
- # This will allow us to re-use args-buffers rather than having to allocate new ones each time.
207
- old_code, old_codelocs = code. code, codelocs (code)
208
- code. code = new_code = eltype (old_code)[]
209
- code. codelocs = new_codelocs = Int32[]
210
- ssainc = fill (1 , length (old_code))
211
- for (i, stmt) in enumerate (old_code)
212
- loc = old_codelocs[i]
213
- if isa (stmt, Expr)
214
- inner = extract_inner_call! (stmt, length (new_code)+ 1 )
215
- while inner != = nothing
216
- push! (new_code, inner)
217
- push! (new_codelocs, loc)
218
- ssainc[i] += 1
219
- inner = extract_inner_call! (stmt, length (new_code)+ 1 )
220
- end
221
- end
222
- push! (new_code, stmt)
223
- push! (new_codelocs, loc)
224
- end
225
- # Fix all the SSAValues and GotoNodes
226
- ssalookup = cumsum (ssainc)
227
- renumber_ssa! (new_code, ssalookup)
228
- code. ssavaluetypes = length (new_code)
229
-
230
- # Insert the foreigncall wrappers at the updated idxs
231
- methodtables = Vector {Union{Compiled,DispatchableMethod}} (undef, length (code. code))
232
- for idx in foreigncalls_idx
233
- methodtables[ssalookup[idx]] = Compiled ()
234
- end
235
-
236
117
return code, methodtables
237
118
end
238
119
@@ -255,7 +136,7 @@ function parametric_type_to_expr(@nospecialize(t::Type))
255
136
return t
256
137
end
257
138
258
- function build_compiled_llvmcall! (stmt:: Expr , code, idx, evalmod)
139
+ function build_compiled_llvmcall! (stmt:: Expr , code:: CodeInfo , idx:: Int , evalmod:: Module )
259
140
# Run a mini-interpreter to extract the types
260
141
framecode = FrameCode (CompiledCalls, code; optimize= false )
261
142
frame = Frame (framecode, prepare_framedata (framecode, []))
@@ -292,9 +173,8 @@ function build_compiled_llvmcall!(stmt::Expr, code, idx, evalmod)
292
173
append! (stmt. args, args)
293
174
end
294
175
295
-
296
176
# Handle :llvmcall & :foreigncall (issue #28)
297
- function build_compiled_foreigncall! (stmt:: Expr , code, sparams:: Vector{Symbol} , evalmod)
177
+ function build_compiled_foreigncall! (stmt:: Expr , code:: CodeInfo , sparams:: Vector{Symbol} , evalmod:: Module )
298
178
TVal = evalmod == Core. Compiler ? Core. Compiler. Val : Val
299
179
cfunc, RetType, ArgType = lookup_stmt (code. code, stmt. args[1 ]), stmt. args[2 ], stmt. args[3 ]:: SimpleVector
300
180
0 commit comments