[K/N][IR] Split Devirtualization onto phases
The analysis itself and applying its results to the IR
This commit is contained in:
+2
-2
@@ -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
|
||||
|
||||
|
||||
+4
-2
@@ -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
|
||||
|
||||
+27
-12
@@ -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)
|
||||
}
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+9
-23
@@ -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()
|
||||
Reference in New Issue
Block a user