@@ -640,9 +640,6 @@ function lines_required!(isrequired::AbstractVector{Union{Bool,Symbol}}, objs, s
640640 iter = 0
641641 while changed
642642 changed = false
643- @show iter
644- print_with_code (stdout , src, isrequired)
645- println ()
646643
647644 # Handle ssa predecessors
648645 changed |= add_ssa_preds! (isrequired, src, edges, norequire)
@@ -651,7 +648,6 @@ function lines_required!(isrequired::AbstractVector{Union{Bool,Symbol}}, objs, s
651648 changed |= add_named_dependencies! (isrequired, edges, objs, norequire)
652649
653650 # Add control-flow
654- changed |= add_loops! (isrequired, cfg, domtree, postdomtree)
655651 changed |= add_control_flow! (isrequired, src, cfg, domtree, postdomtree)
656652
657653 # So far, everything is generic graph traversal. Now we add some domain-specific information
@@ -730,85 +726,125 @@ end
730726
731727# # Add control-flow
732728
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
747760 end
748761 end
749- return changed
762+ return needed
750763end
751764
752765function add_control_flow! (isrequired, src, cfg, domtree, postdomtree)
753766 changed, _changed = false , true
754767 blocks = cfg. blocks
755- nblocks = length (blocks)
768+ needed = falses (length (blocks))
769+ cache = Set {Int} ()
756770 while _changed
757771 _changed = false
758772 for (ibb, bb) in enumerate (blocks)
759773 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
762777 jbb = ibb
763778 while jbb != 1
764- jdbb = domtree. idoms_bb[jbb]
779+ jdbb = domtree. idoms_bb[jbb] # immediate dominator of jbb
765780 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
774791 end
775- break
776792 end
777793 end
778794 jbb = jdbb
779795 end
780- # Walk down the post-dominators, including self
796+ # Walk down the post-dominators, starting with self
781797 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]
786802 idxlast = rng (pdbb)[end ]
787803 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
791806 _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
793815 end
794816 end
795817 end
796818 jbb = postdomtree. idoms_bb[jbb]
797819 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
808820 end
809821 end
810822 changed |= _changed
811823 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
812848 return changed
813849end
814850
0 commit comments