[IR] Correct handling of loops in liveness analysis

#KT-64139 Fixed
This commit is contained in:
Igor Chevdar
2023-12-15 17:49:21 +02:00
committed by Space Team
parent 7907231bf2
commit 69459b056e
@@ -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)