Skip to content

Commit 3ec8900

Browse files
authored
Merge branch 'master' into meilers_allow_heapdep_func_calls
2 parents 541b560 + 496dcdc commit 3ec8900

1 file changed

Lines changed: 74 additions & 0 deletions

File tree

src/main/scala/viper/silver/cfg/silver/SilverCfg.scala

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

87161
object SilverCfg {

0 commit comments

Comments
 (0)