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>>() val edgesMap = LinkedHashMap<Instruction, Edges<I>>()
edgesMap.put(getStartInstruction(traversalOrder), Edges(initialInfo, initialInfo)) edgesMap.put(getStartInstruction(traversalOrder), Edges(initialInfo, initialInfo))
val changed = BooleanArray(1) val changed = mutableMapOf<Instruction, Boolean>()
changed[0] = true do {
while (changed[0]) {
changed[0] = false
collectDataFromSubgraph( collectDataFromSubgraph(
traversalOrder, edgesMap, traversalOrder, edgesMap,
mergeEdges, updateEdge, Collections.emptyList<Instruction>(), changed, false) mergeEdges, updateEdge, Collections.emptyList<Instruction>(), changed, false)
} } while (changed.any { it.value })
return edgesMap return edgesMap
} }
@@ -81,7 +80,7 @@ private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
mergeEdges: (Instruction, Collection<I>) -> Edges<I>, mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
updateEdge: (Instruction, Instruction, I) -> I, updateEdge: (Instruction, Instruction, I) -> I,
previousSubGraphInstructions: Collection<Instruction>, previousSubGraphInstructions: Collection<Instruction>,
changed: BooleanArray, changed: MutableMap<Instruction, Boolean>,
isLocal: Boolean isLocal: Boolean
) { ) {
val instructions = getInstructions(traversalOrder) val instructions = getInstructions(traversalOrder)
@@ -107,7 +106,13 @@ private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
updateEdgeDataForInstruction(instruction, previousValue, updatedValue, edgesMap, changed) updateEdgeDataForInstruction(instruction, previousValue, updatedValue, edgesMap, changed)
continue continue
} }
val previousDataValue = edgesMap[instruction] val previousDataValue = edgesMap[instruction]
if (previousDataValue != null && previousInstructions.all { changed[it] == false }) {
changed[instruction] = false
continue
}
val incomingEdgesData = HashSet<I>() val incomingEdgesData = HashSet<I>()
@@ -139,11 +144,19 @@ private fun getPreviousIncludingSubGraphInstructions(
} }
private fun <I : ControlFlowInfo<*, *>> updateEdgeDataForInstruction( 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) { if (previousValue != newValue && newValue != null) {
changed[0] = true changed[instruction] = true
edgesMap.put(instruction, newValue) edgesMap.put(instruction, newValue)
} }
else {
changed[instruction] = false
}
} }
data class Edges<out T>(val incoming: T, val outgoing: T) data class Edges<out T>(val incoming: T, val outgoing: T)