Optimize control-flow analysis algorithm

There's no need to recalculate results if all of the
previous instructions' results remain unchanged.

It's a crucial optimizations because otherwise algorithm
can degrate to O(n * m) [n - instructions number, m - variables number]
even in a linear code like this:
var a_1 = 1
var a_2 = 1
...
var a_m = 1

We perform analysis iteration once, then we repeat it to be sure
that no changes happened and here for each instruction we're
starting to check if recomputed value is the same, that basically
compares maps of all the variables, so it works O(n * m)

After this change on the second iteration we won't recompute new values
as none of predecessor has been changed
This commit is contained in:
Denis Zharkov
2017-04-10 16:24:41 +03:00
parent 5e449fdc02
commit aaddc34b54
@@ -64,14 +64,13 @@ fun <I : ControlFlowInfo<*, *>> Pseudocode.collectData(
val edgesMap = LinkedHashMap<Instruction, Edges<I>>()
edgesMap.put(getStartInstruction(traversalOrder), Edges(initialInfo, initialInfo))
val changed = BooleanArray(1)
changed[0] = true
while (changed[0]) {
changed[0] = false
val changed = mutableMapOf<Instruction, Boolean>()
do {
collectDataFromSubgraph(
traversalOrder, edgesMap,
mergeEdges, updateEdge, Collections.emptyList<Instruction>(), changed, false)
}
} while (changed.any { it.value })
return edgesMap
}
@@ -81,7 +80,7 @@ private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
updateEdge: (Instruction, Instruction, I) -> I,
previousSubGraphInstructions: Collection<Instruction>,
changed: BooleanArray,
changed: MutableMap<Instruction, Boolean>,
isLocal: Boolean
) {
val instructions = getInstructions(traversalOrder)
@@ -107,7 +106,13 @@ private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
updateEdgeDataForInstruction(instruction, previousValue, updatedValue, edgesMap, changed)
continue
}
val previousDataValue = edgesMap[instruction]
if (previousDataValue != null && previousInstructions.all { changed[it] == false }) {
changed[instruction] = false
continue
}
val incomingEdgesData = HashSet<I>()
@@ -139,11 +144,19 @@ private fun getPreviousIncludingSubGraphInstructions(
}
private fun <I : ControlFlowInfo<*, *>> updateEdgeDataForInstruction(
instruction: Instruction, previousValue: Edges<I>?, newValue: Edges<I>?, edgesMap: MutableMap<Instruction, Edges<I>>, changed: BooleanArray) {
instruction: Instruction,
previousValue: Edges<I>?,
newValue: Edges<I>?,
edgesMap: MutableMap<Instruction, Edges<I>>,
changed: MutableMap<Instruction, Boolean>
) {
if (previousValue != newValue && newValue != null) {
changed[0] = true
changed[instruction] = true
edgesMap.put(instruction, newValue)
}
else {
changed[instruction] = false
}
}
data class Edges<out T>(val incoming: T, val outgoing: T)