[IR] Correct handling of loops in liveness analysis
#KT-64139 Fixed
This commit is contained in:
+24
-5
@@ -57,14 +57,31 @@ object LivenessAnalysis {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// May be used for debug purposes.
|
||||||
|
@Suppress("unused")
|
||||||
|
private fun BitSet.format() = buildString {
|
||||||
|
append('[')
|
||||||
|
var first = true
|
||||||
|
forEachBit {
|
||||||
|
if (!first) append(", ")
|
||||||
|
first = false
|
||||||
|
append(variables[it].name)
|
||||||
|
}
|
||||||
|
append(']')
|
||||||
|
}
|
||||||
|
|
||||||
private fun getVariableId(variable: IrVariable) = variableIds.getOrPut(variable) {
|
private fun getVariableId(variable: IrVariable) = variableIds.getOrPut(variable) {
|
||||||
variables.add(variable)
|
variables.add(variable)
|
||||||
variables.lastIndex
|
variables.lastIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <T : IrElement> saveAndCompute(element: T, liveVariables: BitSet, compute: () -> BitSet): BitSet {
|
private inline fun <T : IrElement> saveAndCompute(element: T, liveVariables: BitSet, compute: () -> BitSet): BitSet {
|
||||||
if (filter(element))
|
if (filter(element)) {
|
||||||
filteredElementEndsLV[element] = liveVariables.copy().also { it.or(catchesLV) }
|
// Merge with the previous because of the loops (see the comment there).
|
||||||
|
val elementLV = filteredElementEndsLV.getOrPut(element) { BitSet() }
|
||||||
|
elementLV.or(liveVariables)
|
||||||
|
elementLV.or(catchesLV)
|
||||||
|
}
|
||||||
return compute()
|
return compute()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,13 +234,15 @@ object LivenessAnalysis {
|
|||||||
loopEndsLV[loop] = data
|
loopEndsLV[loop] = data
|
||||||
var bodyEndLV = loop.condition.accept(this, data)
|
var bodyEndLV = loop.condition.accept(this, data)
|
||||||
val body = loop.body ?: return bodyEndLV
|
val body = loop.body ?: return bodyEndLV
|
||||||
var bodyStartLV: BitSet
|
val bodyStartLV = BitSet()
|
||||||
// In practice, only one or two iterations seem to be enough, but the classic algorithm
|
// In practice, only one or two iterations seem to be enough, but the classic algorithm
|
||||||
// loops until "saturation" (when nothing changes anymore).
|
// loops until "saturation" (when nothing changes anymore).
|
||||||
do {
|
do {
|
||||||
loopStartsLV[loop] = bodyEndLV
|
loopStartsLV[loop] = bodyEndLV
|
||||||
bodyStartLV = body.accept(this, bodyEndLV)
|
val curBodyStartLV = body.accept(this, bodyEndLV)
|
||||||
val nextBodyEndLV = loop.condition.accept(this, bodyStartLV)
|
// Since it's unknown how many iterations the loop will execute, merge the live variables at each iteration.
|
||||||
|
bodyStartLV.or(curBodyStartLV)
|
||||||
|
val nextBodyEndLV = loop.condition.accept(this, curBodyStartLV)
|
||||||
val lvHaveChanged = nextBodyEndLV != bodyEndLV
|
val lvHaveChanged = nextBodyEndLV != bodyEndLV
|
||||||
bodyEndLV = nextBodyEndLV
|
bodyEndLV = nextBodyEndLV
|
||||||
} while (lvHaveChanged)
|
} while (lvHaveChanged)
|
||||||
|
|||||||
Reference in New Issue
Block a user