@@ -339,43 +339,58 @@ RPO traversal and in particular, any use of an SSA value must come after
339
339
(by linear order) its definition.
340
340
"""
341
341
function domsort_ssa! (ir:: IRCode , domtree:: DomTree )
342
- # First compute the new order of basic blocks
342
+ # Mapping from new → old BB index
343
+ # An "old" index of 0 means that this was a BB inserted as part of a fixup (see below)
343
344
result_order = Int[]
344
- stack = Int[]
345
+
346
+ # Mapping from old → new BB index
345
347
bb_rename = fill (- 1 , length (ir. cfg. blocks))
346
- node = 1
347
- ncritbreaks = 0
348
- nnewfallthroughs = 0
349
- while node != = - 1
350
- push! (result_order, node)
351
- bb_rename[node] = length (result_order)
352
- cs = domtree. nodes[node]. children
353
- terminator = ir[SSAValue (last (ir. cfg. blocks[node]. stmts))][:stmt ]
354
- next_node = node + 1
355
- node = - 1
348
+
349
+ # The number of GotoNodes we need to insert to preserve control-flow after sorting
350
+ nfixupstmts = 0
351
+
352
+ # node queued up for scheduling (-1 === nothing)
353
+ node_to_schedule = 1
354
+ worklist = Int[]
355
+ while node_to_schedule != = - 1
356
+ # First assign a new BB index to `node_to_schedule`
357
+ push! (result_order, node_to_schedule)
358
+ bb_rename[node_to_schedule] = length (result_order)
359
+ cs = domtree. nodes[node_to_schedule]. children
360
+ terminator = ir[SSAValue (last (ir. cfg. blocks[node_to_schedule]. stmts))][:stmt ]
361
+ fallthrough = node_to_schedule + 1
362
+ node_to_schedule = - 1
363
+
356
364
# Adding the nodes in reverse sorted order attempts to retain
357
365
# the original source order of the nodes as much as possible.
358
366
# This is not required for correctness, but is easier on the humans
359
- for child in Iterators. Reverse (cs)
360
- if child == next_node
367
+ for node in Iterators. Reverse (cs)
368
+ if node == fallthrough
361
369
# Schedule the fall through node first,
362
370
# so we can retain the fall through
363
- node = next_node
371
+ node_to_schedule = node
364
372
else
365
- push! (stack, child )
373
+ push! (worklist, node )
366
374
end
367
375
end
368
- if node == - 1 && ! isempty (stack )
369
- node = pop! (stack )
376
+ if node_to_schedule == - 1 && ! isempty (worklist )
377
+ node_to_schedule = pop! (worklist )
370
378
end
371
- if node != next_node && ! isa (terminator, Union{GotoNode, ReturnNode})
379
+ # If a fallthrough successor is no longer the fallthrough after sorting, we need to
380
+ # add a GotoNode (and either extend or split the basic block as necessary)
381
+ if node_to_schedule != fallthrough && ! isa (terminator, Union{GotoNode, ReturnNode})
372
382
if isa (terminator, GotoIfNot)
373
383
# Need to break the critical edge
374
- ncritbreaks += 1
384
+ push! (result_order, 0 )
385
+ elseif isa (terminator, EnterNode) || isexpr (terminator, :leave )
386
+ # Cannot extend the BasicBlock with a goto, have to split it
375
387
push! (result_order, 0 )
376
388
else
377
- nnewfallthroughs += 1
389
+ # No need for a new block, just extend
390
+ @assert ! isterminator (terminator)
378
391
end
392
+ # Reserve space for the fixup goto
393
+ nfixupstmts += 1
379
394
end
380
395
end
381
396
new_bbs = Vector {BasicBlock} (undef, length (result_order))
@@ -385,7 +400,7 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
385
400
nstmts += length (ir. cfg. blocks[i]. stmts)
386
401
end
387
402
end
388
- result = InstructionStream (nstmts + ncritbreaks + nnewfallthroughs )
403
+ result = InstructionStream (nstmts + nfixupstmts )
389
404
inst_rename = Vector {SSAValue} (undef, length (ir. stmts) + length (ir. new_nodes))
390
405
@inbounds for i = 1 : length (ir. stmts)
391
406
inst_rename[i] = SSAValue (- 1 )
@@ -394,7 +409,6 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
394
409
inst_rename[i + length (ir. stmts)] = SSAValue (i + length (result))
395
410
end
396
411
bb_start_off = 0
397
- crit_edge_breaks_fixup = Tuple{Int, Int}[]
398
412
for (new_bb, bb) in pairs (result_order)
399
413
if bb == 0
400
414
nidx = bb_start_off + 1
@@ -426,20 +440,23 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
426
440
else
427
441
result[inst_range[end ]][:stmt ] = GotoNode (bb_rename[terminator. label])
428
442
end
429
- elseif isa (terminator, GotoIfNot)
430
- # Check if we need to break the critical edge
443
+ elseif isa (terminator, GotoIfNot) || isa (terminator, EnterNode) || isexpr (terminator, :leave )
444
+ # Check if we need to break the critical edge or split the block
431
445
if bb_rename[bb + 1 ] != new_bb + 1
432
446
@assert result_order[new_bb + 1 ] == 0
433
447
# Add an explicit goto node in the next basic block (we accounted for this above)
434
448
nidx = inst_range[end ] + 1
435
449
node = result[nidx]
436
450
node[:stmt ], node[:type ], node[:line ] = GotoNode (bb_rename[bb + 1 ]), Any, NoLineUpdate
437
451
end
438
- result[inst_range[ end ]][ :stmt ] = GotoIfNot (terminator. cond, bb_rename[terminator . dest] )
439
- elseif ! isa (terminator, ReturnNode )
440
- if isa (terminator, EnterNode)
452
+ if isa (terminator, GotoIfNot )
453
+ result[inst_range[ end ]][ :stmt ] = GotoIfNot (terminator. cond, bb_rename[terminator . dest] )
454
+ elseif isa (terminator, EnterNode)
441
455
result[inst_range[end ]][:stmt ] = EnterNode (terminator, terminator. catch_dest == 0 ? 0 : bb_rename[terminator. catch_dest])
456
+ else
457
+ @assert isexpr (terminator, :leave )
442
458
end
459
+ elseif ! isa (terminator, ReturnNode)
443
460
if bb_rename[bb + 1 ] != new_bb + 1
444
461
# Add an explicit goto node
445
462
nidx = inst_range[end ] + 1
@@ -452,7 +469,7 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
452
469
local new_preds, new_succs
453
470
let bb = bb, bb_rename = bb_rename, result_order = result_order
454
471
new_preds = Int[bb for bb in (rename_incoming_edge (i, bb, result_order, bb_rename) for i in ir. cfg. blocks[bb]. preds) if bb != - 1 ]
455
- new_succs = Int[ rename_outgoing_edge (i, bb, result_order, bb_rename) for i in ir. cfg. blocks[bb]. succs]
472
+ new_succs = Int[ rename_outgoing_edge (i, bb, result_order, bb_rename) for i in ir. cfg. blocks[bb]. succs]
456
473
end
457
474
new_bbs[new_bb] = BasicBlock (inst_range, new_preds, new_succs)
458
475
end
0 commit comments