diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index a25b91e0542..31be973f001 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -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 lateinit var codegenVisitor: CodeGeneratorVisitor - var devirtualizationAnalysisResult: Devirtualization.AnalysisResult? = null + var devirtualizationAnalysisResult: DevirtualizationAnalysis.AnalysisResult? = null var referencedFunctions: Set? = null diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index c221d868336..0e0beacf12e 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -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 diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt index ad4c9539131..a1c7643c559 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt @@ -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) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt index 219c99de237..9e9b935ca0b 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt @@ -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() 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) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DevirtualizationAnalysis.kt similarity index 98% rename from kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt rename to kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DevirtualizationAnalysis.kt index 8f6ace31ad3..b376f689488 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/Devirtualization.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DevirtualizationAnalysis.kt @@ -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) class AnalysisResult(val devirtualizedCallSites: Map, - 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) { + fun devirtualize(irModule: IrModuleFragment, context: Context, externalModulesDFG: ExternalModulesDFG, + devirtualizedCallSites: Map) { val symbols = context.ir.symbols val nativePtrEqualityOperatorSymbol = symbols.areEqualByValue[PrimitiveBinaryType.POINTER]!! val optimize = context.shouldOptimize()