[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.library.SerializedMetadata
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
|
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.ExternalModulesDFG
|
||||||
import org.jetbrains.kotlin.backend.konan.optimizations.ModuleDFG
|
import org.jetbrains.kotlin.backend.konan.optimizations.ModuleDFG
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
@@ -462,7 +462,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
|||||||
var externalModulesDFG: ExternalModulesDFG? = null
|
var externalModulesDFG: ExternalModulesDFG? = null
|
||||||
lateinit var lifetimes: MutableMap<IrElement, Lifetime>
|
lateinit var lifetimes: MutableMap<IrElement, Lifetime>
|
||||||
lateinit var codegenVisitor: CodeGeneratorVisitor
|
lateinit var codegenVisitor: CodeGeneratorVisitor
|
||||||
var devirtualizationAnalysisResult: Devirtualization.AnalysisResult? = null
|
var devirtualizationAnalysisResult: DevirtualizationAnalysis.AnalysisResult? = null
|
||||||
|
|
||||||
var referencedFunctions: Set<IrFunction>? = null
|
var referencedFunctions: Set<IrFunction>? = null
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -374,10 +374,11 @@ internal val bitcodePhase = NamedCompilerPhase(
|
|||||||
description = "LLVM Bitcode generation",
|
description = "LLVM Bitcode generation",
|
||||||
lower = contextLLVMSetupPhase then
|
lower = contextLLVMSetupPhase then
|
||||||
buildDFGPhase then
|
buildDFGPhase then
|
||||||
devirtualizationPhase then
|
devirtualizationAnalysisPhase then
|
||||||
redundantCoercionsCleaningPhase then
|
|
||||||
dcePhase then
|
dcePhase then
|
||||||
removeRedundantCallsToFileInitializersPhase then
|
removeRedundantCallsToFileInitializersPhase then
|
||||||
|
devirtualizationPhase then
|
||||||
|
redundantCoercionsCleaningPhase then
|
||||||
createLLVMDeclarationsPhase then
|
createLLVMDeclarationsPhase then
|
||||||
ghaPhase then
|
ghaPhase then
|
||||||
RTTIPhase then
|
RTTIPhase then
|
||||||
@@ -464,6 +465,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
|
|||||||
disableUnless(linkerPhase, config.produce.involvesLinkStage)
|
disableUnless(linkerPhase, config.produce.involvesLinkStage)
|
||||||
disableIf(testProcessorPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) == TestRunnerKind.NONE)
|
disableIf(testProcessorPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) == TestRunnerKind.NONE)
|
||||||
disableUnless(buildDFGPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
disableUnless(buildDFGPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
||||||
|
disableUnless(devirtualizationAnalysisPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
||||||
disableUnless(devirtualizationPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
disableUnless(devirtualizationPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
||||||
disableUnless(escapeAnalysisPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
disableUnless(escapeAnalysisPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
||||||
// Inline accessors only in optimized builds due to separate compilation and possibility to get broken
|
// 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) } }
|
op = { context, irModule -> irModule.files.forEach { ReturnsInsertionLowering(context).lower(it) } }
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val devirtualizationPhase = makeKonanModuleOpPhase(
|
internal val devirtualizationAnalysisPhase = makeKonanModuleOpPhase(
|
||||||
name = "Devirtualization",
|
name = "DevirtualizationAnalysis",
|
||||||
description = "Devirtualization",
|
description = "Devirtualization analysis",
|
||||||
prerequisite = setOf(buildDFGPhase),
|
prerequisite = setOf(buildDFGPhase),
|
||||||
op = { context, irModule ->
|
op = { context, _ ->
|
||||||
context.devirtualizationAnalysisResult = Devirtualization.run(
|
context.devirtualizationAnalysisResult = DevirtualizationAnalysis.run(
|
||||||
irModule, context, context.moduleDFG!!, ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
|
context, context.moduleDFG!!, ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -150,7 +150,7 @@ internal val IrFunction.longName: String
|
|||||||
internal val dcePhase = makeKonanModuleOpPhase(
|
internal val dcePhase = makeKonanModuleOpPhase(
|
||||||
name = "DCEPhase",
|
name = "DCEPhase",
|
||||||
description = "Dead code elimination",
|
description = "Dead code elimination",
|
||||||
prerequisite = setOf(devirtualizationPhase),
|
prerequisite = setOf(devirtualizationAnalysisPhase),
|
||||||
op = { context, _ ->
|
op = { context, _ ->
|
||||||
val externalModulesDFG = ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
|
val externalModulesDFG = ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ internal val dcePhase = makeKonanModuleOpPhase(
|
|||||||
internal val removeRedundantCallsToFileInitializersPhase = makeKonanModuleOpPhase(
|
internal val removeRedundantCallsToFileInitializersPhase = makeKonanModuleOpPhase(
|
||||||
name = "RemoveRedundantCallsToFileInitializersPhase",
|
name = "RemoveRedundantCallsToFileInitializersPhase",
|
||||||
description = "Redundant file initializers calls removal",
|
description = "Redundant file initializers calls removal",
|
||||||
prerequisite = setOf(devirtualizationPhase),
|
prerequisite = setOf(devirtualizationAnalysisPhase),
|
||||||
op = { context, _ ->
|
op = { context, _ ->
|
||||||
val moduleDFG = context.moduleDFG!!
|
val moduleDFG = context.moduleDFG!!
|
||||||
val externalModulesDFG = ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
|
val externalModulesDFG = ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
|
||||||
@@ -259,8 +259,8 @@ internal val removeRedundantCallsToFileInitializersPhase = makeKonanModuleOpPhas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val rootSet = Devirtualization.computeRootSet(context, moduleDFG, externalModulesDFG).toSet()
|
val rootSet = DevirtualizationAnalysis.computeRootSet(context, moduleDFG, externalModulesDFG).toSet()
|
||||||
context.irModule!!.transformChildrenVoid(object: IrElementTransformerVoid() {
|
context.irModule!!.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||||
declaration.transformChildrenVoid(this)
|
declaration.transformChildrenVoid(this)
|
||||||
if (declaration in functionsBeingCalledFromOtherFiles
|
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(
|
internal val escapeAnalysisPhase = makeKonanModuleOpPhase(
|
||||||
name = "EscapeAnalysis",
|
name = "EscapeAnalysis",
|
||||||
description = "Escape analysis",
|
description = "Escape analysis",
|
||||||
prerequisite = setOf(buildDFGPhase, devirtualizationPhase),
|
prerequisite = setOf(buildDFGPhase, devirtualizationAnalysisPhase),
|
||||||
op = { context, _ ->
|
op = { context, _ ->
|
||||||
val entryPoint = context.ir.symbols.entryPoint?.owner
|
val entryPoint = context.ir.symbols.entryPoint?.owner
|
||||||
val externalModulesDFG = ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
|
val externalModulesDFG = ExternalModulesDFG(emptyList(), emptyMap(), emptyMap(), emptyMap())
|
||||||
@@ -314,7 +329,7 @@ internal val escapeAnalysisPhase = makeKonanModuleOpPhase(
|
|||||||
internal val localEscapeAnalysisPhase = makeKonanModuleOpPhase(
|
internal val localEscapeAnalysisPhase = makeKonanModuleOpPhase(
|
||||||
name = "LocalEscapeAnalysis",
|
name = "LocalEscapeAnalysis",
|
||||||
description = "Local escape analysis",
|
description = "Local escape analysis",
|
||||||
prerequisite = setOf(buildDFGPhase, devirtualizationPhase),
|
prerequisite = setOf(buildDFGPhase, devirtualizationAnalysisPhase),
|
||||||
op = { context, _ ->
|
op = { context, _ ->
|
||||||
LocalEscapeAnalysis.computeLifetimes(context, context.moduleDFG!!, context.lifetimes)
|
LocalEscapeAnalysis.computeLifetimes(context, context.moduleDFG!!, context.lifetimes)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -55,7 +55,7 @@ internal class CallGraphBuilder(
|
|||||||
val context: Context,
|
val context: Context,
|
||||||
val moduleDFG: ModuleDFG,
|
val moduleDFG: ModuleDFG,
|
||||||
val externalModulesDFG: ExternalModulesDFG,
|
val externalModulesDFG: ExternalModulesDFG,
|
||||||
val devirtualizationAnalysisResult: Devirtualization.AnalysisResult,
|
val devirtualizationAnalysisResult: DevirtualizationAnalysis.AnalysisResult,
|
||||||
val nonDevirtualizedCallSitesUnfoldFactor: Int
|
val nonDevirtualizedCallSitesUnfoldFactor: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ internal class CallGraphBuilder(
|
|||||||
private val functionStack = mutableListOf<HandleFunctionParams>()
|
private val functionStack = mutableListOf<HandleFunctionParams>()
|
||||||
|
|
||||||
fun build(): CallGraph {
|
fun build(): CallGraph {
|
||||||
val rootSet = Devirtualization.computeRootSet(context, moduleDFG, externalModulesDFG)
|
val rootSet = DevirtualizationAnalysis.computeRootSet(context, moduleDFG, externalModulesDFG)
|
||||||
for (symbol in rootSet) {
|
for (symbol in rootSet) {
|
||||||
val function = moduleDFG.functions[symbol]
|
val function = moduleDFG.functions[symbol]
|
||||||
if (function == null)
|
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.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
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.symbols.impl.IrVariableSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
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.irCall
|
||||||
import org.jetbrains.kotlin.ir.util.explicitParameters
|
import org.jetbrains.kotlin.ir.util.explicitParameters
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
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.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
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.
|
// 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.
|
// 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).
|
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].
|
private val VIRTUAL_TYPE_ID = 0 // Id of [DataFlowIR.Type.Virtual].
|
||||||
|
|
||||||
internal class DevirtualizationAnalysis(val context: Context,
|
internal class DevirtualizationAnalysisImpl(val context: Context,
|
||||||
val moduleDFG: ModuleDFG,
|
val moduleDFG: ModuleDFG,
|
||||||
val externalModulesDFG: ExternalModulesDFG) {
|
val externalModulesDFG: ExternalModulesDFG) {
|
||||||
|
|
||||||
private val entryPoint = context.ir.symbols.entryPoint?.owner
|
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 DevirtualizedCallSite(val callee: DataFlowIR.FunctionSymbol, val possibleCallees: List<DevirtualizedCallee>)
|
||||||
|
|
||||||
class AnalysisResult(val devirtualizedCallSites: Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite>,
|
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)
|
fun run(context: Context, moduleDFG: ModuleDFG, externalModulesDFG: ExternalModulesDFG) =
|
||||||
: AnalysisResult {
|
DevirtualizationAnalysisImpl(context, moduleDFG, externalModulesDFG).analyze()
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun devirtualize(irModule: IrModuleFragment, context: Context, externalModulesDFG: ExternalModulesDFG,
|
fun devirtualize(irModule: IrModuleFragment, context: Context, externalModulesDFG: ExternalModulesDFG,
|
||||||
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
|
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
|
||||||
val symbols = context.ir.symbols
|
val symbols = context.ir.symbols
|
||||||
val nativePtrEqualityOperatorSymbol = symbols.areEqualByValue[PrimitiveBinaryType.POINTER]!!
|
val nativePtrEqualityOperatorSymbol = symbols.areEqualByValue[PrimitiveBinaryType.POINTER]!!
|
||||||
val optimize = context.shouldOptimize()
|
val optimize = context.shouldOptimize()
|
||||||
Reference in New Issue
Block a user