diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/BackendPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/BackendPhases.kt index 795dfb5b430..062463b5768 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/BackendPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/BackendPhases.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.NativeGenerationState import org.jetbrains.kotlin.backend.konan.driver.PhaseContext import org.jetbrains.kotlin.backend.konan.driver.PhaseEngine import org.jetbrains.kotlin.backend.konan.driver.utilities.KotlinBackendIrHolder +import org.jetbrains.kotlin.backend.konan.driver.utilities.getDefaultIrActions import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier import org.jetbrains.kotlin.backend.konan.lower.SpecialBackendChecksTraversal @@ -36,6 +37,8 @@ internal data class SpecialBackendChecksInput( internal val SpecialBackendChecksPhase = createSimpleNamedCompilerPhase( "SpecialBackendChecks", "Special backend checks", + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), ) { context, input -> SpecialBackendChecksTraversal(context, context.interopBuiltIns, input.symbols, input.irModule.irBuiltins).lower(input.irModule) } @@ -56,6 +59,8 @@ internal val K2SpecialBackendChecksPhase = createSimpleNamedCompilerPhase( name = "CopyDefaultValuesToActual", description = "Copy default values from expect to actual declarations", + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), ) { _, input -> ExpectToActualDefaultValueCopier(input).process() } @@ -70,7 +75,9 @@ internal fun PhaseEngine.runK2SpecialBackendChecks(fir2IrO internal val EntryPointPhase = createSimpleNamedCompilerPhase( name = "addEntryPoint", - description = "Add entry point for program" + description = "Add entry point for program", + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), ) { context, module -> val parent = context.context val entryPoint = parent.ir.symbols.entryPoint!!.owner diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/BitcodeGeneration.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/BitcodeGeneration.kt index 96ce1c29838..87f283ca52a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/BitcodeGeneration.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/BitcodeGeneration.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.konan.driver.phases import llvm.DIFinalize import org.jetbrains.kotlin.backend.konan.NativeGenerationState import org.jetbrains.kotlin.backend.konan.driver.utilities.KotlinBackendIrHolder +import org.jetbrains.kotlin.backend.konan.driver.utilities.getDefaultIrActions import org.jetbrains.kotlin.backend.konan.llvm.CodeGeneratorVisitor import org.jetbrains.kotlin.backend.konan.llvm.Lifetime import org.jetbrains.kotlin.backend.konan.llvm.RTTIGeneratorVisitor @@ -21,6 +22,8 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid internal val CreateLLVMDeclarationsPhase = createSimpleNamedCompilerPhase( name = "CreateLLVMDeclarations", description = "Map IR declarations to LLVM", + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), op = { generationState, module -> generationState.llvmDeclarations = createLlvmDeclarations(generationState, module) } @@ -37,6 +40,8 @@ internal data class RTTIInput( internal val RTTIPhase = createSimpleNamedCompilerPhase( name = "RTTI", description = "RTTI generation", + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), op = { generationState, input -> val visitor = RTTIGeneratorVisitor(generationState, input.referencedFunctions) input.irModule.acceptVoid(visitor) @@ -55,6 +60,8 @@ internal data class CodegenInput( internal val CodegenPhase = createSimpleNamedCompilerPhase( name = "Codegen", description = "Code generation", + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), op = { generationState, input -> val context = generationState.context generationState.objCExport = ObjCExport( diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/CacheBuilding.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/CacheBuilding.kt index 47baf67c3dd..94da8ec6103 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/CacheBuilding.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/CacheBuilding.kt @@ -10,12 +10,15 @@ import org.jetbrains.kotlin.backend.konan.NativeGenerationState import org.jetbrains.kotlin.backend.konan.OutputFiles import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary import org.jetbrains.kotlin.backend.konan.driver.PhaseContext +import org.jetbrains.kotlin.backend.konan.driver.utilities.getDefaultIrActions import org.jetbrains.kotlin.backend.konan.lower.CacheInfoBuilder import org.jetbrains.kotlin.ir.declarations.IrModuleFragment internal val BuildAdditionalCacheInfoPhase = createSimpleNamedCompilerPhase( name = "BuildAdditionalCacheInfo", description = "Build additional cache info (inline functions bodies and fields of classes)", + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), ) { context, module -> // TODO: Use explicit parameter val parent = context.context diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/LTO.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/LTO.kt index 4a8fe57c554..a400f3ed7cf 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/LTO.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/LTO.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.phaser.ActionState import org.jetbrains.kotlin.backend.konan.NativeGenerationState import org.jetbrains.kotlin.backend.konan.descriptors.GlobalHierarchyAnalysis import org.jetbrains.kotlin.backend.konan.driver.utilities.KotlinBackendIrHolder +import org.jetbrains.kotlin.backend.konan.driver.utilities.getDefaultIrActions import org.jetbrains.kotlin.backend.konan.llvm.Lifetime import org.jetbrains.kotlin.backend.konan.optimizations.* import org.jetbrains.kotlin.backend.konan.optimizations.DevirtualizationAnalysis @@ -31,6 +32,8 @@ internal val GHAPhase = createSimpleNamedCompilerPhase( name = "BuildDFG", description = "Data flow graph building", + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), outputIfNotEnabled = { _, _, generationState, irModule -> val context = generationState.context val symbolTable = DataFlowIR.SymbolTable(context, DataFlowIR.Module(irModule.descriptor)) @@ -53,6 +56,8 @@ internal data class DevirtualizationAnalysisInput( internal val DevirtualizationAnalysisPhase = createSimpleNamedCompilerPhase( name = "DevirtualizationAnalysis", description = "Devirtualization analysis", + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), outputIfNotEnabled = { _, _, _, _ -> DevirtualizationAnalysis.AnalysisResult( emptyMap(), @@ -79,6 +84,8 @@ internal val DCEPhase = createSimpleNamedCompilerPhase null }, + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), op = { generationState, input -> val context = generationState.context dce(context, input.irModule, input.moduleDFG, input.devirtualizationAnalysisResult) @@ -93,13 +100,11 @@ internal data class DevirtualizationInput( get() = irModule } -internal val DevirtualizationPhase = createSimpleNamedCompilerPhase( +internal val DevirtualizationPhase = createSimpleNamedCompilerPhase( name = "Devirtualization", description = "Devirtualization", - postactions = modulePhaseActions.map { f -> - fun(actionState: ActionState, data: DevirtualizationInput, context: NativeGenerationState) = - f(actionState, data.irModule, context) - }.toSet(), + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), op = { generationState, input -> val context = generationState.context val devirtualizedCallSites = input.devirtualizationAnalysisResult.devirtualizedCallSites @@ -125,6 +130,8 @@ internal val EscapeAnalysisPhase = createSimpleNamedCompilerPhase emptyMap() }, + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), op = { generationState, input -> val lifetimes = mutableMapOf() val context = generationState.context @@ -165,13 +172,11 @@ internal data class RedundantCallsInput( get() = irModule } -internal val RemoveRedundantCallsToStaticInitializersPhase = createSimpleNamedCompilerPhase( +internal val RemoveRedundantCallsToStaticInitializersPhase = createSimpleNamedCompilerPhase( name = "RemoveRedundantCallsToStaticInitializersPhase", description = "Redundant static initializers calls removal", - postactions = modulePhaseActions.map { f -> - fun(actionState: ActionState, data: RedundantCallsInput, context: NativeGenerationState) = - f(actionState, data.irModule, context) - }.toSet(), + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), op = { generationState, input -> val context = generationState.context val moduleDFG = input.moduleDFG diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt index db2d8e99543..0caed92f8c1 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.konan.driver.PhaseEngine import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.driver.utilities.getDefaultIrActions import org.jetbrains.kotlin.backend.konan.ir.FunctionsWithoutBoundCheckGenerator import org.jetbrains.kotlin.backend.konan.lower.* import org.jetbrains.kotlin.backend.konan.lower.ImportCachesAbiTransformer @@ -50,18 +51,6 @@ internal fun PhaseEngine.runAllLowerings(irModuleFragment } } -private val validateAll = false - -private val fileLoweringActions: Set> = setOfNotNull( - nativeStateDumper, - nativeStateIrValidator.takeIf { validateAll } -) - -internal val modulePhaseActions: Set> = setOfNotNull( - nativeStateDumper, - nativeStateIrValidator.takeIf { validateAll } -) - internal val functionsWithoutBoundCheck = createSimpleNamedCompilerPhase( name = "FunctionsWithoutBoundCheckGenerator", description = "Functions without bounds check generation", @@ -555,7 +544,8 @@ private fun createFileLoweringPhase( ): SimpleNamedCompilerPhase = createSimpleNamedCompilerPhase( name, description, - postactions = fileLoweringActions, + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), prerequisite = prerequisite, outputIfNotEnabled = { _, _, _, irFile -> irFile }, op = { context, irFile -> @@ -572,7 +562,8 @@ private fun createFileLoweringPhase( ): SimpleNamedCompilerPhase = createSimpleNamedCompilerPhase( name, description, - postactions = fileLoweringActions, + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), prerequisite = prerequisite, outputIfNotEnabled = { _, _, _, irFile -> irFile }, op = { context, irFile -> @@ -589,7 +580,8 @@ private fun createFileLoweringPhase( ): SimpleNamedCompilerPhase = createSimpleNamedCompilerPhase( name, description, - postactions = fileLoweringActions, + preactions = getDefaultIrActions(), + postactions = getDefaultIrActions(), prerequisite = prerequisite, outputIfNotEnabled = { _, _, _, irFile -> irFile }, op = { context, irFile -> diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/PsiToIr.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/PsiToIr.kt index 3997c594abf..ede3dddc777 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/PsiToIr.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/PsiToIr.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.KonanReflectionTypes import org.jetbrains.kotlin.backend.konan.driver.BasicPhaseContext import org.jetbrains.kotlin.backend.konan.driver.PhaseContext import org.jetbrains.kotlin.backend.konan.driver.utilities.KotlinBackendIrHolder +import org.jetbrains.kotlin.backend.konan.driver.utilities.getDefaultIrActions import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols import org.jetbrains.kotlin.backend.konan.psiToIr import org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer @@ -102,6 +103,7 @@ internal class PsiToIrContextImpl( internal val PsiToIrPhase = createSimpleNamedCompilerPhase( "PsiToIr", "Translate PSI to IR", + postactions = getDefaultIrActions(), outputIfNotEnabled = { _, _, _, _ -> error("PsiToIr phase cannot be disabled") } ) { context, input -> context.psiToIr(input, useLinkerWhenProducingLibrary = false) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Utilities.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Utilities.kt deleted file mode 100644 index 9da2e8539d0..00000000000 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Utilities.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.backend.konan.driver.phases - -import org.jetbrains.kotlin.backend.common.IrValidator -import org.jetbrains.kotlin.backend.common.IrValidatorConfig -import org.jetbrains.kotlin.backend.common.checkDeclarationParents -import org.jetbrains.kotlin.backend.common.phaser.* -import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.NativeGenerationState -import org.jetbrains.kotlin.backend.konan.driver.PhaseContext -import org.jetbrains.kotlin.backend.konan.reportCompilationWarning -import org.jetbrains.kotlin.ir.IrElement - -internal fun irValidationCallback(state: ActionState, element: IrElement, context: Context) { - if (!context.config.needVerifyIr) return - - val validatorConfig = IrValidatorConfig( - abortOnError = false, - ensureAllNodesAreDifferent = true, - checkTypes = true, - checkDescriptors = false - ) - try { - element.accept(IrValidator(context, validatorConfig), null) - element.checkDeclarationParents() - } catch (t: Throwable) { - // TODO: Add reference to source. - if (validatorConfig.abortOnError) - throw IllegalStateException("Failed IR validation ${state.beforeOrAfter} ${state.phase}", t) - else context.reportCompilationWarning("[IR VALIDATION] ${state.beforeOrAfter} ${state.phase}: ${t.message}") - } -} - -internal val nativeStateIrValidator = - fun(actionState: ActionState, data: IrElement, context: NativeGenerationState) { - irValidationCallback(actionState, data, context.context) - } - -internal val nativeStateDumper = - fun(actionState: ActionState, data: IrElement, context: NativeGenerationState) { - defaultDumper(actionState, data, context.context) - } - -internal fun SimpleNamedCompilerPhase.copy( - preactions: Set> = emptySet(), - postactions: Set> = emptySet(), -) = object : SimpleNamedCompilerPhase( - name, - description, - preactions = preactions, - postactions = postactions.map { f -> - fun(actionState: ActionState, data: Pair, context: C) { f(actionState, data.second, context) } - }.toSet(), -) { - override fun outputIfNotEnabled(phaseConfig: PhaseConfigurationService, phaserState: PhaserState, context: C, input: Input): Output = - this@copy.outputIfNotEnabled(phaseConfig, phaserState, context, input) - - override fun phaseBody(context: C, input: Input): Output = - this@copy.phaseBody(context, input) -} \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/utilities/IrPassesUtilities.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/utilities/IrPassesUtilities.kt index 65f4a1749f7..5ce7f7ab67c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/utilities/IrPassesUtilities.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/utilities/IrPassesUtilities.kt @@ -6,6 +6,16 @@ package org.jetbrains.kotlin.backend.konan.driver.utilities import org.jetbrains.kotlin.backend.common.CommonBackendContext +import org.jetbrains.kotlin.backend.common.IrValidator +import org.jetbrains.kotlin.backend.common.IrValidatorConfig +import org.jetbrains.kotlin.backend.common.checkDeclarationParents +import org.jetbrains.kotlin.backend.common.phaser.Action +import org.jetbrains.kotlin.backend.common.phaser.ActionState +import org.jetbrains.kotlin.backend.common.phaser.BeforeOrAfter +import org.jetbrains.kotlin.backend.common.phaser.defaultDumper +import org.jetbrains.kotlin.backend.konan.driver.PhaseContext +import org.jetbrains.kotlin.backend.konan.reportCompilationWarning +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.ir.IrElement @@ -23,4 +33,84 @@ interface BackendContextHolder { */ interface KotlinBackendIrHolder { val kotlinIr: IrElement -} \ No newline at end of file +} + +private fun findBackendContext(context: Context): CommonBackendContext? = when { + context is CommonBackendContext -> context + context is BackendContextHolder<*> -> context.backendContext + else -> null +} + +private fun findKotlinBackendIr(context: Context, data: Data): IrElement? = when { + data is IrElement -> data + data is KotlinBackendIrHolder -> data.kotlinIr + context is KotlinBackendIrHolder -> context.kotlinIr + else -> null +} + +private fun ActionState.isDumpNeeded() = + when (beforeOrAfter) { + BeforeOrAfter.BEFORE -> config.shouldDumpStateBefore(phase) + BeforeOrAfter.AFTER -> config.shouldDumpStateAfter(phase) + } + +private fun getIrValidator(): Action = + fun(state: ActionState, data: Data, context: Context) { + if (!context.config.needVerifyIr) return + + val backendContext: CommonBackendContext? = findBackendContext(context) + if (backendContext == null) { + context.messageCollector.report(CompilerMessageSeverity.WARNING, + "Cannot verify IR ${state.beforeOrAfter} ${state.phase}: insufficient context.") + return + } + val element = findKotlinBackendIr(context, data) + if (element == null) { + context.messageCollector.report(CompilerMessageSeverity.WARNING, + "Cannot verify IR ${state.beforeOrAfter} ${state.phase}: IR not found.") + return + } + val validatorConfig = IrValidatorConfig( + abortOnError = false, + ensureAllNodesAreDifferent = true, + checkTypes = true, + checkDescriptors = false + ) + try { + element.accept(IrValidator(backendContext, validatorConfig), null) + element.checkDeclarationParents() + } catch (t: Throwable) { + // TODO: Add reference to source. + if (validatorConfig.abortOnError) + throw IllegalStateException("Failed IR validation ${state.beforeOrAfter} ${state.phase}", t) + else context.reportCompilationWarning("[IR VALIDATION] ${state.beforeOrAfter} ${state.phase}: ${t.message}") + } + } + +private fun getIrDumper(): Action = + fun(state: ActionState, data: Data, context: Context) { + if (!state.isDumpNeeded()) return + val backendContext: CommonBackendContext? = findBackendContext(context) + if (backendContext == null) { + context.messageCollector.report(CompilerMessageSeverity.WARNING, + "Cannot dump IR ${state.beforeOrAfter} ${state.phase}: insufficient context.") + return + } + val element = findKotlinBackendIr(context, data) + if (element == null) { + context.messageCollector.report(CompilerMessageSeverity.WARNING, + "Cannot dump IR ${state.beforeOrAfter} ${state.phase}: IR not found.") + return + } + defaultDumper(state, element, backendContext) + } + +private val validateAll = false + +/** + * IR dump and verify actions. + */ +internal fun getDefaultIrActions(): Set> = setOfNotNull( + getIrDumper(), + getIrValidator().takeIf { validateAll } +) \ No newline at end of file