@@ -163,8 +163,10 @@ function postprint_linelinks(io::IO, idx::Int, src::CodeInfo, cl::CodeLinks, bbc
163
163
printstyled (io, bbchanged ? " " : " │" , color= :light_black )
164
164
printstyled (io, " # " , color= :yellow )
165
165
stmt = src. code[idx]
166
- if is_assignment_like (stmt)
167
- lhs = normalize_defsig (stmt. args[1 ], cl. thismod)
166
+ lhs_rhs = get_lhs_rhs (stmt)
167
+ if lhs_rhs != = nothing
168
+ lhs, _ = lhs_rhs
169
+ lhs = normalize_defsig (lhs, cl. thismod)
168
170
if @issslotnum (lhs)
169
171
# id = lhs.id
170
172
# preds, succs = cl.slotpreds[id], cl.slotsuccs[id]
@@ -190,38 +192,51 @@ function namedkeys(cl::CodeLinks)
190
192
return ukeys
191
193
end
192
194
193
- is_assignment_like (stmt:: Expr ) = isexpr (stmt, :(= )) || (isexpr (stmt, :const ) && length (stmt. args) == 2 )
194
- is_assignment_like (@nospecialize stmt) = false
195
+ function get_lhs_rhs (@nospecialize stmt)
196
+ if isexpr (stmt, :(= ))
197
+ return Pair {Any,Any} (stmt. args[1 ], stmt. args[2 ])
198
+ elseif isexpr (stmt, :const ) && length (stmt. args) == 2
199
+ return Pair {Any,Any} (stmt. args[1 ], stmt. args[2 ])
200
+ elseif isexpr (stmt, :call ) && length (stmt. args) == 4
201
+ f = stmt. args[1 ]
202
+ if isa (f, GlobalRef) && f. name === :setglobal!
203
+ mod = stmt. args[2 ]
204
+ mod isa Module || return nothing
205
+ name = stmt. args[3 ]
206
+ if name isa QuoteNode
207
+ name = name. value
208
+ end
209
+ name isa Symbol || return nothing
210
+ lhs = GlobalRef (mod, name)
211
+ return Pair {Any,Any} (lhs, stmt. args[4 ])
212
+ end
213
+ end
214
+ return nothing
215
+ end
195
216
196
217
function direct_links! (cl:: CodeLinks , src:: CodeInfo )
197
218
# Utility for when a stmt itself contains a CodeInfo
198
219
function add_inner! (cl:: CodeLinks , icl:: CodeLinks , idx)
199
220
for (name, _) in icl. nameassigns
200
- assigns = get (cl. nameassigns, name, nothing )
201
- if assigns === nothing
202
- cl. nameassigns[name] = assigns = Int[]
203
- end
221
+ assigns = get! (Vector{Int}, cl. nameassigns, name)
204
222
push! (assigns, idx)
205
223
end
206
224
for (name, _) in icl. namesuccs
207
- succs = get (cl. namesuccs, name, nothing )
208
- if succs === nothing
209
- cl. namesuccs[name] = succs = Links ()
210
- end
225
+ succs = get! (Links, cl. namesuccs, name)
211
226
push! (succs. ssas, idx)
212
227
end
213
228
end
214
229
215
230
P = Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}
216
231
217
232
for (i, stmt) in enumerate (src. code)
218
- if isexpr (stmt, :thunk ) && isa ( stmt. args[1 ], CodeInfo)
219
- icl = CodeLinks (cl. thismod, stmt . args[ 1 ] )
233
+ if isexpr (stmt, :thunk ) && (arg1 = stmt. args[1 ]; arg1 isa CodeInfo)
234
+ icl = CodeLinks (cl. thismod, arg1 )
220
235
add_inner! (cl, icl, i)
221
236
continue
222
- elseif isa (stmt, Expr) && stmt . head ∈ trackedheads
223
- if stmt . head === :method && length (stmt. args) === 3 && isa ( stmt. args[3 ], CodeInfo)
224
- icl = CodeLinks (cl. thismod, stmt . args[ 3 ] )
237
+ elseif isexpr (stmt, :method )
238
+ if length (stmt. args) === 3 && (arg3 = stmt. args[3 ]; arg3 isa CodeInfo)
239
+ icl = CodeLinks (cl. thismod, arg3 )
225
240
add_inner! (cl, icl, i)
226
241
end
227
242
name = stmt. args[1 ]
@@ -234,10 +249,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
234
249
cl. nameassigns[name] = assign = Int[]
235
250
end
236
251
push! (assign, i)
237
- targetstore = get (cl. namepreds, name, nothing )
238
- if targetstore === nothing
239
- cl. namepreds[name] = targetstore = Links ()
240
- end
252
+ targetstore = get! (Links, cl. namepreds, name)
241
253
target = P (name, targetstore)
242
254
add_links! (target, stmt, cl)
243
255
elseif name in (nothing , false )
@@ -247,10 +259,10 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
247
259
end
248
260
rhs = stmt
249
261
target = P (SSAValue (i), cl. ssapreds[i])
250
- elseif is_assignment_like ( stmt)
262
+ elseif (lhs_rhs = get_lhs_rhs ( stmt); lhs_rhs != = nothing )
251
263
# An assignment
252
264
stmt = stmt:: Expr
253
- lhs, rhs = stmt . args[ 1 ], stmt . args[ 2 ]
265
+ lhs, rhs = lhs_rhs
254
266
if @issslotnum (lhs)
255
267
lhs = lhs:: AnySlotNumber
256
268
id = lhs. id
@@ -260,10 +272,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
260
272
if isa (lhs, Symbol)
261
273
lhs = GlobalRef (cl. thismod, lhs)
262
274
end
263
- targetstore = get (cl. namepreds, lhs, nothing )
264
- if targetstore === nothing
265
- cl. namepreds[lhs] = targetstore = Links ()
266
- end
275
+ targetstore = get! (Links, cl. namepreds, lhs)
267
276
target = P (lhs, targetstore)
268
277
assign = get (cl. nameassigns, lhs, nothing )
269
278
if assign === nothing
@@ -299,23 +308,35 @@ function add_links!(target::Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}, @n
299
308
stmt = GlobalRef (cl. thismod, stmt)
300
309
end
301
310
push! (targetstore, stmt)
302
- namestore = get (cl. namesuccs, stmt, nothing )
303
- if namestore === nothing
304
- cl. namesuccs[stmt] = namestore = Links ()
305
- end
311
+ namestore = get! (Links, cl. namesuccs, stmt)
306
312
push! (namestore, targetid)
307
- elseif isa (stmt, Expr) && stmt. head != = :copyast
308
- stmt = stmt:: Expr
309
- arng = 1 : length (stmt. args)
310
- if stmt. head === :call
311
- f = stmt. args[1 ]
312
- if ! @isssa (f) && ! @issslotnum (f)
313
- # Avoid putting named callees on the namestore
314
- arng = 2 : length (stmt. args)
313
+ elseif isa (stmt, Expr)
314
+ if stmt. head === :globaldecl
315
+ for i = 1 : length (stmt. args)
316
+ a = stmt. args[i]
317
+ if a isa GlobalRef
318
+ namestore = get! (Links, cl. namepreds, a) # TODO should this information be tracked in the separate `cl.namedecls` store?
319
+ push! (namestore, targetid)
320
+ if targetid isa SSAValue
321
+ push! (namestore, SSAValue (targetid. id+ 1 )) # +1 for :latestworld
322
+ end
323
+ else
324
+ add_links! (target, a, cl)
325
+ end
326
+ end
327
+ elseif stmt. head != = :copyast
328
+ stmt = stmt:: Expr
329
+ arng = 1 : length (stmt. args)
330
+ if stmt. head === :call
331
+ f = stmt. args[1 ]
332
+ if ! @isssa (f) && ! @issslotnum (f)
333
+ # Avoid putting named callees on the namestore
334
+ arng = 2 : length (stmt. args)
335
+ end
336
+ end
337
+ for i in arng
338
+ add_links! (target, stmt. args[i], cl)
315
339
end
316
- end
317
- for i in arng
318
- add_links! (target, stmt. args[i], cl)
319
340
end
320
341
elseif stmt isa Core. GotoIfNot
321
342
add_links! (target, stmt. cond, cl)
@@ -362,7 +383,6 @@ struct Variable
362
383
preds:: Vector{Int}
363
384
succs:: Vector{Int}
364
385
end
365
- Variable () = Variable (Int[], Int[], Int[])
366
386
367
387
function Base. show (io:: IO , v:: Variable )
368
388
print (io, " assigned on " , showempty (v. assigned))
@@ -423,9 +443,9 @@ function CodeEdges(src::CodeInfo, cl::CodeLinks)
423
443
emptylist = Int[]
424
444
for (i, stmt) in enumerate (src. code)
425
445
# Identify line predecents for slots and named variables
426
- if is_assignment_like ( stmt)
446
+ if (lhs_rhs = get_lhs_rhs ( stmt); lhs_rhs != = nothing )
427
447
stmt = stmt:: Expr
428
- lhs = stmt . args[ 1 ]
448
+ lhs, _ = lhs_rhs
429
449
# Mark predecessors and successors of this line by following ssas & named assignments
430
450
if @issslotnum (lhs)
431
451
lhs = lhs:: AnySlotNumber
@@ -611,7 +631,7 @@ function exclude_named_typedefs(src::CodeInfo, edges::CodeEdges)
611
631
i = 1
612
632
nstmts = length (src. code)
613
633
while i <= nstmts
614
- stmt = rhs (src. code[i])
634
+ stmt = getrhs (src. code[i])
615
635
if istypedef (stmt) && ! isanonymous_typedef (stmt:: Expr )
616
636
r = typedef_range (src, i)
617
637
pushall! (norequire, r)
@@ -715,10 +735,17 @@ function add_succs!(isrequired, idx, edges::CodeEdges, succs, norequire)
715
735
end
716
736
return chngd
717
737
end
718
- function add_obj! (isrequired, objs, obj, edges:: CodeEdges , norequire)
738
+ function add_obj! (isrequired, objs, obj:: GlobalRef , edges:: CodeEdges , norequire)
719
739
chngd = false
740
+ for p in edges. byname[obj]. preds
741
+ p ∈ norequire && continue
742
+ isrequired[p] && continue
743
+ isrequired[p] = true
744
+ chngd = true
745
+ end
720
746
for d in edges. byname[obj]. assigned
721
747
d ∈ norequire && continue
748
+ isrequired[d] && continue
722
749
isrequired[d] || add_preds! (isrequired, d, edges, norequire)
723
750
isrequired[d] = true
724
751
chngd = true
@@ -871,7 +898,7 @@ function find_typedefs(src::CodeInfo)
871
898
i = 1
872
899
nstmts = length (src. code)
873
900
while i <= nstmts
874
- stmt = rhs (src. code[i])
901
+ stmt = getrhs (src. code[i])
875
902
if istypedef (stmt) && ! isanonymous_typedef (stmt:: Expr )
876
903
stmt = stmt:: Expr
877
904
r = typedef_range (src, i)
@@ -972,8 +999,8 @@ function add_inplace!(isrequired, src, edges, norequire)
972
999
for k in edges. preds[j]
973
1000
isrequired[k] || continue
974
1001
predstmt = src. code[k]
975
- if is_assignment_like ( predstmt)
976
- lhs = predstmt . args[ 1 ]
1002
+ if (lhs_rhs = get_lhs_rhs ( predstmt); lhs_rhs != = nothing )
1003
+ lhs, _ = lhs_rhs
977
1004
if @issslotnum (lhs) && lhs. id == id
978
1005
changed |= mark_if_inplace (stmt, j)
979
1006
break
@@ -1056,7 +1083,7 @@ function print_with_code(io::IO, src::CodeInfo, isrequired::AbstractVector{Bool}
1056
1083
preprint (:: IO ) = nothing
1057
1084
preprint (io:: IO , idx:: Int ) = (c = isrequired[idx]; printstyled (io, lpad (idx, nd), ' ' , c ? " t " : " f " ; color = c ? :cyan : :plain ))
1058
1085
postprint (:: IO ) = nothing
1059
- postprint (io :: IO , idx:: Int , bbchanged:: Bool ) = nothing
1086
+ postprint (:: IO , idx:: Int , bbchanged:: Bool ) = nothing
1060
1087
1061
1088
print_with_code (preprint, postprint, io, src)
1062
1089
end
0 commit comments