From afe9f07cbc0986124927608c23fb0e4e3729de0f Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Tue, 24 Sep 2019 13:57:36 +0300 Subject: [PATCH] Added `Global hierarchy analysis` phase --- .../org/jetbrains/kotlin/backend/konan/Context.kt | 1 + .../jetbrains/kotlin/backend/konan/ToplevelPhases.kt | 2 ++ .../backend/konan/descriptors/ClassLayoutBuilder.kt | 6 +++--- .../kotlin/backend/konan/llvm/BitcodePhases.kt | 12 +++++++----- .../kotlin/backend/konan/llvm/CodeGenerator.kt | 2 +- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 2 +- .../kotlin/backend/konan/llvm/RTTIGenerator.kt | 8 ++++---- .../konan/llvm/objcexport/ObjCExportCodeGenerator.kt | 2 +- 8 files changed, 20 insertions(+), 15 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 55f402afc0f..1b5297d7f33 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -435,6 +435,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { fun shouldContainAnyDebugInfo() = shouldContainDebugInfo() || shouldContainLocationDebugInfo() fun shouldOptimize() = config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION) + fun ghaEnabled() = ::globalHierarchyAnalysisResult.isInitialized val memoryModel = config.memoryModel diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index 35e3ec5b832..6103452f34f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -361,6 +361,7 @@ internal val bitcodePhase = namedIrModulePhase( devirtualizationPhase then dcePhase then contextLLVMSetupPhase then + ghaPhase then RTTIPhase then generateDebugInfoHeaderPhase then escapeAnalysisPhase then @@ -424,6 +425,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) { disableUnless(buildDFGPhase, getBoolean(KonanConfigKeys.OPTIMIZATION)) disableUnless(devirtualizationPhase, getBoolean(KonanConfigKeys.OPTIMIZATION)) disableUnless(dcePhase, getBoolean(KonanConfigKeys.OPTIMIZATION)) + disableUnless(ghaPhase, getBoolean(KonanConfigKeys.OPTIMIZATION)) disableUnless(verifyBitcodePhase, config.needCompilerVerification || getBoolean(KonanConfigKeys.VERIFY_BITCODE)) } } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt index 39c6a683bfa..b1f3f563558 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt @@ -93,7 +93,7 @@ internal class ClassGlobalHierarchyInfo(val classIdLo: Int, val classIdHi: Int, internal class GlobalHierarchyAnalysisResult(val bitsPerColor: Int) -internal class GlobalHierarchyAnalysis(val context: Context) { +internal class GlobalHierarchyAnalysis(val context: Context, val irModule: IrModuleFragment) { fun run() { /* * The algorithm for fast interface call and check: @@ -142,7 +142,7 @@ internal class GlobalHierarchyAnalysis(val context: Context) { val root = context.irBuiltIns.anyClass.owner val immediateInheritors = mutableMapOf>() val allClasses = mutableListOf() - context.irModule!!.acceptVoid(object: IrElementVisitorVoid { + irModule.acceptVoid(object: IrElementVisitorVoid { override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) } @@ -251,7 +251,7 @@ internal class GlobalHierarchyAnalysis(val context: Context) { } private fun assignColorsToInterfaces(): Map { - val graph = InterfacesForbiddennessGraph.build(context.irModule!!) + val graph = InterfacesForbiddennessGraph.build(irModule) val coloring = graph.computeColoringGreedy() return graph.nodes.mapIndexed { v, irClass -> irClass to coloring[v] }.toMap() } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt index bb906ae36cf..c624cb40861 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt @@ -38,11 +38,7 @@ internal val contextLLVMSetupPhase = makeKonanModuleOpPhase( internal val RTTIPhase = makeKonanModuleOpPhase( name = "RTTI", description = "RTTI generation", - op = { context, irModule -> - if (context.shouldOptimize()) - GlobalHierarchyAnalysis(context).run() - irModule.acceptVoid(RTTIGeneratorVisitor(context)) - } + op = { context, irModule -> irModule.acceptVoid(RTTIGeneratorVisitor(context)) } ) internal val generateDebugInfoHeaderPhase = makeKonanModuleOpPhase( @@ -82,6 +78,12 @@ internal val devirtualizationPhase = makeKonanModuleOpPhase( } ) +internal val ghaPhase = makeKonanModuleOpPhase( + name = "GHAPhase", + description = "Global hierarchy analysis", + op = { context, irModule -> GlobalHierarchyAnalysis(context, irModule).run() } +) + internal val IrFunction.longName: String get() = "${(parent as? IrClass)?.name?.asString() ?: ""}.${(this as? IrSimpleFunction)?.name ?: ""}" diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index e5ca9c45569..fcdbda51574 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -779,7 +779,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, load(slot) } - !context.shouldOptimize() -> call(context.llvm.lookupOpenMethodFunction, listOf(typeInfoPtr, methodHash)) + !context.ghaEnabled() -> call(context.llvm.lookupOpenMethodFunction, listOf(typeInfoPtr, methodHash)) else -> { // Essentially: typeInfo.itable[place(interfaceId)].vtable[method] diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 67d3afef39e..445f0acf168 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1392,7 +1392,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map { - val needInterfaceTable = context.shouldOptimize() && !irClass.isInterface + val needInterfaceTable = context.ghaEnabled() && !irClass.isInterface && !irClass.isAbstract() && !irClass.isObjCClass() if (!needInterfaceTable) return Pair(null, 0) // The details are in ClassLayoutBuilder. @@ -484,12 +484,12 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { val typeInfoWithVtableType = structType(runtime.typeInfoType, vtable.llvmType) val typeInfoWithVtableGlobal = staticData.createGlobal(typeInfoWithVtableType, "", isExported = false) val result = typeInfoWithVtableGlobal.pointer.getElementPtr(0) - val typeHierarchyInfo = if (!context.shouldOptimize()) + val typeHierarchyInfo = if (!context.ghaEnabled()) ClassGlobalHierarchyInfo.DUMMY else ClassGlobalHierarchyInfo(-1, -1, 0, 0) - val interfaceTable = if (!context.shouldOptimize()) null else { + val interfaceTable = if (!context.ghaEnabled()) null else { val layoutBuilder = context.getLayoutBuilder(irClass) val vtableEntries = layoutBuilder.interfaceTableEntries.map { methodImpls[it]!!.bitcast(int8TypePtr) } val interfaceVTable = staticData.placeGlobalArray("", kInt8Ptr, vtableEntries) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index 02277967480..503280cc1c0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -932,7 +932,7 @@ private fun ObjCExportCodeGenerator.vtableIndex(irFunction: IrSimpleFunction): I private fun ObjCExportCodeGenerator.itablePlace(irFunction: IrSimpleFunction): ClassLayoutBuilder.InterfaceTablePlace? { assert(irFunction.isOverridable) val irClass = irFunction.parentAsClass - return if (irClass.isInterface && context.shouldOptimize() + return if (irClass.isInterface && context.ghaEnabled() && (irFunction.isReal || irFunction.resolveFakeOverrideMaybeAbstract().parent != context.irBuiltIns.anyClass.owner)) { context.getLayoutBuilder(irClass).itablePlace(irFunction) } else {