@@ -609,7 +609,8 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
609
609
610
610
# Compute basic blocks, which we'll use to make sure we mark necessary control-flow
611
611
cfg = Core. Compiler. compute_basic_blocks (src. code) # needed for control-flow analysis
612
- paths = enumerate_paths (cfg)
612
+ domtree = construct_domtree (cfg. blocks)
613
+ postdomtree = construct_postdomtree (cfg. blocks)
613
614
614
615
# We'll mostly use generic graph traversal to discover all the lines we need,
615
616
# but structs are in a bit of a different category (especially on Julia 1.5+).
@@ -629,7 +630,7 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
629
630
630
631
# Add control-flow
631
632
changed |= add_loops! (isrequired, cfg)
632
- changed |= add_control_flow! (isrequired, cfg, paths )
633
+ changed |= add_control_flow! (isrequired, cfg, domtree, postdomtree )
633
634
634
635
# So far, everything is generic graph traversal. Now we add some domain-specific information
635
636
changed |= add_typedefs! (isrequired, src, edges, typedefs, norequire)
706
707
707
708
# # Add control-flow
708
709
709
- struct Path
710
- path:: Vector{Int}
711
- visited:: BitSet
712
- end
713
- Path () = Path (Int[], BitSet ())
714
- Path (i:: Int ) = Path ([i], BitSet ([i]))
715
- Path (path:: Path ) = copy (path)
716
- Base. copy (path:: Path ) = Path (copy (path. path), copy (path. visited))
717
- Base. in (node:: Int , path:: Path ) = node ∈ path. visited
718
- Base. push! (path:: Path , node:: Int ) = (push! (path. path, node); push! (path. visited, node); return path)
719
-
720
710
# Mark loops that contain evaluated statements
721
711
function add_loops! (isrequired, cfg)
722
712
changed = false
@@ -741,26 +731,7 @@ function add_loops!(isrequired, cfg)
741
731
return changed
742
732
end
743
733
744
- enumerate_paths (cfg) = enumerate_paths! (Path[], cfg, Path (1 ))
745
- function enumerate_paths! (paths, cfg, path)
746
- bb = cfg. blocks[path. path[end ]]
747
- if isempty (bb. succs)
748
- push! (paths, copy (path))
749
- return paths
750
- end
751
- for ibbs in bb. succs
752
- if ibbs ∈ path
753
- push! (paths, push! (copy (path), ibbs)) # close the loop
754
- continue
755
- end
756
- enumerate_paths! (paths, cfg, push! (copy (path), ibbs))
757
- end
758
- return paths
759
- end
760
-
761
- # Mark exits of blocks that bifurcate execution paths in ways that matter for required statements
762
- function add_control_flow! (isrequired, cfg, paths:: AbstractVector{Path} )
763
- withnode, withoutnode, shared = BitSet (), BitSet (), BitSet ()
734
+ function add_control_flow! (isrequired, cfg, domtree, postdomtree)
764
735
changed, _changed = false , true
765
736
blocks = cfg. blocks
766
737
nblocks = length (blocks)
@@ -769,28 +740,33 @@ function add_control_flow!(isrequired, cfg, paths::AbstractVector{Path})
769
740
for (ibb, bb) in enumerate (blocks)
770
741
r = rng (bb)
771
742
if any (view (isrequired, r))
772
- # Check if the exit of this block is a GotoNode or `return`
773
- if length (bb. succs) < 2 && ibb < nblocks
774
- idxlast = r[end ]
775
- _changed |= ! isrequired[idxlast]
776
- isrequired[idxlast] = true
777
- end
778
- empty! (withnode)
779
- empty! (withoutnode)
780
- for path in paths
781
- union! (ibb ∈ path ? withnode : withoutnode, path. visited)
743
+ # Walk up the dominators
744
+ jbb = ibb
745
+ while jbb != 1
746
+ jdbb = domtree. idoms_bb[jbb]
747
+ dbb = blocks[jdbb]
748
+ # Check the successors; if jbb doesn't post-dominate, mark the last statement
749
+ for s in dbb. succs
750
+ if ! postdominates (postdomtree, jbb, s)
751
+ idxlast = rng (dbb)[end ]
752
+ _changed |= ! isrequired[idxlast]
753
+ isrequired[idxlast] = true
754
+ break
755
+ end
756
+ end
757
+ jbb = jdbb
782
758
end
783
- empty! (shared)
784
- union! (shared, withnode)
785
- intersect! (shared, withoutnode)
786
- for icfbb in shared
787
- cfbb = blocks[icfbb]
788
- if any (∉ (shared), cfbb. succs)
789
- rcfbb = rng (blocks[icfbb])
790
- idxlast = rcfbb[end ]
759
+ # Walk down the post-dominators, including self
760
+ jbb = ibb
761
+ while jbb != 0 && jbb < nblocks
762
+ pdbb = blocks[jbb]
763
+ # Check if the exit of this block is a GotoNode or `return`
764
+ if length (pdbb. succs) < 2
765
+ idxlast = rng (pdbb)[end ]
791
766
_changed |= ! isrequired[idxlast]
792
767
isrequired[idxlast] = true
793
768
end
769
+ jbb = postdomtree. idoms_bb[jbb]
794
770
end
795
771
end
796
772
end
0 commit comments