From 7feeb7cd4ea7298ef556aa753fda1f18c943216a Mon Sep 17 00:00:00 2001 From: pyos Date: Sun, 27 Nov 2022 22:18:49 +0100 Subject: [PATCH] FIR CFA: remove edge kind merging There shouldn't be any duplicate edges anymore. There probably weren't any before, either. --- .../dfa/cfg/ControlFlowGraphBuilder.kt | 14 ++--- .../kotlin/fir/resolve/dfa/cfg/CFGNode.kt | 60 +++++-------------- 2 files changed, 20 insertions(+), 54 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index 30447355615..ada7cacb9df 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -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) } } } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt index 8c1ca9e7f10..836ddb67192 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt @@ -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(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(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(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() }