Skip to content

Commit

Permalink
add "until" to iteration, add state information to Worklist, fix pop …
Browse files Browse the repository at this point in the history
…order
  • Loading branch information
CodingDepot committed Oct 14, 2024
1 parent 253debb commit 6ec77dc
Showing 1 changed file with 65 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ class Worklist<K : Any, N : Any, V>() {
/** A list of all nodes which have already been visited. */
private val alreadySeen = IdentitySet<K>()

enum class EvaluationState {
WIDENING,
NARROWING,
DONE
}

val evaluationStateMap = IdentityHashMap<K, EvaluationState>()

constructor(
globalState: IdentityHashMap<K, State<N, V>> = IdentityHashMap<K, State<N, V>>()
) : this() {
Expand Down Expand Up @@ -210,14 +218,24 @@ class Worklist<K : Any, N : Any, V>() {

/** Removes a [Node] from the worklist and returns the [Node] together with its [State] */
fun pop(): Pair<K, State<N, V>> {
val node = nodeOrder.removeFirst()
val node = nodeOrder.removeLast()
alreadySeen.add(node.first)
return node
}

/** Checks if [currentNode] has already been visited before. */
fun hasAlreadySeen(currentNode: K) = currentNode in alreadySeen

/** Checks if [currentNode] needs to be widened. */
fun needsWidening(currentNode: K) = evaluationStateMap[currentNode] == EvaluationState.WIDENING

/** Checks if [currentNode] needs to be narrowed. */
fun needsNarrowing(currentNode: K) =
evaluationStateMap[currentNode] == EvaluationState.NARROWING

/** Checks if [currentNode] should not be changed anymore. */
fun isDone(currentNode: K) = evaluationStateMap[currentNode] == EvaluationState.DONE

/** Computes the meet over paths for all the states in [globalState]. */
fun mop(): State<N, V>? {
val firstKey = globalState.keys.firstOrNull()
Expand Down Expand Up @@ -247,47 +265,12 @@ inline fun <reified K : Node, V> iterateEOG(
return iterateEOG(startNode, startState) { k, s, _ -> transformation(k, s) }
}

/**
* Iterates through the worklist of the Evaluation Order Graph starting at [startNode] and with the
* [State] [startState]. For each node, the [transformation] is applied which should update the
* state.
*
* [transformation] receives the current [Node] popped from the worklist, the [State] at this node
* which is considered for this analysis and even the current [Worklist]. The worklist is given if
* we have to add more elements out-of-order e.g. because the EOG is traversed in an order which is
* not useful for this analysis. The [transformation] has to return the updated [State].
*/
inline fun <reified K : Node, V> iterateEOG(
startNode: K,
startState: State<K, V>,
transformation: (K, State<K, V>, Worklist<K, K, V>) -> State<K, V>
): State<K, V>? {
val initialState = IdentityHashMap<K, State<K, V>>()
initialState[startNode] = startState
val worklist = Worklist(initialState)
worklist.push(startNode, startState)

while (worklist.isNotEmpty()) {
val (nextNode, state) = worklist.pop()

// This should check if we're not near the beginning/end of a basic block (i.e., there are
// no merge points or branches of the EOG nearby). If that's the case, we just parse the
// whole basic block and do not want to duplicate the state. Near the beginning/end, we do
// want to copy the state to avoid terminating the iteration too early by messing up with
// the state-changing checks.
val insideBB =
(nextNode.nextEOG.size == 1 && nextNode.prevEOG.singleOrNull()?.nextEOG?.size == 1)
val newState =
transformation(nextNode, if (insideBB) state else state.duplicate(), worklist)
if (worklist.update(nextNode, newState)) {
nextNode.nextEOG.forEach {
if (it is K) {
worklist.push(it, newState)
}
}
}
}
return worklist.mop()
return iterateEOG(startNode, startState, transformation, null)
}

inline fun <reified K : PropertyEdge<Node>, N : Any, V> iterateEOG(
Expand Down Expand Up @@ -334,3 +317,48 @@ inline fun <reified K : PropertyEdge<Node>, N : Any, V> iterateEOG(
}
return worklist.mop()
}

/**
* Iterates through the worklist of the Evaluation Order Graph starting at [startNode] and with the
* [State] [startState]. For each node, the [transformation] is applied which should update the
* state. When the [until] node is reached, its successors are not added to the worklist.
*
* [transformation] receives the current [Node] popped from the worklist, the [State] at this node
* which is considered for this analysis and even the current [Worklist]. The worklist is given if
* we have to add more elements out-of-order e.g. because the EOG is traversed in an order which is
* not useful for this analysis. The [transformation] has to return the updated [State].
*/
inline fun <reified K : Node, V> iterateEOG(
startNode: K,
startState: State<K, V>,
transformation: (K, State<K, V>, Worklist<K, K, V>) -> State<K, V>,
until: Node?
): State<K, V>? {
val initialState = IdentityHashMap<K, State<K, V>>()
initialState[startNode] = startState
val worklist = Worklist(initialState)
worklist.push(startNode, startState)

while (worklist.isNotEmpty()) {
val (nextNode, state) = worklist.pop()

// This should check if we're not near the beginning/end of a basic block (i.e., there are
// no merge points or branches of the EOG nearby). If that's the case, we just parse the
// whole basic block and do not want to duplicate the state. Near the beginning/end, we do
// want to copy the state to avoid terminating the iteration too early by messing up with
// the state-changing checks.
val insideBB =
(nextNode.nextEOG.size == 1 && nextNode.prevEOG.singleOrNull()?.nextEOG?.size == 1)
val newState =
transformation(nextNode, if (insideBB) state else state.duplicate(), worklist)

if (worklist.update(nextNode, newState) && nextNode != until) {
nextNode.nextEOG.forEach {
if (it is K && !worklist.isDone(it)) {
worklist.push(it, newState)
}
}
}
}
return worklist.mop()
}

0 comments on commit 6ec77dc

Please sign in to comment.