@@ -163,8 +163,10 @@ function postprint_linelinks(io::IO, idx::Int, src::CodeInfo, cl::CodeLinks, bbc
163163 printstyled (io, bbchanged ? " " : " │" , color= :light_black )
164164 printstyled (io, " # " , color= :yellow )
165165 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)
168170 if @issslotnum (lhs)
169171 # id = lhs.id
170172 # preds, succs = cl.slotpreds[id], cl.slotsuccs[id]
@@ -190,38 +192,51 @@ function namedkeys(cl::CodeLinks)
190192 return ukeys
191193end
192194
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
195216
196217function direct_links! (cl:: CodeLinks , src:: CodeInfo )
197218 # Utility for when a stmt itself contains a CodeInfo
198219 function add_inner! (cl:: CodeLinks , icl:: CodeLinks , idx)
199220 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)
204222 push! (assigns, idx)
205223 end
206224 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)
211226 push! (succs. ssas, idx)
212227 end
213228 end
214229
215230 P = Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}
216231
217232 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 )
220235 add_inner! (cl, icl, i)
221236 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 )
225240 add_inner! (cl, icl, i)
226241 end
227242 name = stmt. args[1 ]
@@ -234,10 +249,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
234249 cl. nameassigns[name] = assign = Int[]
235250 end
236251 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)
241253 target = P (name, targetstore)
242254 add_links! (target, stmt, cl)
243255 elseif name in (nothing , false )
@@ -247,10 +259,10 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
247259 end
248260 rhs = stmt
249261 target = P (SSAValue (i), cl. ssapreds[i])
250- elseif is_assignment_like ( stmt)
262+ elseif (lhs_rhs = get_lhs_rhs ( stmt); lhs_rhs != = nothing )
251263 # An assignment
252264 stmt = stmt:: Expr
253- lhs, rhs = stmt . args[ 1 ], stmt . args[ 2 ]
265+ lhs, rhs = lhs_rhs
254266 if @issslotnum (lhs)
255267 lhs = lhs:: AnySlotNumber
256268 id = lhs. id
@@ -260,10 +272,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
260272 if isa (lhs, Symbol)
261273 lhs = GlobalRef (cl. thismod, lhs)
262274 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)
267276 target = P (lhs, targetstore)
268277 assign = get (cl. nameassigns, lhs, nothing )
269278 if assign === nothing
@@ -299,23 +308,35 @@ function add_links!(target::Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}, @n
299308 stmt = GlobalRef (cl. thismod, stmt)
300309 end
301310 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)
306312 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)
315339 end
316- end
317- for i in arng
318- add_links! (target, stmt. args[i], cl)
319340 end
320341 elseif stmt isa Core. GotoIfNot
321342 add_links! (target, stmt. cond, cl)
@@ -362,7 +383,6 @@ struct Variable
362383 preds:: Vector{Int}
363384 succs:: Vector{Int}
364385end
365- Variable () = Variable (Int[], Int[], Int[])
366386
367387function Base. show (io:: IO , v:: Variable )
368388 print (io, " assigned on " , showempty (v. assigned))
@@ -423,9 +443,9 @@ function CodeEdges(src::CodeInfo, cl::CodeLinks)
423443 emptylist = Int[]
424444 for (i, stmt) in enumerate (src. code)
425445 # 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 )
427447 stmt = stmt:: Expr
428- lhs = stmt . args[ 1 ]
448+ lhs, _ = lhs_rhs
429449 # Mark predecessors and successors of this line by following ssas & named assignments
430450 if @issslotnum (lhs)
431451 lhs = lhs:: AnySlotNumber
@@ -611,7 +631,7 @@ function exclude_named_typedefs(src::CodeInfo, edges::CodeEdges)
611631 i = 1
612632 nstmts = length (src. code)
613633 while i <= nstmts
614- stmt = rhs (src. code[i])
634+ stmt = getrhs (src. code[i])
615635 if istypedef (stmt) && ! isanonymous_typedef (stmt:: Expr )
616636 r = typedef_range (src, i)
617637 pushall! (norequire, r)
@@ -715,10 +735,17 @@ function add_succs!(isrequired, idx, edges::CodeEdges, succs, norequire)
715735 end
716736 return chngd
717737end
718- function add_obj! (isrequired, objs, obj, edges:: CodeEdges , norequire)
738+ function add_obj! (isrequired, objs, obj:: GlobalRef , edges:: CodeEdges , norequire)
719739 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
720746 for d in edges. byname[obj]. assigned
721747 d ∈ norequire && continue
748+ isrequired[d] && continue
722749 isrequired[d] || add_preds! (isrequired, d, edges, norequire)
723750 isrequired[d] = true
724751 chngd = true
@@ -871,7 +898,7 @@ function find_typedefs(src::CodeInfo)
871898 i = 1
872899 nstmts = length (src. code)
873900 while i <= nstmts
874- stmt = rhs (src. code[i])
901+ stmt = getrhs (src. code[i])
875902 if istypedef (stmt) && ! isanonymous_typedef (stmt:: Expr )
876903 stmt = stmt:: Expr
877904 r = typedef_range (src, i)
@@ -972,8 +999,8 @@ function add_inplace!(isrequired, src, edges, norequire)
972999 for k in edges. preds[j]
9731000 isrequired[k] || continue
9741001 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
9771004 if @issslotnum (lhs) && lhs. id == id
9781005 changed |= mark_if_inplace (stmt, j)
9791006 break
@@ -1056,7 +1083,7 @@ function print_with_code(io::IO, src::CodeInfo, isrequired::AbstractVector{Bool}
10561083 preprint (:: IO ) = nothing
10571084 preprint (io:: IO , idx:: Int ) = (c = isrequired[idx]; printstyled (io, lpad (idx, nd), ' ' , c ? " t " : " f " ; color = c ? :cyan : :plain ))
10581085 postprint (:: IO ) = nothing
1059- postprint (io :: IO , idx:: Int , bbchanged:: Bool ) = nothing
1086+ postprint (:: IO , idx:: Int , bbchanged:: Bool ) = nothing
10601087
10611088 print_with_code (preprint, postprint, io, src)
10621089end
0 commit comments