@@ -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,58 @@ 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+ # Required by Revise, but otherwise deprecated
196+ # The depwarn is currently disabled because Revise's tests check for empty warning logs
197+ function is_assignment_like (@nospecialize stmt)
198+ # Base.depwarn("is_assignment_like is deprecated, switch to `LoweredCodeUtils.get_lhs_rhs`", :is_assignment_like)
199+ return isexpr (stmt, :(= )) || isexpr (stmt, :const , 2 )
200+ end
201+
202+ function get_lhs_rhs (@nospecialize stmt)
203+ if isexpr (stmt, :(= ))
204+ return Pair {Any,Any} (stmt. args[1 ], stmt. args[2 ])
205+ elseif isexpr (stmt, :const ) && length (stmt. args) == 2
206+ return Pair {Any,Any} (stmt. args[1 ], stmt. args[2 ])
207+ elseif isexpr (stmt, :call ) && length (stmt. args) == 4
208+ f = stmt. args[1 ]
209+ if is_global_ref_egal (f, :setglobal! , Core. setglobal!)
210+ mod = stmt. args[2 ]
211+ mod isa Module || return nothing
212+ name = stmt. args[3 ]
213+ if name isa QuoteNode
214+ name = name. value
215+ end
216+ name isa Symbol || return nothing
217+ lhs = GlobalRef (mod, name)
218+ return Pair {Any,Any} (lhs, stmt. args[4 ])
219+ end
220+ end
221+ return nothing
222+ end
195223
196224function direct_links! (cl:: CodeLinks , src:: CodeInfo )
197225 # Utility for when a stmt itself contains a CodeInfo
198226 function add_inner! (cl:: CodeLinks , icl:: CodeLinks , idx)
199227 for (name, _) in icl. nameassigns
200- assigns = get (cl. nameassigns, name, nothing )
201- if assigns === nothing
202- cl. nameassigns[name] = assigns = Int[]
203- end
228+ assigns = get! (Vector{Int}, cl. nameassigns, name)
204229 push! (assigns, idx)
205230 end
206231 for (name, _) in icl. namesuccs
207- succs = get (cl. namesuccs, name, nothing )
208- if succs === nothing
209- cl. namesuccs[name] = succs = Links ()
210- end
232+ succs = get! (Links, cl. namesuccs, name)
211233 push! (succs. ssas, idx)
212234 end
213235 end
214236
215237 P = Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}
216238
217239 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 ] )
240+ if isexpr (stmt, :thunk ) && (arg1 = stmt. args[1 ]; arg1 isa CodeInfo)
241+ icl = CodeLinks (cl. thismod, arg1 )
220242 add_inner! (cl, icl, i)
221243 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 ] )
244+ elseif isexpr (stmt, :method )
245+ if length (stmt. args) === 3 && (arg3 = stmt. args[3 ]; arg3 isa CodeInfo)
246+ icl = CodeLinks (cl. thismod, arg3 )
225247 add_inner! (cl, icl, i)
226248 end
227249 name = stmt. args[1 ]
@@ -234,10 +256,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
234256 cl. nameassigns[name] = assign = Int[]
235257 end
236258 push! (assign, i)
237- targetstore = get (cl. namepreds, name, nothing )
238- if targetstore === nothing
239- cl. namepreds[name] = targetstore = Links ()
240- end
259+ targetstore = get! (Links, cl. namepreds, name)
241260 target = P (name, targetstore)
242261 add_links! (target, stmt, cl)
243262 elseif name in (nothing , false )
@@ -247,10 +266,10 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
247266 end
248267 rhs = stmt
249268 target = P (SSAValue (i), cl. ssapreds[i])
250- elseif is_assignment_like ( stmt)
269+ elseif (lhs_rhs = get_lhs_rhs ( stmt); lhs_rhs != = nothing )
251270 # An assignment
252271 stmt = stmt:: Expr
253- lhs, rhs = stmt . args[ 1 ], stmt . args[ 2 ]
272+ lhs, rhs = lhs_rhs
254273 if @issslotnum (lhs)
255274 lhs = lhs:: AnySlotNumber
256275 id = lhs. id
@@ -260,10 +279,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
260279 if isa (lhs, Symbol)
261280 lhs = GlobalRef (cl. thismod, lhs)
262281 end
263- targetstore = get (cl. namepreds, lhs, nothing )
264- if targetstore === nothing
265- cl. namepreds[lhs] = targetstore = Links ()
266- end
282+ targetstore = get! (Links, cl. namepreds, lhs)
267283 target = P (lhs, targetstore)
268284 assign = get (cl. nameassigns, lhs, nothing )
269285 if assign === nothing
@@ -299,23 +315,35 @@ function add_links!(target::Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}, @n
299315 stmt = GlobalRef (cl. thismod, stmt)
300316 end
301317 push! (targetstore, stmt)
302- namestore = get (cl. namesuccs, stmt, nothing )
303- if namestore === nothing
304- cl. namesuccs[stmt] = namestore = Links ()
305- end
318+ namestore = get! (Links, cl. namesuccs, stmt)
306319 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)
320+ elseif isa (stmt, Expr)
321+ if stmt. head === :globaldecl
322+ for i = 1 : length (stmt. args)
323+ a = stmt. args[i]
324+ if a isa GlobalRef
325+ namestore = get! (Links, cl. namepreds, a) # TODO should this information be tracked in the separate `cl.namedecls` store?
326+ push! (namestore, targetid)
327+ if targetid isa SSAValue
328+ push! (namestore, SSAValue (targetid. id+ 1 )) # +1 for :latestworld
329+ end
330+ else
331+ add_links! (target, a, cl)
332+ end
333+ end
334+ elseif stmt. head != = :copyast
335+ stmt = stmt:: Expr
336+ arng = 1 : length (stmt. args)
337+ if stmt. head === :call
338+ f = stmt. args[1 ]
339+ if ! @isssa (f) && ! @issslotnum (f)
340+ # Avoid putting named callees on the namestore
341+ arng = 2 : length (stmt. args)
342+ end
343+ end
344+ for i in arng
345+ add_links! (target, stmt. args[i], cl)
315346 end
316- end
317- for i in arng
318- add_links! (target, stmt. args[i], cl)
319347 end
320348 elseif stmt isa Core. GotoIfNot
321349 add_links! (target, stmt. cond, cl)
@@ -362,7 +390,6 @@ struct Variable
362390 preds:: Vector{Int}
363391 succs:: Vector{Int}
364392end
365- Variable () = Variable (Int[], Int[], Int[])
366393
367394function Base. show (io:: IO , v:: Variable )
368395 print (io, " assigned on " , showempty (v. assigned))
@@ -423,9 +450,9 @@ function CodeEdges(src::CodeInfo, cl::CodeLinks)
423450 emptylist = Int[]
424451 for (i, stmt) in enumerate (src. code)
425452 # Identify line predecents for slots and named variables
426- if is_assignment_like ( stmt)
453+ if (lhs_rhs = get_lhs_rhs ( stmt); lhs_rhs != = nothing )
427454 stmt = stmt:: Expr
428- lhs = stmt . args[ 1 ]
455+ lhs, _ = lhs_rhs
429456 # Mark predecessors and successors of this line by following ssas & named assignments
430457 if @issslotnum (lhs)
431458 lhs = lhs:: AnySlotNumber
@@ -611,7 +638,7 @@ function exclude_named_typedefs(src::CodeInfo, edges::CodeEdges)
611638 i = 1
612639 nstmts = length (src. code)
613640 while i <= nstmts
614- stmt = rhs (src. code[i])
641+ stmt = getrhs (src. code[i])
615642 if istypedef (stmt) && ! isanonymous_typedef (stmt:: Expr )
616643 r = typedef_range (src, i)
617644 pushall! (norequire, r)
@@ -715,10 +742,17 @@ function add_succs!(isrequired, idx, edges::CodeEdges, succs, norequire)
715742 end
716743 return chngd
717744end
718- function add_obj! (isrequired, objs, obj, edges:: CodeEdges , norequire)
745+ function add_obj! (isrequired, objs, obj:: GlobalRef , edges:: CodeEdges , norequire)
719746 chngd = false
747+ for p in edges. byname[obj]. preds
748+ p ∈ norequire && continue
749+ isrequired[p] && continue
750+ isrequired[p] = true
751+ chngd = true
752+ end
720753 for d in edges. byname[obj]. assigned
721754 d ∈ norequire && continue
755+ isrequired[d] && continue
722756 isrequired[d] || add_preds! (isrequired, d, edges, norequire)
723757 isrequired[d] = true
724758 chngd = true
@@ -871,7 +905,7 @@ function find_typedefs(src::CodeInfo)
871905 i = 1
872906 nstmts = length (src. code)
873907 while i <= nstmts
874- stmt = rhs (src. code[i])
908+ stmt = getrhs (src. code[i])
875909 if istypedef (stmt) && ! isanonymous_typedef (stmt:: Expr )
876910 stmt = stmt:: Expr
877911 r = typedef_range (src, i)
@@ -972,8 +1006,8 @@ function add_inplace!(isrequired, src, edges, norequire)
9721006 for k in edges. preds[j]
9731007 isrequired[k] || continue
9741008 predstmt = src. code[k]
975- if is_assignment_like ( predstmt)
976- lhs = predstmt . args[ 1 ]
1009+ if (lhs_rhs = get_lhs_rhs ( predstmt); lhs_rhs != = nothing )
1010+ lhs, _ = lhs_rhs
9771011 if @issslotnum (lhs) && lhs. id == id
9781012 changed |= mark_if_inplace (stmt, j)
9791013 break
@@ -1056,7 +1090,7 @@ function print_with_code(io::IO, src::CodeInfo, isrequired::AbstractVector{Bool}
10561090 preprint (:: IO ) = nothing
10571091 preprint (io:: IO , idx:: Int ) = (c = isrequired[idx]; printstyled (io, lpad (idx, nd), ' ' , c ? " t " : " f " ; color = c ? :cyan : :plain ))
10581092 postprint (:: IO ) = nothing
1059- postprint (io :: IO , idx:: Int , bbchanged:: Bool ) = nothing
1093+ postprint (:: IO , idx:: Int , bbchanged:: Bool ) = nothing
10601094
10611095 print_with_code (preprint, postprint, io, src)
10621096end
0 commit comments