FIR CFA: remove edge kind merging

There shouldn't be any duplicate edges anymore. There probably weren't
any before, either.
This commit is contained in:
pyos
2022-11-27 22:18:49 +01:00
committed by Dmitriy Novozhilov
parent 069d99c5ea
commit 7feeb7cd4e
2 changed files with 20 additions and 54 deletions
@@ -312,7 +312,7 @@ class ControlFlowGraphBuilder {
if (isDefinitelyVisited || splitNode.isDead) {
// The edge that was added as a hack to enforce ordering of nodes needs to be marked as dead if this lambda is never
// skipped. Or if the entry node is dead, because at the time we added the hack-edge we didn't know that.
CFGNode.addJustKindEdge(splitNode, postponedExitNode, EdgeKind.DeadForward, propagateDeadness = !isDefinitelyVisited)
CFGNode.killEdge(splitNode, postponedExitNode, propagateDeadness = !isDefinitelyVisited)
}
if (invocationKind?.canBeVisited() == true) {
addEdge(exitNode, postponedExitNode, propagateDeadness = isDefinitelyVisited)
@@ -1449,15 +1449,9 @@ class ControlFlowGraphBuilder {
if (!node.isDead) return
for (next in node.followingNodes) {
val kind = node.outgoingEdges.getValue(next).kind
if (kind.isDead) continue
if (kind.isBack) {
CFGNode.addJustKindEdge(node, next, EdgeKind.DeadBackward, propagateDeadness = false)
} else {
CFGNode.addJustKindEdge(node, next, EdgeKind.DeadForward, propagateDeadness = false)
if (kind.usedInCfa) {
next.updateDeadStatus()
propagateDeadnessForward(next)
}
if (CFGNode.killEdge(node, next, propagateDeadness = false) && !kind.isBack && kind.usedInCfa) {
next.updateDeadStatus()
propagateDeadnessForward(next)
}
}
}
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.fir.types.isNothing
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.runIf
@RequiresOptIn
annotation class CfgInternals
@@ -36,55 +35,28 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
) {
from._followingNodes += to
to._previousNodes += from
addJustKindEdge(from, to, kind, propagateDeadness, edgeExists = false, label = label)
}
@CfgInternals
fun addJustKindEdge(
from: CFGNode<*>,
to: CFGNode<*>,
kind: EdgeKind,
propagateDeadness: Boolean,
label: EdgeLabel = NormalPath
) {
addJustKindEdge(from, to, kind, propagateDeadness, edgeExists = true, label = label)
}
private fun addJustKindEdge(
from: CFGNode<*>,
to: CFGNode<*>,
kind: EdgeKind,
propagateDeadness: Boolean,
edgeExists: Boolean,
label: EdgeLabel = NormalPath
) {
// It's hard to define label merging, hence overwritten with the latest one.
// One day, if we allow multiple edges between nodes with different labels, we won't even need kind merging.
if (kind != EdgeKind.Forward || label != NormalPath) {
val fromToKind = from._outgoingEdges?.get(to)?.kind ?: runIf(edgeExists) { EdgeKind.Forward }
merge(kind, fromToKind)?.let {
from.insertOutgoingEdge(to, Edge.create(label, it))
} ?: from._outgoingEdges?.remove(to)
val toFromKind = to._incomingEdges?.get(from)?.kind ?: runIf(edgeExists) { EdgeKind.Forward }
merge(kind, toFromKind)?.let {
to.insertIncomingEdge(from, Edge.create(label, it))
} ?: to._incomingEdges?.remove(from)
val edge = Edge.create(label, kind)
from.insertOutgoingEdge(to, edge)
to.insertIncomingEdge(from, edge)
}
if (propagateDeadness && kind == EdgeKind.DeadForward) {
to.isDead = true
}
}
private fun merge(first: EdgeKind, second: EdgeKind?): EdgeKind? {
return when {
second == null -> first
first == second -> first
first == EdgeKind.DeadForward || second == EdgeKind.DeadForward -> EdgeKind.DeadForward
first == EdgeKind.DeadBackward || second == EdgeKind.DeadBackward -> EdgeKind.DeadBackward
first == EdgeKind.Forward || second == EdgeKind.Forward -> null
first.usedInDfa xor second.usedInDfa -> null
else -> throw IllegalStateException()
@CfgInternals
fun killEdge(from: CFGNode<*>, to: CFGNode<*>, propagateDeadness: Boolean): Boolean {
val oldEdge = to.incomingEdges.getValue(from)
if (oldEdge.kind.isDead) return false
val newEdge = Edge.create(oldEdge.label, if (oldEdge.kind.isBack) EdgeKind.DeadBackward else EdgeKind.DeadForward)
from.insertOutgoingEdge(to, newEdge)
to.insertIncomingEdge(from, newEdge)
if (propagateDeadness) {
to.isDead = true
}
return true
}
@CfgInternals
@@ -92,8 +64,8 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
for (from in to._previousNodes) {
from._followingNodes.remove(to)
from._outgoingEdges?.remove(to)
to._incomingEdges?.remove(from)
}
to._incomingEdges = null
to._previousNodes.clear()
}
@@ -101,9 +73,9 @@ sealed class CFGNode<out E : FirElement>(val owner: ControlFlowGraph, val level:
fun removeAllOutgoingEdges(from: CFGNode<*>) {
for (to in from._followingNodes) {
to._previousNodes.remove(from)
from._outgoingEdges?.remove(to)
to._incomingEdges?.remove(from)
}
from._outgoingEdges = null
from._followingNodes.clear()
}