[K/N][IR] Split Devirtualization onto phases

The analysis itself and applying its results to the IR
This commit is contained in:
Igor Chevdar
2021-03-22 18:12:12 +05:00
parent b11201be81
commit 9c6943b8c4
5 changed files with 44 additions and 41 deletions
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.backend.konan.ir.KonanIr
import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
import org.jetbrains.kotlin.backend.konan.optimizations.Devirtualization
import org.jetbrains.kotlin.backend.konan.optimizations.DevirtualizationAnalysis
import org.jetbrains.kotlin.backend.konan.optimizations.ExternalModulesDFG
import org.jetbrains.kotlin.backend.konan.optimizations.ModuleDFG
import org.jetbrains.kotlin.descriptors.*
@@ -462,7 +462,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
var externalModulesDFG: ExternalModulesDFG? = null
lateinit var lifetimes: MutableMap<IrElement, Lifetime>
lateinit var codegenVisitor: CodeGeneratorVisitor
var devirtualizationAnalysisResult: Devirtualization.AnalysisResult? = null
var devirtualizationAnalysisResult: DevirtualizationAnalysis.AnalysisResult? = null
var referencedFunctions: Set<IrFunction>? = null
@@ -374,10 +374,11 @@ internal val bitcodePhase = NamedCompilerPhase(
description = "LLVM Bitcode generation",
lower = contextLLVMSetupPhase then
buildDFGPhase then
devirtualizationPhase then
redundantCoercionsCleaningPhase then
devirtualizationAnalysisPhase then
dcePhase then
removeRedundantCallsToFileInitializersPhase then
devirtualizationPhase then
redundantCoercionsCleaningPhase then
createLLVMDeclarationsPhase then
ghaPhase then
RTTIPhase then
@@ -464,6 +465,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
disableUnless(linkerPhase, config.produce.involvesLinkStage)
disableIf(testProcessorPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) == TestRunnerKind.NONE)
disableUnless(buildDFGPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
disableUnless(devirtualizationAnalysisPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
disableUnless(devirtualizationPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
disableUnless(escapeAnalysisPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
// Inline accessors only in optimized builds due to separate compilation and possibility to get broken
@@ -121,13 +121,13 @@ internal val returnsInsertionPhase = makeKonanModuleOpPhase(
op = { context, irModule -> irModule.files.forEach { ReturnsInsertionLowering(context).lower(it) } }
)
internal val devirtualizationPhase = makeKonanModuleOpPhase(
name = "Devirtualization",
description = "Devirtualization",
internal val devirtualizationAnalysisPhase = makeKonanModuleOpPhase(
name = "DevirtualizationAnalysis",
description = "Devirtualization analysis",
prerequisite = setOf(buildDFGPhase),
op = { context, irModule ->
context.devirtualizationAnalysisResult = Devirtualization.run(
irModule, context, context.moduleDFG!!, ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
op = { context, _ ->
context.devirtualizationAnalysisResult = DevirtualizationAnalysis.run(
context, context.moduleDFG!!, ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
)
}
)
@@ -150,7 +150,7 @@ internal val IrFunction.longName: String
internal val dcePhase = makeKonanModuleOpPhase(
name = "DCEPhase",
description = "Dead code elimination",
prerequisite = setOf(devirtualizationPhase),
prerequisite = setOf(devirtualizationAnalysisPhase),
op = { context, _ ->
val externalModulesDFG = ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
@@ -236,7 +236,7 @@ internal val dcePhase = makeKonanModuleOpPhase(
internal val removeRedundantCallsToFileInitializersPhase = makeKonanModuleOpPhase(
name = "RemoveRedundantCallsToFileInitializersPhase",
description = "Redundant file initializers calls removal",
prerequisite = setOf(devirtualizationPhase),
prerequisite = setOf(devirtualizationAnalysisPhase),
op = { context, _ ->
val moduleDFG = context.moduleDFG!!
val externalModulesDFG = ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
@@ -259,8 +259,8 @@ internal val removeRedundantCallsToFileInitializersPhase = makeKonanModuleOpPhas
}
}
val rootSet = Devirtualization.computeRootSet(context, moduleDFG, externalModulesDFG).toSet()
context.irModule!!.transformChildrenVoid(object: IrElementTransformerVoid() {
val rootSet = DevirtualizationAnalysis.computeRootSet(context, moduleDFG, externalModulesDFG).toSet()
context.irModule!!.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitFunction(declaration: IrFunction): IrStatement {
declaration.transformChildrenVoid(this)
if (declaration in functionsBeingCalledFromOtherFiles
@@ -278,10 +278,25 @@ internal val removeRedundantCallsToFileInitializersPhase = makeKonanModuleOpPhas
}
)
internal val devirtualizationPhase = makeKonanModuleOpPhase(
name = "Devirtualization",
description = "Devirtualization",
prerequisite = setOf(buildDFGPhase, devirtualizationAnalysisPhase),
op = { context, irModule ->
val devirtualizedCallSites =
context.devirtualizationAnalysisResult!!.devirtualizedCallSites
.asSequence()
.filter { it.key.irCallSite != null }
.associate { it.key.irCallSite!! to it.value }
DevirtualizationAnalysis.devirtualize(irModule, context,
ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap()), devirtualizedCallSites)
}
)
internal val escapeAnalysisPhase = makeKonanModuleOpPhase(
name = "EscapeAnalysis",
description = "Escape analysis",
prerequisite = setOf(buildDFGPhase, devirtualizationPhase),
prerequisite = setOf(buildDFGPhase, devirtualizationAnalysisPhase),
op = { context, _ ->
val entryPoint = context.ir.symbols.entryPoint?.owner
val externalModulesDFG = ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
@@ -314,7 +329,7 @@ internal val escapeAnalysisPhase = makeKonanModuleOpPhase(
internal val localEscapeAnalysisPhase = makeKonanModuleOpPhase(
name = "LocalEscapeAnalysis",
description = "Local escape analysis",
prerequisite = setOf(buildDFGPhase, devirtualizationPhase),
prerequisite = setOf(buildDFGPhase, devirtualizationAnalysisPhase),
op = { context, _ ->
LocalEscapeAnalysis.computeLifetimes(context, context.moduleDFG!!, context.lifetimes)
}
@@ -55,7 +55,7 @@ internal class CallGraphBuilder(
val context: Context,
val moduleDFG: ModuleDFG,
val externalModulesDFG: ExternalModulesDFG,
val devirtualizationAnalysisResult: Devirtualization.AnalysisResult,
val devirtualizationAnalysisResult: DevirtualizationAnalysis.AnalysisResult,
val nonDevirtualizedCallSitesUnfoldFactor: Int
) {
@@ -77,7 +77,7 @@ internal class CallGraphBuilder(
private val functionStack = mutableListOf<HandleFunctionParams>()
fun build(): CallGraph {
val rootSet = Devirtualization.computeRootSet(context, moduleDFG, externalModulesDFG)
val rootSet = DevirtualizationAnalysis.computeRootSet(context, moduleDFG, externalModulesDFG)
for (symbol in rootSet) {
val function = moduleDFG.functions[symbol]
if (function == null)
@@ -24,16 +24,11 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.util.explicitParameters
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -52,7 +47,7 @@ inline fun BitSet.forEachBit(block: (Int) -> Unit) {
// Devirtualization analysis is performed using Variable Type Analysis algorithm.
// See http://web.cs.ucla.edu/~palsberg/tba/papers/sundaresan-et-al-oopsla00.pdf for details.
internal object Devirtualization {
internal object DevirtualizationAnalysis {
private val TAKE_NAMES = false // Take fqNames for all functions and types (for debug purposes).
@@ -120,9 +115,9 @@ internal object Devirtualization {
private val VIRTUAL_TYPE_ID = 0 // Id of [DataFlowIR.Type.Virtual].
internal class DevirtualizationAnalysis(val context: Context,
val moduleDFG: ModuleDFG,
val externalModulesDFG: ExternalModulesDFG) {
internal class DevirtualizationAnalysisImpl(val context: Context,
val moduleDFG: ModuleDFG,
val externalModulesDFG: ExternalModulesDFG) {
private val entryPoint = context.ir.symbols.entryPoint?.owner
@@ -1265,22 +1260,13 @@ internal object Devirtualization {
class DevirtualizedCallSite(val callee: DataFlowIR.FunctionSymbol, val possibleCallees: List<DevirtualizedCallee>)
class AnalysisResult(val devirtualizedCallSites: Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite>,
val typeHierarchy: DevirtualizationAnalysis.TypeHierarchy)
val typeHierarchy: DevirtualizationAnalysisImpl.TypeHierarchy)
fun run(irModule: IrModuleFragment, context: Context, moduleDFG: ModuleDFG, externalModulesDFG: ExternalModulesDFG)
: AnalysisResult {
val devirtualizationAnalysisResult = DevirtualizationAnalysis(context, moduleDFG, externalModulesDFG).analyze()
val devirtualizedCallSites =
devirtualizationAnalysisResult.devirtualizedCallSites
.asSequence()
.filter { it.key.irCallSite != null }
.associate { it.key.irCallSite!! to it.value }
devirtualize(irModule, context, externalModulesDFG, devirtualizedCallSites)
return devirtualizationAnalysisResult
}
fun run(context: Context, moduleDFG: ModuleDFG, externalModulesDFG: ExternalModulesDFG) =
DevirtualizationAnalysisImpl(context, moduleDFG, externalModulesDFG).analyze()
private fun devirtualize(irModule: IrModuleFragment, context: Context, externalModulesDFG: ExternalModulesDFG,
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
fun devirtualize(irModule: IrModuleFragment, context: Context, externalModulesDFG: ExternalModulesDFG,
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
val symbols = context.ir.symbols
val nativePtrEqualityOperatorSymbol = symbols.areEqualByValue[PrimitiveBinaryType.POINTER]!!
val optimize = context.shouldOptimize()