@@ -1177,63 +1177,58 @@ end
11771177# and if there is an active successor and the terminator is not a fall-through, then request
11781178# the concretization of that terminator. Additionally, for conditional terminators, a simple
11791179# optimization using post-domination analysis is also performed.
1180- function add_control_flow! (concretize:: BitVector , src:: CodeInfo , cfg:: CFG , postdomtree)
1180+ function add_control_flow! (concretize:: BitVector , src:: CodeInfo , cfg:: CFG , domtree, postdomtree)
11811181 local changed:: Bool = false
11821182 function mark_concretize! (idx:: Int )
11831183 if ! concretize[idx]
1184- concretize[idx] = true
1184+ changed |= concretize[idx] = true
11851185 return true
11861186 end
11871187 return false
11881188 end
1189- nblocks = length (cfg. blocks)
1190- for bbidx = 1 : nblocks
1191- bb = cfg. blocks[bbidx] # forward traversal
1189+ for bbidx = 1 : length (cfg. blocks) # forward traversal
1190+ bb = cfg. blocks[bbidx]
11921191 nsuccs = length (bb. succs)
11931192 if nsuccs == 0
11941193 continue
11951194 elseif nsuccs == 1
1196- terminator_idx = bb. stmts[end ]
1197- if src. code[terminator_idx] isa GotoNode
1198- # If the destination of this `GotoNode` is not active, it's fine to ignore
1199- # the control flow caused by this `GotoNode` and treat it as a fall-through.
1200- # If the block that is fallen through to is active and has a dependency on
1201- # this goto block, then the concretization of this goto block should already
1202- # be requested (at some point of the higher concretization convergence cycle
1203- # of `select_dependencies`), and thus, this `GotoNode` will be concretized.
1204- if any (@view concretize[cfg. blocks[only (bb. succs)]. stmts])
1205- changed |= mark_concretize! (terminator_idx)
1195+ termidx = bb. stmts[end ]
1196+ if src. code[termidx] isa GotoNode
1197+ succ = only (bb. succs)
1198+ if any (@view concretize[cfg. blocks[succ]. stmts])
1199+ dominator = CC. nearest_common_dominator (domtree, bbidx, succ)
1200+ if dominator ≠ succ
1201+ for blk in reachable_blocks (cfg, dominator, succ)
1202+ if blk == dominator || blk == succ
1203+ continue
1204+ end
1205+ if any (@view concretize[cfg. blocks[blk]. stmts])
1206+ mark_concretize! (termidx)
1207+ break
1208+ end
1209+ end
1210+ else
1211+ mark_concretize! (termidx)
1212+ end
12061213 end
12071214 end
1215+ continue # otherwise we can just fall-through
12081216 elseif nsuccs == 2
1209- terminator_idx = bb. stmts[end ]
1210- @assert is_conditional_terminator (src. code[terminator_idx ]) " invalid IR"
1217+ termidx = bb. stmts[end ]
1218+ @assert is_conditional_terminator (src. code[termidx ]) " invalid IR"
12111219 succ1, succ2 = bb. succs
1212- succ1_req = any (@view concretize[cfg. blocks[succ1]. stmts])
1213- succ2_req = any (@view concretize[cfg. blocks[succ2]. stmts])
1214- if succ1_req
1215- if succ2_req
1216- changed |= mark_concretize! (terminator_idx)
1217- else
1218- active_bb, inactive_bb = succ1, succ2
1219- @goto asymmetric_case
1220+ postdominator = CC. nearest_common_dominator (postdomtree, succ1, succ2)
1221+ for blk in (reachable_blocks (cfg, succ1, postdominator) ∪
1222+ reachable_blocks (cfg, succ2, postdominator))
1223+ if blk == postdominator
1224+ continue
12201225 end
1221- elseif succ2_req
1222- active_bb, inactive_bb = succ2, succ1
1223- @label asymmetric_case
1224- # We can ignore the control flow of this conditional terminator and treat
1225- # it as a fall-through if only one of its successors is active and the
1226- # active block post-dominates the inactive one, since the post-domination
1227- # ensures that the active basic block will be reached regardless of the
1228- # control flow.
1229- if CC. postdominates (postdomtree, active_bb, inactive_bb)
1230- # fall through this block
1231- else
1232- changed |= mark_concretize! (terminator_idx)
1226+ if any (@view concretize[cfg. blocks[blk]. stmts])
1227+ mark_concretize! (termidx)
1228+ break
12331229 end
1234- else
1235- # both successors are inactive, just fall through this block
12361230 end
1231+ # we can just fall-through to the post dominator block (by ignoring all statements between)
12371232 end
12381233 end
12391234 return changed
@@ -1242,6 +1237,25 @@ end
12421237is_conditional_terminator (@nospecialize stmt) = stmt isa GotoIfNot ||
12431238 (@static @isdefined (EnterNode) ? stmt isa EnterNode : isexpr (stmt, :enter ))
12441239
1240+ function reachable_blocks (cfg:: CFG , from_bb:: Int , to_bb:: Int )
1241+ worklist = Int[from_bb]
1242+ visited = BitSet (from_bb)
1243+ if to_bb == from_bb
1244+ return visited
1245+ end
1246+ push! (visited, to_bb)
1247+ function visit! (bb:: Int )
1248+ if bb ∉ visited
1249+ push! (visited, bb)
1250+ push! (worklist, bb)
1251+ end
1252+ end
1253+ while ! isempty (worklist)
1254+ foreach (visit!, cfg. blocks[pop! (worklist)]. succs)
1255+ end
1256+ return visited
1257+ end
1258+
12451259function add_required_inplace! (concretize:: BitVector , src:: CodeInfo , edges, cl)
12461260 changed = false
12471261 for i = 1 : length (src. code)
@@ -1275,6 +1289,7 @@ end
12751289function select_dependencies! (concretize:: BitVector , src:: CodeInfo , edges, cl)
12761290 typedefs = LoweredCodeUtils. find_typedefs (src)
12771291 cfg = CC. compute_basic_blocks (src. code)
1292+ domtree = CC. construct_domtree (cfg. blocks)
12781293 postdomtree = CC. construct_postdomtree (cfg. blocks)
12791294
12801295 while true
@@ -1292,7 +1307,7 @@ function select_dependencies!(concretize::BitVector, src::CodeInfo, edges, cl)
12921307
12931308 # mark necessary control flows,
12941309 # and propagate the definition requirements by tracking SSA precedessors
1295- changed |= add_control_flow! (concretize, src, cfg, postdomtree)
1310+ changed |= add_control_flow! (concretize, src, cfg, domtree, postdomtree)
12961311 changed |= add_ssa_preds! (concretize, src, edges, ())
12971312
12981313 changed || break
0 commit comments