@@ -82,6 +82,80 @@ class SilverCfg(val blocks: Seq[SilverBlock], val edges: Seq[SilverEdge], val en
8282 entry : SilverBlock = entry,
8383 exit : Option [SilverBlock ] = exit): SilverCfg =
8484 SilverCfg (blocks, edges, entry, exit)
85+
86+
87+ /**
88+ * Recursively finds the next join point to a branch point.
89+ *
90+ * @param queueInit Used to initialize the BFS queue with blocks that are yet to be visited.
91+ * @param visitedInit Used to initialize list of visited nodes.
92+ * @param loopHeadsSeen All the loop heads that were visited so far.
93+ * @param getNext function which returns the successor nodes.
94+ * @return (jp, m) where jp is the next join point,
95+ * and m maps all branch points which have been already found
96+ * to their join points.
97+ */
98+ private def findJoinPoint (queueInit : Iterable [SilverBlock ],
99+ visitedInit : Iterable [SilverBlock ],
100+ // We never enqueue loopHeads which we already have seen.
101+ // This would lead to non-termination.
102+ loopHeadsSeen : Iterable [SilverBlock ],
103+ getNext : SilverBlock => Iterable [SilverBlock ])
104+ : (Option [SilverBlock ], mutable.Map [SilverBlock , SilverBlock ]) = {
105+
106+ var queue = mutable.Queue .from(queueInit)
107+ var visited : mutable.Set [SilverBlock ] = mutable.Set .from(visitedInit)
108+ val map = mutable.Map [SilverBlock , SilverBlock ]()
109+ var loopHeads : mutable.Set [SilverBlock ] = mutable.Set .from(loopHeadsSeen)
110+
111+ // BFS traversal of CFG.
112+ while (queue.nonEmpty) {
113+ val curr = queue.dequeue()
114+ val visitNext =
115+ if (! visited.contains(curr)) {
116+ visited += curr
117+ if (curr.isInstanceOf [SilverLoopHeadBlock ]) {
118+ // If current block is loop head, add it to set of seen loopheads.
119+ loopHeads += curr
120+ }
121+ getNext(curr) match {
122+ case out@ Seq () => out
123+ case out@ Seq (_) => out
124+ case out@ Seq (_, _) =>
125+ // New branch point found, start findJoinPoint procedure
126+ // recursively to find the corresponding join point.
127+ val (joinPoint, innerMap) =
128+ findJoinPoint(out.filter(! loopHeads.contains(_)), Seq (curr), loopHeads, getNext)
129+ // Add the join points found to the map of all join points.
130+ map ++= innerMap
131+ joinPoint foreach {
132+ jp => map += curr -> jp
133+ }
134+ // Continue BFS traversal from join point.
135+ joinPoint
136+ case _ => sys.error(" At most two outgoing edges expected." )
137+ }
138+ } else {
139+ return (Some (curr), map)
140+ }
141+
142+
143+ // Avoid re-visiting already seen loop heads.
144+ queue = queue.enqueueAll(visitNext.iterator.filter(! loopHeads.contains(_)))
145+ }
146+ (None , map)
147+ }
148+
149+ /**
150+ * Computes a mapping from all branch points to their corresponding join points.
151+ *
152+ * @return Mapping from all branch points to join points.
153+ */
154+ lazy val joinPoints : collection.Map [SilverBlock , SilverBlock ] = {
155+ val (jp, map) = findJoinPoint(Seq (entry), Seq .empty, Seq .empty, successors)
156+ assert(jp.isEmpty)
157+ map
158+ }
85159}
86160
87161object SilverCfg {
0 commit comments