@@ -1177,63 +1177,55 @@ end
1177
1177
# and if there is an active successor and the terminator is not a fall-through, then request
1178
1178
# the concretization of that terminator. Additionally, for conditional terminators, a simple
1179
1179
# 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)
1181
1181
local changed:: Bool = false
1182
1182
function mark_concretize! (idx:: Int )
1183
1183
if ! concretize[idx]
1184
- concretize[idx] = true
1184
+ changed |= concretize[idx] = true
1185
1185
return true
1186
1186
end
1187
1187
return false
1188
1188
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]
1192
1191
nsuccs = length (bb. succs)
1193
1192
if nsuccs == 0
1194
1193
continue
1195
1194
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
+ postdominator = CC. nearest_common_dominator (domtree, bbidx, succ)
1201
+ for blk in reachable_blocks (cfg, dominator, postdominator)
1202
+ if blk == dominator || blk == postdominator
1203
+ continue
1204
+ end
1205
+ if any (@view concretize[cfg. blocks[blk]. stmts])
1206
+ mark_concretize! (termidx)
1207
+ break
1208
+ end
1209
+ end
1206
1210
end
1207
1211
end
1212
+ continue # otherwise we can just fall-through
1208
1213
elseif nsuccs == 2
1209
- terminator_idx = bb. stmts[end ]
1210
- @assert is_conditional_terminator (src. code[terminator_idx ]) " invalid IR"
1214
+ termidx = bb. stmts[end ]
1215
+ @assert is_conditional_terminator (src. code[termidx ]) " invalid IR"
1211
1216
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
1217
+ postdominator = CC. nearest_common_dominator (postdomtree, succ1, succ2)
1218
+ for blk in (reachable_blocks (cfg, succ1, postdominator) ∪
1219
+ reachable_blocks (cfg, succ2, postdominator))
1220
+ if blk == postdominator
1221
+ continue
1220
1222
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)
1223
+ if any (@view concretize[cfg. blocks[blk]. stmts])
1224
+ mark_concretize! (termidx)
1225
+ break
1233
1226
end
1234
- else
1235
- # both successors are inactive, just fall through this block
1236
1227
end
1228
+ # we can just fall-through to the post dominator block (by ignoring all statements between)
1237
1229
end
1238
1230
end
1239
1231
return changed
@@ -1242,6 +1234,25 @@ end
1242
1234
is_conditional_terminator (@nospecialize stmt) = stmt isa GotoIfNot ||
1243
1235
(@static @isdefined (EnterNode) ? stmt isa EnterNode : isexpr (stmt, :enter ))
1244
1236
1237
+ function reachable_blocks (cfg:: CFG , from_bb:: Int , to_bb:: Int )
1238
+ worklist = Int[from_bb]
1239
+ visited = BitSet (from_bb)
1240
+ if to_bb == from_bb
1241
+ return visited
1242
+ end
1243
+ push! (visited, to_bb)
1244
+ function visit! (bb:: Int )
1245
+ if bb ∉ visited
1246
+ push! (visited, bb)
1247
+ push! (worklist, bb)
1248
+ end
1249
+ end
1250
+ while ! isempty (worklist)
1251
+ foreach (visit!, cfg. blocks[pop! (worklist)]. succs)
1252
+ end
1253
+ return visited
1254
+ end
1255
+
1245
1256
function add_required_inplace! (concretize:: BitVector , src:: CodeInfo , edges, cl)
1246
1257
changed = false
1247
1258
for i = 1 : length (src. code)
@@ -1275,6 +1286,7 @@ end
1275
1286
function select_dependencies! (concretize:: BitVector , src:: CodeInfo , edges, cl)
1276
1287
typedefs = LoweredCodeUtils. find_typedefs (src)
1277
1288
cfg = CC. compute_basic_blocks (src. code)
1289
+ domtree = CC. construct_domtree (cfg. blocks)
1278
1290
postdomtree = CC. construct_postdomtree (cfg. blocks)
1279
1291
1280
1292
while true
@@ -1292,7 +1304,7 @@ function select_dependencies!(concretize::BitVector, src::CodeInfo, edges, cl)
1292
1304
1293
1305
# mark necessary control flows,
1294
1306
# and propagate the definition requirements by tracking SSA precedessors
1295
- changed |= add_control_flow! (concretize, src, cfg, postdomtree)
1307
+ changed |= add_control_flow! (concretize, src, cfg, domtree, postdomtree)
1296
1308
changed |= add_ssa_preds! (concretize, src, edges, ())
1297
1309
1298
1310
changed || break
0 commit comments