@@ -640,9 +640,6 @@ function lines_required!(isrequired::AbstractVector{Union{Bool,Symbol}}, objs, s
640
640
iter = 0
641
641
while changed
642
642
changed = false
643
- @show iter
644
- print_with_code (stdout , src, isrequired)
645
- println ()
646
643
647
644
# Handle ssa predecessors
648
645
changed |= add_ssa_preds! (isrequired, src, edges, norequire)
@@ -651,7 +648,6 @@ function lines_required!(isrequired::AbstractVector{Union{Bool,Symbol}}, objs, s
651
648
changed |= add_named_dependencies! (isrequired, edges, objs, norequire)
652
649
653
650
# Add control-flow
654
- changed |= add_loops! (isrequired, cfg, domtree, postdomtree)
655
651
changed |= add_control_flow! (isrequired, src, cfg, domtree, postdomtree)
656
652
657
653
# So far, everything is generic graph traversal. Now we add some domain-specific information
@@ -730,85 +726,125 @@ end
730
726
731
727
# # Add control-flow
732
728
733
- # Mark loops that contain evaluated statements
734
- function add_loops! (isrequired, cfg, domtree, postdomtree)
735
- changed = false
736
- for (ibb, bb) in enumerate (cfg. blocks)
737
- for ibbp in bb. preds
738
- # Is there a backwards-pointing predecessor, and if so are there any required statements between the two?
739
- ibbp > ibb || continue # not a loop-block predecessor
740
- if postdominates (postdomtree, ibb, ibbp)
741
- r = rng (cfg. blocks[ibbp])
742
- if isrequired[r[end ]] != true
743
- isrequired[r[end ]] = true
744
- changed = true
745
- end
746
- end
729
+ iscf (stmt) = isa (stmt, Core. GotoNode) || isa (stmt, Core. GotoIfNot) || isa (stmt, Core. ReturnNode)
730
+
731
+ """
732
+ ispredecessor(blocks, i, j)
733
+
734
+ Determine whether block `i` is a predecessor of block `j` in the control-flow graph `blocks`.
735
+ """
736
+ function ispredecessor (blocks, i, j, cache= Set {Int} ())
737
+ for p in blocks[j]. preds # avoid putting `j` in the cache unless it loops back
738
+ getpreds! (cache, blocks, p)
739
+ end
740
+ return i ∈ cache
741
+ end
742
+ function getpreds! (cache, blocks, j)
743
+ if j ∈ cache
744
+ return cache
745
+ end
746
+ push! (cache, j)
747
+ for p in blocks[j]. preds
748
+ getpreds! (cache, blocks, p)
749
+ end
750
+ return cache
751
+ end
752
+
753
+ function block_internals_needed (isrequired, src, r)
754
+ needed = false
755
+ for i in r
756
+ if isrequired[i] == true
757
+ iscf (src. code[i]) && continue
758
+ needed = true
759
+ break
747
760
end
748
761
end
749
- return changed
762
+ return needed
750
763
end
751
764
752
765
function add_control_flow! (isrequired, src, cfg, domtree, postdomtree)
753
766
changed, _changed = false , true
754
767
blocks = cfg. blocks
755
- nblocks = length (blocks)
768
+ needed = falses (length (blocks))
769
+ cache = Set {Int} ()
756
770
while _changed
757
771
_changed = false
758
772
for (ibb, bb) in enumerate (blocks)
759
773
r = rng (bb)
760
- if any (== (true ), view (isrequired, r))
761
- # Walk up the dominators
774
+ if block_internals_needed (isrequired, src, r)
775
+ needed[ibb] = true
776
+ # Check control flow that's needed to reach this block by walking up the dominators
762
777
jbb = ibb
763
778
while jbb != 1
764
- jdbb = domtree. idoms_bb[jbb]
779
+ jdbb = domtree. idoms_bb[jbb] # immediate dominator of jbb
765
780
dbb = blocks[jdbb]
766
- # Check the successors; if jbb doesn't post-dominate, mark the last statement
767
- for s in dbb. succs
768
- if ! postdominates (postdomtree, jbb, s)
769
- idxlast = rng (dbb)[end ]
770
- if isrequired[idxlast] != true
771
- println (" add 1: " , idxlast)
772
- _changed = true
773
- isrequired[idxlast] = true
781
+ idxlast = rng (dbb)[end ]
782
+ if iscf (src. code[idxlast])
783
+ # Check the idom's successors; if jbb doesn't post-dominate, mark the last statement
784
+ for s in dbb. succs
785
+ if ! postdominates (postdomtree, jbb, s)
786
+ if isrequired[idxlast] != true
787
+ _changed = true
788
+ isrequired[idxlast] = true
789
+ break
790
+ end
774
791
end
775
- break
776
792
end
777
793
end
778
794
jbb = jdbb
779
795
end
780
- # Walk down the post-dominators, including self
796
+ # Walk down the post-dominators, starting with self
781
797
jbb = ibb
782
- while jbb != 0 && jbb < nblocks
783
- pdbb = blocks[jbb]
784
- # Check if the exit of this block is a GotoNode or `return`
785
- if length ( pdbb. succs) < 2
798
+ while jbb != 0
799
+ empty! (cache)
800
+ if ispredecessor (blocks, jbb, ibb, cache) # is post-dominator jbb also a predecessor of ibb? If so we have a loop.
801
+ pdbb = blocks[jbb]
786
802
idxlast = rng (pdbb)[end ]
787
803
stmt = src. code[idxlast]
788
- if isa (stmt, GotoNode) || isa (stmt, Core. ReturnNode)
789
- if isrequired[idxlast] == false
790
- println (" add 2: " , idxlast)
804
+ if iscf (stmt)
805
+ if isrequired[idxlast] != true
791
806
_changed = true
792
- isrequired[idxlast] = :exit
807
+ if isa (stmt, Core. ReturnNode) && isrequired[idxlast] != :exit
808
+ isrequired[idxlast] = :exit
809
+ else
810
+ isrequired[idxlast] = true
811
+ if isa (stmt, Core. GotoIfNot) && idxlast < length (isrequired) && isrequired[idxlast+ 1 ] != true && iscf (src. code[idxlast+ 1 ])
812
+ isrequired[idxlast+ 1 ] = true
813
+ end
814
+ end
793
815
end
794
816
end
795
817
end
796
818
jbb = postdomtree. idoms_bb[jbb]
797
819
end
798
- elseif length (r) == 1
799
- # pdbb = blocks[ibb]
800
- # if length(pdbb.succs) < 2 && isa(src.code[r[1]], GotoNode)
801
- # idxlast = r[end]
802
- # if isrequired[idxlast] == false
803
- # println("add 3: ", idxlast)
804
- # _changed = true
805
- # isrequired[idxlast] = true
806
- # end
807
- # end
808
820
end
809
821
end
810
822
changed |= _changed
811
823
end
824
+ # Now handle "exclusions": in code that would fall through during selective evaluation, find a post-dominator between the two
825
+ # that is marked, or mark the end block
826
+ marked = findall (needed)
827
+ for k in Iterators. drop (eachindex (marked), 1 )
828
+ ibb, jbb = marked[k- 1 ], marked[k]
829
+ ok = false
830
+ ipbb = ibb
831
+ while ipbb < jbb
832
+ ipbb = postdomtree. idoms_bb[ipbb]
833
+ ipbb == 0 && break
834
+ idxlast = rng (blocks[ipbb])[end ]
835
+ if isrequired[idxlast] != false
836
+ ok = true
837
+ break
838
+ end
839
+ end
840
+ if ! ok
841
+ idxlast = rng (blocks[ibb])[end ]
842
+ if isrequired[idxlast] != true
843
+ isrequired[idxlast] = true
844
+ changed = true
845
+ end
846
+ end
847
+ end
812
848
return changed
813
849
end
814
850
0 commit comments