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")
|
||||
var devirtualizationAnalysisResult: Map<DataFlowIR.Node.VirtualCall, Devirtualization.DevirtualizedCallSite>? = null
|
||||
var devirtualizationAnalysisResult: Devirtualization.AnalysisResult? = null
|
||||
phaser.phase(KonanPhase.DEVIRTUALIZATION) {
|
||||
devirtualizationAnalysisResult = Devirtualization.run(irModule, context, moduleDFG!!, externalModulesDFG!!)
|
||||
|
||||
@@ -107,7 +107,7 @@ internal fun emitLLVM(context: Context) {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
+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.DirectedGraphNode
|
||||
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)
|
||||
: DirectedGraphNode<DataFlowIR.FunctionSymbol> {
|
||||
@@ -37,7 +35,7 @@ internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.Functi
|
||||
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>()
|
||||
}
|
||||
@@ -59,7 +57,9 @@ internal class CallGraph(val directEdges: Map<DataFlowIR.FunctionSymbol, CallGra
|
||||
|
||||
internal class CallGraphBuilder(val context: Context,
|
||||
val moduleDFG: ModuleDFG,
|
||||
val externalModulesDFG: ExternalModulesDFG) {
|
||||
val externalModulesDFG: ExternalModulesDFG,
|
||||
devirtualizationAnalysisResult: Devirtualization.AnalysisResult?,
|
||||
val gotoExternal: Boolean) {
|
||||
|
||||
private val DEBUG = 0
|
||||
|
||||
@@ -67,15 +67,7 @@ internal class CallGraphBuilder(val context: Context,
|
||||
if (DEBUG > severity) block()
|
||||
}
|
||||
|
||||
private val hasMain = context.config.configuration.get(KonanConfigKeys.PRODUCE) == CompilerOutputKind.PROGRAM
|
||||
|
||||
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 val devirtualizedCallSites = devirtualizationAnalysisResult?.devirtualizedCallSites
|
||||
|
||||
private fun DataFlowIR.FunctionSymbol.resolved(): DataFlowIR.FunctionSymbol {
|
||||
if (this is DataFlowIR.FunctionSymbol.External)
|
||||
@@ -83,46 +75,92 @@ internal class CallGraphBuilder(val context: Context,
|
||||
return this
|
||||
}
|
||||
|
||||
private fun DataFlowIR.Type.Declared.isSubtypeOf(other: DataFlowIR.Type.Declared): Boolean {
|
||||
return this == other || this.superTypes.any { it.resolved().isSubtypeOf(other) }
|
||||
}
|
||||
|
||||
private val visitedFunctions = mutableSetOf<DataFlowIR.FunctionSymbol>()
|
||||
private val directEdges = mutableMapOf<DataFlowIR.FunctionSymbol, CallGraphNode>()
|
||||
private val reversedEdges = mutableMapOf<DataFlowIR.FunctionSymbol, MutableList<DataFlowIR.FunctionSymbol>>()
|
||||
private val callGraph = CallGraph(directEdges, reversedEdges)
|
||||
|
||||
fun build(): CallGraph {
|
||||
val rootSet = if (hasMain) {
|
||||
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>()
|
||||
}
|
||||
val rootSet = Devirtualization.computeRootSet(context, moduleDFG, externalModulesDFG)
|
||||
@Suppress("LoopToCallChain")
|
||||
for (symbol in rootSet) {
|
||||
if (!directEdges.containsKey(symbol))
|
||||
if (!visitedFunctions.contains(symbol))
|
||||
dfs(symbol)
|
||||
}
|
||||
return callGraph
|
||||
}
|
||||
|
||||
private fun dfs(symbol: DataFlowIR.FunctionSymbol) {
|
||||
private fun addNode(symbol: DataFlowIR.FunctionSymbol) {
|
||||
if (directEdges.containsKey(symbol))
|
||||
return
|
||||
val node = CallGraphNode(callGraph, symbol)
|
||||
directEdges.put(symbol, node)
|
||||
val list = mutableListOf<DataFlowIR.FunctionSymbol>()
|
||||
reversedEdges.put(symbol, list)
|
||||
val function = moduleDFG.functions[symbol] ?: externalModulesDFG.functionDFGs[symbol]
|
||||
val body = function!!.body
|
||||
body.nodes.filterIsInstance<DataFlowIR.Node.Call>()
|
||||
.forEach {
|
||||
val callee = it.callee.resolved()
|
||||
callGraph.addEdge(symbol, CallGraphNode.CallSite(it, callee))
|
||||
if (callee is DataFlowIR.FunctionSymbol.Declared
|
||||
&& it !is DataFlowIR.Node.VirtualCall
|
||||
&& !directEdges.containsKey(callee))
|
||||
dfs(callee)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dfs(symbol: DataFlowIR.FunctionSymbol) {
|
||||
visitedFunctions += symbol
|
||||
if (gotoExternal) {
|
||||
addNode(symbol)
|
||||
val function = moduleDFG.functions[symbol] ?: externalModulesDFG.functionDFGs[symbol]
|
||||
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()
|
||||
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 AnalysisResult(val devirtualizedCallSites: Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite>)
|
||||
|
||||
fun run(irModule: IrModuleFragment, context: Context, moduleDFG: ModuleDFG, externalModulesDFG: ExternalModulesDFG)
|
||||
: Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite> {
|
||||
: AnalysisResult {
|
||||
val devirtualizationAnalysisResult = DevirtualizationAnalysis(context, moduleDFG, externalModulesDFG).analyze()
|
||||
val devirtualizedCallSites =
|
||||
devirtualizationAnalysisResult
|
||||
@@ -897,7 +899,7 @@ internal object Devirtualization {
|
||||
.filter { it.key.callSite != null }
|
||||
.associate { it.key.callSite!! to it.value }
|
||||
Devirtualization.devirtualize(irModule, context, devirtualizedCallSites)
|
||||
return devirtualizationAnalysisResult
|
||||
return AnalysisResult(devirtualizationAnalysisResult)
|
||||
}
|
||||
|
||||
private fun devirtualize(irModule: IrModuleFragment, context: Context,
|
||||
|
||||
Reference in New Issue
Block a user