Call graph building using devirtualization analysis results
This commit is contained in:
+2
-2
@@ -87,7 +87,7 @@ internal fun emitLLVM(context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||||
var devirtualizationAnalysisResult: Map<DataFlowIR.Node.VirtualCall, Devirtualization.DevirtualizedCallSite>? = null
|
var devirtualizationAnalysisResult: Devirtualization.AnalysisResult? = null
|
||||||
phaser.phase(KonanPhase.DEVIRTUALIZATION) {
|
phaser.phase(KonanPhase.DEVIRTUALIZATION) {
|
||||||
devirtualizationAnalysisResult = Devirtualization.run(irModule, context, moduleDFG!!, externalModulesDFG!!)
|
devirtualizationAnalysisResult = Devirtualization.run(irModule, context, moduleDFG!!, externalModulesDFG!!)
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ internal fun emitLLVM(context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
phaser.phase(KonanPhase.ESCAPE_ANALYSIS) {
|
phaser.phase(KonanPhase.ESCAPE_ANALYSIS) {
|
||||||
val callGraph = CallGraphBuilder(context, moduleDFG!!, externalModulesDFG!!).build()
|
val callGraph = CallGraphBuilder(context, moduleDFG!!, externalModulesDFG!!, devirtualizationAnalysisResult, false).build()
|
||||||
EscapeAnalysis.computeLifetimes(moduleDFG!!, externalModulesDFG!!, callGraph, lifetimes)
|
EscapeAnalysis.computeLifetimes(moduleDFG!!, externalModulesDFG!!, callGraph, lifetimes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+76
-38
@@ -19,8 +19,6 @@ package org.jetbrains.kotlin.backend.konan.optimizations
|
|||||||
import org.jetbrains.kotlin.backend.konan.DirectedGraph
|
import org.jetbrains.kotlin.backend.konan.DirectedGraph
|
||||||
import org.jetbrains.kotlin.backend.konan.DirectedGraphNode
|
import org.jetbrains.kotlin.backend.konan.DirectedGraphNode
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
|
||||||
|
|
||||||
internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.FunctionSymbol)
|
internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.FunctionSymbol)
|
||||||
: DirectedGraphNode<DataFlowIR.FunctionSymbol> {
|
: DirectedGraphNode<DataFlowIR.FunctionSymbol> {
|
||||||
@@ -37,7 +35,7 @@ internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.Functi
|
|||||||
graph.reversedEdges[symbol]!!
|
graph.reversedEdges[symbol]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
class CallSite(val call: DataFlowIR.Node.Call, val actualCallee: DataFlowIR.FunctionSymbol)
|
class CallSite(val call: DataFlowIR.Node.Call, val isVirtual: Boolean, val actualCallee: DataFlowIR.FunctionSymbol)
|
||||||
|
|
||||||
val callSites = mutableListOf<CallSite>()
|
val callSites = mutableListOf<CallSite>()
|
||||||
}
|
}
|
||||||
@@ -59,7 +57,9 @@ internal class CallGraph(val directEdges: Map<DataFlowIR.FunctionSymbol, CallGra
|
|||||||
|
|
||||||
internal class CallGraphBuilder(val context: Context,
|
internal class CallGraphBuilder(val context: Context,
|
||||||
val moduleDFG: ModuleDFG,
|
val moduleDFG: ModuleDFG,
|
||||||
val externalModulesDFG: ExternalModulesDFG) {
|
val externalModulesDFG: ExternalModulesDFG,
|
||||||
|
devirtualizationAnalysisResult: Devirtualization.AnalysisResult?,
|
||||||
|
val gotoExternal: Boolean) {
|
||||||
|
|
||||||
private val DEBUG = 0
|
private val DEBUG = 0
|
||||||
|
|
||||||
@@ -67,15 +67,7 @@ internal class CallGraphBuilder(val context: Context,
|
|||||||
if (DEBUG > severity) block()
|
if (DEBUG > severity) block()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val hasMain = context.config.configuration.get(KonanConfigKeys.PRODUCE) == CompilerOutputKind.PROGRAM
|
private val devirtualizedCallSites = devirtualizationAnalysisResult?.devirtualizedCallSites
|
||||||
|
|
||||||
private val symbolTable = moduleDFG.symbolTable
|
|
||||||
|
|
||||||
private fun DataFlowIR.Type.resolved(): DataFlowIR.Type.Declared {
|
|
||||||
if (this is DataFlowIR.Type.Declared) return this
|
|
||||||
val hash = (this as DataFlowIR.Type.External).hash
|
|
||||||
return externalModulesDFG.publicTypes[hash] ?: error("Unable to resolve exported type $hash")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun DataFlowIR.FunctionSymbol.resolved(): DataFlowIR.FunctionSymbol {
|
private fun DataFlowIR.FunctionSymbol.resolved(): DataFlowIR.FunctionSymbol {
|
||||||
if (this is DataFlowIR.FunctionSymbol.External)
|
if (this is DataFlowIR.FunctionSymbol.External)
|
||||||
@@ -83,46 +75,92 @@ internal class CallGraphBuilder(val context: Context,
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DataFlowIR.Type.Declared.isSubtypeOf(other: DataFlowIR.Type.Declared): Boolean {
|
private val visitedFunctions = mutableSetOf<DataFlowIR.FunctionSymbol>()
|
||||||
return this == other || this.superTypes.any { it.resolved().isSubtypeOf(other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private val directEdges = mutableMapOf<DataFlowIR.FunctionSymbol, CallGraphNode>()
|
private val directEdges = mutableMapOf<DataFlowIR.FunctionSymbol, CallGraphNode>()
|
||||||
private val reversedEdges = mutableMapOf<DataFlowIR.FunctionSymbol, MutableList<DataFlowIR.FunctionSymbol>>()
|
private val reversedEdges = mutableMapOf<DataFlowIR.FunctionSymbol, MutableList<DataFlowIR.FunctionSymbol>>()
|
||||||
private val callGraph = CallGraph(directEdges, reversedEdges)
|
private val callGraph = CallGraph(directEdges, reversedEdges)
|
||||||
|
|
||||||
fun build(): CallGraph {
|
fun build(): CallGraph {
|
||||||
val rootSet = if (hasMain) {
|
val rootSet = Devirtualization.computeRootSet(context, moduleDFG, externalModulesDFG)
|
||||||
listOf(symbolTable.mapFunction(context.ir.symbols.entryPoint!!.owner).resolved()) +
|
|
||||||
moduleDFG.functions
|
|
||||||
.map { it.key }
|
|
||||||
.filter { it.isGlobalInitializer }
|
|
||||||
} else {
|
|
||||||
moduleDFG.functions.keys.filterIsInstance<DataFlowIR.FunctionSymbol.Public>()
|
|
||||||
}
|
|
||||||
@Suppress("LoopToCallChain")
|
@Suppress("LoopToCallChain")
|
||||||
for (symbol in rootSet) {
|
for (symbol in rootSet) {
|
||||||
if (!directEdges.containsKey(symbol))
|
if (!visitedFunctions.contains(symbol))
|
||||||
dfs(symbol)
|
dfs(symbol)
|
||||||
}
|
}
|
||||||
return callGraph
|
return callGraph
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dfs(symbol: DataFlowIR.FunctionSymbol) {
|
private fun addNode(symbol: DataFlowIR.FunctionSymbol) {
|
||||||
|
if (directEdges.containsKey(symbol))
|
||||||
|
return
|
||||||
val node = CallGraphNode(callGraph, symbol)
|
val node = CallGraphNode(callGraph, symbol)
|
||||||
directEdges.put(symbol, node)
|
directEdges.put(symbol, node)
|
||||||
val list = mutableListOf<DataFlowIR.FunctionSymbol>()
|
val list = mutableListOf<DataFlowIR.FunctionSymbol>()
|
||||||
reversedEdges.put(symbol, list)
|
reversedEdges.put(symbol, list)
|
||||||
val function = moduleDFG.functions[symbol] ?: externalModulesDFG.functionDFGs[symbol]
|
}
|
||||||
val body = function!!.body
|
|
||||||
body.nodes.filterIsInstance<DataFlowIR.Node.Call>()
|
private fun dfs(symbol: DataFlowIR.FunctionSymbol) {
|
||||||
.forEach {
|
visitedFunctions += symbol
|
||||||
val callee = it.callee.resolved()
|
if (gotoExternal) {
|
||||||
callGraph.addEdge(symbol, CallGraphNode.CallSite(it, callee))
|
addNode(symbol)
|
||||||
if (callee is DataFlowIR.FunctionSymbol.Declared
|
val function = moduleDFG.functions[symbol] ?: externalModulesDFG.functionDFGs[symbol]
|
||||||
&& it !is DataFlowIR.Node.VirtualCall
|
val body = function!!.body
|
||||||
&& !directEdges.containsKey(callee))
|
body.nodes.filterIsInstance<DataFlowIR.Node.Call>()
|
||||||
dfs(callee)
|
.forEach { call ->
|
||||||
}
|
val devirtualizedCallSite = (call as? DataFlowIR.Node.VirtualCall)?.let { devirtualizedCallSites?.get(it) }
|
||||||
|
if (devirtualizedCallSite == null) {
|
||||||
|
val callee = call.callee.resolved()
|
||||||
|
callGraph.addEdge(symbol, CallGraphNode.CallSite(call, call is DataFlowIR.Node.VirtualCall, callee))
|
||||||
|
if (callee is DataFlowIR.FunctionSymbol.Declared
|
||||||
|
&& call !is DataFlowIR.Node.VirtualCall
|
||||||
|
&& !directEdges.containsKey(callee))
|
||||||
|
dfs(callee)
|
||||||
|
} else {
|
||||||
|
devirtualizedCallSite.possibleCallees.forEach {
|
||||||
|
val callee = it.callee.resolved()
|
||||||
|
callGraph.addEdge(symbol, CallGraphNode.CallSite(call, false, callee))
|
||||||
|
if (callee is DataFlowIR.FunctionSymbol.Declared
|
||||||
|
&& !directEdges.containsKey(callee))
|
||||||
|
dfs(callee)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var function = moduleDFG.functions[symbol]
|
||||||
|
var local = true
|
||||||
|
if (function != null)
|
||||||
|
addNode(symbol)
|
||||||
|
else {
|
||||||
|
function = externalModulesDFG.functionDFGs[symbol]!!
|
||||||
|
local = false
|
||||||
|
}
|
||||||
|
val body = function.body
|
||||||
|
body.nodes.filterIsInstance<DataFlowIR.Node.Call>()
|
||||||
|
.forEach { call ->
|
||||||
|
val devirtualizedCallSite = (call as? DataFlowIR.Node.VirtualCall)?.let { devirtualizedCallSites?.get(it) }
|
||||||
|
if (devirtualizedCallSite == null) {
|
||||||
|
val callee = call.callee.resolved()
|
||||||
|
if (moduleDFG.functions.containsKey(callee))
|
||||||
|
addNode(callee)
|
||||||
|
if (local)
|
||||||
|
callGraph.addEdge(symbol, CallGraphNode.CallSite(call, call is DataFlowIR.Node.VirtualCall, callee))
|
||||||
|
if (callee is DataFlowIR.FunctionSymbol.Declared
|
||||||
|
&& call !is DataFlowIR.Node.VirtualCall
|
||||||
|
&& !visitedFunctions.contains(callee))
|
||||||
|
dfs(callee)
|
||||||
|
} else {
|
||||||
|
devirtualizedCallSite.possibleCallees.forEach {
|
||||||
|
val callee = it.callee.resolved()
|
||||||
|
if (moduleDFG.functions.containsKey(callee))
|
||||||
|
addNode(callee)
|
||||||
|
if (local)
|
||||||
|
callGraph.addEdge(symbol, CallGraphNode.CallSite(call, false, callee))
|
||||||
|
if (callee is DataFlowIR.FunctionSymbol.Declared
|
||||||
|
&& !visitedFunctions.contains(callee))
|
||||||
|
dfs(callee)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+4
-2
@@ -888,8 +888,10 @@ internal object Devirtualization {
|
|||||||
|
|
||||||
class DevirtualizedCallSite(val possibleCallees: List<DevirtualizedCallee>)
|
class DevirtualizedCallSite(val possibleCallees: List<DevirtualizedCallee>)
|
||||||
|
|
||||||
|
class AnalysisResult(val devirtualizedCallSites: Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite>)
|
||||||
|
|
||||||
fun run(irModule: IrModuleFragment, context: Context, moduleDFG: ModuleDFG, externalModulesDFG: ExternalModulesDFG)
|
fun run(irModule: IrModuleFragment, context: Context, moduleDFG: ModuleDFG, externalModulesDFG: ExternalModulesDFG)
|
||||||
: Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite> {
|
: AnalysisResult {
|
||||||
val devirtualizationAnalysisResult = DevirtualizationAnalysis(context, moduleDFG, externalModulesDFG).analyze()
|
val devirtualizationAnalysisResult = DevirtualizationAnalysis(context, moduleDFG, externalModulesDFG).analyze()
|
||||||
val devirtualizedCallSites =
|
val devirtualizedCallSites =
|
||||||
devirtualizationAnalysisResult
|
devirtualizationAnalysisResult
|
||||||
@@ -897,7 +899,7 @@ internal object Devirtualization {
|
|||||||
.filter { it.key.callSite != null }
|
.filter { it.key.callSite != null }
|
||||||
.associate { it.key.callSite!! to it.value }
|
.associate { it.key.callSite!! to it.value }
|
||||||
Devirtualization.devirtualize(irModule, context, devirtualizedCallSites)
|
Devirtualization.devirtualize(irModule, context, devirtualizedCallSites)
|
||||||
return devirtualizationAnalysisResult
|
return AnalysisResult(devirtualizationAnalysisResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun devirtualize(irModule: IrModuleFragment, context: Context,
|
private fun devirtualize(irModule: IrModuleFragment, context: Context,
|
||||||
|
|||||||
Reference in New Issue
Block a user