diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt index df67548963f..a475d8cfed5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt @@ -20,19 +20,20 @@ val CompilerOutputKind.isNativeBinary: Boolean get() = when (this) { CompilerOutputKind.LIBRARY, CompilerOutputKind.BITCODE -> false } -internal fun produceOutput(context: Context, phaser: PhaseManager) { +internal fun produceCStubs(context: Context) { + val llvmModule = context.llvmModule!! + context.cStubsManager.compile(context.config.clang, context.messageCollector, context.inVerbosePhase)?.let { + parseAndLinkBitcodeFile(llvmModule, it.absolutePath) + } +} + +internal fun produceOutput(context: Context) { val llvmModule = context.llvmModule!! val config = context.config.configuration val tempFiles = context.config.tempFiles val produce = config.get(KonanConfigKeys.PRODUCE) - phaser.phase(KonanPhase.C_STUBS) { - context.cStubsManager.compile(context.config.clang, context.messageCollector, context.phase!!.verbose)?.let { - parseAndLinkBitcodeFile(llvmModule, it.absolutePath) - } - } - when (produce) { CompilerOutputKind.STATIC, CompilerOutputKind.DYNAMIC, @@ -55,10 +56,8 @@ internal fun produceOutput(context: Context, phaser: PhaseManager) { context.config.defaultNativeLibraries + generatedBitcodeFiles - phaser.phase(KonanPhase.BITCODE_LINKER) { - for (library in nativeLibraries) { - parseAndLinkBitcodeFile(llvmModule, library) - } + for (library in nativeLibraries) { + parseAndLinkBitcodeFile(llvmModule, library) } LLVMWriteBitcodeToFile(llvmModule, output) 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 50a4b82e4d6..d90390d90c8 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 @@ -10,6 +10,7 @@ import llvm.LLVMModuleRef import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor +import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.validateIrModule import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.ir.KonanIr @@ -18,6 +19,9 @@ import org.jetbrains.kotlin.backend.konan.library.LinkData 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.DataFlowIR +import org.jetbrains.kotlin.backend.konan.optimizations.Devirtualization +import org.jetbrains.kotlin.backend.konan.optimizations.ExternalModulesDFG +import org.jetbrains.kotlin.backend.konan.optimizations.ModuleDFG import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl @@ -35,12 +39,14 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver @@ -204,6 +210,9 @@ internal class SpecialDeclarationsFactory(val context: Context) { } internal class Context(config: KonanConfig) : KonanBackendContext(config) { + lateinit var environment: KotlinCoreEnvironment + lateinit var bindingContext: BindingContext + override val declarationFactory get() = TODO("not implemented") @@ -217,6 +226,10 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { moduleDescriptor.builtIns as KonanBuiltIns } + override val configuration get() = config.configuration + + val phaseConfig = PhaseConfig(toplevelPhase, config.configuration) + private val packageScope by lazy { builtIns.builtInsModule.getPackage(KonanFqNames.internalPackageName).memberScope } val nativePtr by lazy { packageScope.getContributedClassifier(NATIVE_PTR_NAME) as ClassDescriptor } @@ -321,9 +334,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { val cStubsManager = CStubsManager() - var phase: KonanPhase? = null - var depth: Int = 0 - lateinit var privateFunctions: List> lateinit var privateClasses: List> @@ -342,7 +352,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { if (!::moduleDescriptor.isInitialized) return - separator("Descriptors after: ${phase?.description}") + separator("Descriptors:") moduleDescriptor.deepPrint() } @@ -353,19 +363,19 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { fun printIr() { if (irModule == null) return - separator("IR after: ${phase?.description}") + separator("IR:") irModule!!.accept(DumpIrTreeVisitor(out), "") } fun printIrWithDescriptors() { if (irModule == null) return - separator("IR after: ${phase?.description}") + separator("IR:") irModule!!.accept(DumpIrTreeWithDescriptorsVisitor(out), "") } fun printLocations() { if (irModule == null) return - separator("Locations after: ${phase?.description}") + separator("Locations:") irModule!!.acceptVoid(object: IrElementVisitorVoid { override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) @@ -407,7 +417,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { fun printBitCode() { if (llvmModule == null) return - separator("BitCode after: ${phase?.description}") + separator("BitCode:") LLVMDumpModule(llvmModule!!) } @@ -446,13 +456,19 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { fun shouldOptimize() = config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION) + override var inVerbosePhase = false override fun log(message: () -> String) { - if (phase?.verbose ?: false) { + if (inVerbosePhase) { println(message()) } } lateinit var debugInfo: DebugInfo + var moduleDFG: ModuleDFG? = null + var externalModulesDFG: ExternalModulesDFG? = null + lateinit var lifetimes: MutableMap + lateinit var codegenVisitor: CodeGeneratorVisitor + var devirtualizationAnalysisResult: Devirtualization.AnalysisResult? = null val isNativeLibrary: Boolean by lazy { val kind = config.configuration.get(KonanConfigKeys.PRODUCE) @@ -461,6 +477,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { internal val stdlibModule get() = this.builtIns.any.module + + lateinit var linkStage: LinkStage } private fun MemberScope.getContributedClassifier(name: String) = diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt index 15593914030..17f19e0f95b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt @@ -5,23 +5,8 @@ package org.jetbrains.kotlin.backend.konan -import org.jetbrains.kotlin.backend.common.LoggingContext -import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension -import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule -import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary -import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols -import org.jetbrains.kotlin.backend.konan.ir.ModuleIndex -import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM -import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier -import org.jetbrains.kotlin.backend.konan.serialization.* -import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport +import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.languageVersionSettings -import org.jetbrains.kotlin.ir.util.patchDeclarationParents -import org.jetbrains.kotlin.konan.library.impl.CombinedIrFileWriter -import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration -import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironment) { @@ -32,118 +17,16 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme targets.list() } - KonanPhases.config(konanConfig) + val context = Context(konanConfig) + context.environment = environment + context.phaseConfig.konanPhasesConfig(konanConfig) // TODO: Wrong place to call it + if (config.get(KonanConfigKeys.LIST_PHASES) ?: false) { - KonanPhases.list() + context.phaseConfig.list() } if (konanConfig.infoArgsOnly) return - val context = Context(konanConfig) - - val analyzerWithCompilerReport = AnalyzerWithCompilerReport(context.messageCollector, - environment.configuration.languageVersionSettings) - - val phaser = PhaseManager(context, null) - - phaser.phase(KonanPhase.FRONTEND) { - // Build AST and binding info. - analyzerWithCompilerReport.analyzeAndReport(environment.getSourceFiles()) { - TopDownAnalyzerFacadeForKonan.analyzeFiles(environment.getSourceFiles(), konanConfig) - } - if (analyzerWithCompilerReport.hasErrors()) { - throw KonanCompilationException() - } - context.moduleDescriptor = analyzerWithCompilerReport.analysisResult.moduleDescriptor - } - - val bindingContext = analyzerWithCompilerReport.analysisResult.bindingContext - - phaser.phase(KonanPhase.PSI_TO_IR) { - // Translate AST to high level IR. - val translator = Psi2IrTranslator(context.config.configuration.languageVersionSettings, - Psi2IrConfiguration(false)) - val generatorContext = translator.createGeneratorContext(context.moduleDescriptor, bindingContext) - @Suppress("DEPRECATION") - context.psi2IrGeneratorContext = generatorContext - - val forwardDeclarationsModuleDescriptor = context.moduleDescriptor.allDependencyModules.firstOrNull { it.isForwardDeclarationModule } - - val deserializer = KonanIrModuleDeserializer( - context.moduleDescriptor, - context as LoggingContext, - generatorContext.irBuiltIns, - generatorContext.symbolTable, - forwardDeclarationsModuleDescriptor - ) - - val irModules = context.moduleDescriptor.allDependencyModules.map { - val library = it.konanLibrary - if (library == null) { - return@map null - } - library.irHeader?.let { header -> deserializer.deserializeIrModule(it, header) } - }.filterNotNull() - - val symbols = KonanSymbols(context, generatorContext.symbolTable, generatorContext.symbolTable.lazyWrapper) - val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(), deserializer) - - irModules.forEach { - it.patchDeclarationParents() - } - - context.irModule = module - context.ir.symbols = symbols - -// validateIrModule(context, module) - } - phaser.phase(KonanPhase.IR_GENERATOR_PLUGINS) { - val extensions = IrGenerationExtension.getInstances(context.config.project) - extensions.forEach { extension -> - context.irModule!!.files.forEach { irFile -> extension.generate(irFile, context, bindingContext) } - } - } - phaser.phase(KonanPhase.GEN_SYNTHETIC_FIELDS) { - markBackingFields(context) - } - - // TODO: We copy default value expressions from expects to actuals before IR serialization, - // because the current infrastructure doesn't allow us to get them at deserialization stage. - // That equires some design and implementation work. - phaser.phase(KonanPhase.COPY_DEFAULT_VALUES_TO_ACTUAL) { - context.irModule!!.files.forEach(ExpectToActualDefaultValueCopier(context)::lower) - } - - context.irModule!!.patchDeclarationParents() // why do we need it? - - phaser.phase(KonanPhase.SERIALIZER) { - val declarationTable = DeclarationTable(context.irModule!!.irBuiltins, DescriptorTable()) - val serializedIr = IrModuleSerializer( - context, declarationTable, bodiesOnlyForInlines = context.config.isInteropStubs).serializedIrModule(context.irModule!!) - val serializer = KonanSerializationUtil(context, context.config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, declarationTable) - context.serializedLinkData = - serializer.serializeModule(context.moduleDescriptor, /*if (!context.config.isInteropStubs) serializedIr else null*/ serializedIr) - } - phaser.phase(KonanPhase.BACKEND) { - phaser.phase(KonanPhase.LOWER) { - KonanLower(context, phaser).lower() -// validateIrModule(context, context.ir.irModule) // Temporarily disabled until moving to new IR finished. - context.ir.moduleIndexForCodegen = ModuleIndex(context.ir.irModule) - } - phaser.phase(KonanPhase.BITCODE) { - emitLLVM(context, phaser) - produceOutput(context, phaser) - } - // We always verify bitcode to prevent hard to debug bugs. - context.verifyBitCode() - - if (context.shouldPrintBitCode()) { - context.printBitCode() - } - } - - phaser.phase(KonanPhase.LINK_STAGE) { - LinkStage(context, phaser).linkStage() - } + toplevelPhase.invokeToplevel(context.phaseConfig, context, Unit) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt deleted file mode 100644 index feb004cc0aa..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package org.jetbrains.kotlin.backend.konan - -import org.jetbrains.kotlin.backend.common.runOnFilePostfix -import org.jetbrains.kotlin.backend.common.lower.* -import org.jetbrains.kotlin.backend.common.lower.LocalDelegatedPropertiesLowering -import org.jetbrains.kotlin.backend.konan.lower.* -import org.jetbrains.kotlin.backend.konan.lower.ExpectDeclarationsRemoving -import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering -import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering -import org.jetbrains.kotlin.backend.konan.lower.VarargInjectionLowering -import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.ir.declarations.name -import org.jetbrains.kotlin.ir.util.checkDeclarationParents -import org.jetbrains.kotlin.ir.util.patchDeclarationParents -import org.jetbrains.kotlin.ir.util.replaceUnboundSymbols - -internal class KonanLower(val context: Context, val parentPhaser: PhaseManager) { - - fun lower() { - val irModule = context.irModule!! - - // Phases to run against whole module. - lowerModule(irModule, parentPhaser) - - // Phases to run against a file. - irModule.files.forEach { - lowerFile(it, PhaseManager(context, parentPhaser)) - } - - irModule.checkDeclarationParents() - } - - private fun lowerModule(irModule: IrModuleFragment, phaser: PhaseManager) { - phaser.phase(KonanPhase.REMOVE_EXPECT_DECLARATIONS) { - irModule.files.forEach(ExpectDeclarationsRemoving(context)::lower) - } - - phaser.phase(KonanPhase.LOWER_BEFORE_INLINE) { - irModule.files.forEach(PreInlineLowering(context)::lower) - } - - // Inlining must be run before other phases. - phaser.phase(KonanPhase.LOWER_INLINE) { - FunctionInlining(context).inline(irModule) - } - - phaser.phase(KonanPhase.LOWER_AFTER_INLINE) { - irModule.files.forEach(PostInlineLowering(context)::lower) - // TODO: Seems like this should be deleted in PsiToIR. - irModule.files.forEach(ContractsDslRemover(context)::lower) - } - - phaser.phase(KonanPhase.LOWER_INTEROP_PART1) { - irModule.files.forEach(InteropLoweringPart1(context)::lower) - } - - irModule.patchDeclarationParents() - -// validateIrModule(context, irModule) // Temporarily disabled until moving to new IR finished. - } - - private fun lowerFile(irFile: IrFile, phaser: PhaseManager) { - phaser.phase(KonanPhase.LOWER_LATEINIT) { - LateinitLowering(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_STRING_CONCAT) { - StringConcatenationLowering(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_ENUM_CONSTRUCTORS) { - EnumConstructorsLowering(context).run(irFile) - } - phaser.phase(KonanPhase.LOWER_INITIALIZERS) { - InitializersLowering(context).runOnFilePostfix(irFile) - } - phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) { - SharedVariablesLowering(context).runOnFilePostfix(irFile) - } - phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) { - LocalDelegatedPropertiesLowering().lower(irFile) - LocalDeclarationsLowering(context).runOnFilePostfix(irFile) - } - phaser.phase(KonanPhase.LOWER_TAILREC) { - TailrecLowering(context).runOnFilePostfix(irFile) - } - phaser.phase(KonanPhase.LOWER_DEFAULT_PARAMETER_EXTENT) { - DefaultArgumentStubGenerator(context, skipInlineMethods = false).runOnFilePostfix(irFile) - KonanDefaultParameterInjector(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_INNER_CLASSES) { - InnerClassLowering(context).runOnFilePostfix(irFile) - } - phaser.phase(KonanPhase.LOWER_FOR_LOOPS) { - ForLoopsLowering(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_DATA_CLASSES) { - DataClassOperatorsLowering(context).runOnFilePostfix(irFile) - } - phaser.phase(KonanPhase.LOWER_BUILTIN_OPERATORS) { - BuiltinOperatorLowering(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_FINALLY) { - FinallyBlocksLowering(context).lower(irFile) - } - phaser.phase(KonanPhase.TEST_PROCESSOR) { - TestProcessor(context).process(irFile) - } - phaser.phase(KonanPhase.LOWER_ENUMS) { - EnumClassLowering(context).run(irFile) - } - phaser.phase(KonanPhase.LOWER_DELEGATION) { - PropertyDelegationLowering(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_CALLABLES) { - CallableReferenceLowering(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_INTEROP_PART2) { - InteropLoweringPart2(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_VARARG) { - VarargInjectionLowering(context).runOnFilePostfix(irFile) - } - phaser.phase(KonanPhase.LOWER_COMPILE_TIME_EVAL) { - CompileTimeEvaluateLowering(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_COROUTINES) { - SuspendFunctionsLowering(context).lower(irFile) - } - phaser.phase(KonanPhase.LOWER_TYPE_OPERATORS) { - TypeOperatorLowering(context).runOnFilePostfix(irFile) - } - phaser.phase(KonanPhase.BRIDGES_BUILDING) { - BridgesBuilding(context).runOnFilePostfix(irFile) - WorkersBridgesBuilding(context).lower(irFile) - } - phaser.phase(KonanPhase.AUTOBOX) { - // validateIrFile(context, irFile) // Temporarily disabled until moving to new IR finished. - Autoboxing(context).lower(irFile) - } - phaser.phase(KonanPhase.RETURNS_INSERTION) { - ReturnsInsertionLowering(context).lower(irFile) - } - } - -} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt new file mode 100644 index 00000000000..830d79d9991 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt @@ -0,0 +1,309 @@ +package org.jetbrains.kotlin.backend.konan + +import org.jetbrains.kotlin.backend.common.* +import org.jetbrains.kotlin.backend.common.lower.* +import org.jetbrains.kotlin.backend.common.phaser.* +import org.jetbrains.kotlin.backend.konan.ir.ModuleIndex +import org.jetbrains.kotlin.backend.konan.lower.* +import org.jetbrains.kotlin.backend.konan.lower.ExpectDeclarationsRemoving +import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering +import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering +import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.util.checkDeclarationParents +import org.jetbrains.kotlin.ir.util.patchDeclarationParents + +private fun makeKonanFileLoweringPhase( + lowering: (Context) -> FileLoweringPass, + name: String, + description: String, + prerequisite: Set = emptySet() +) = makeIrFilePhase(lowering, name, description, prerequisite) + +private fun makeKonanModuleLoweringPhase( + lowering: (Context) -> FileLoweringPass, + name: String, + description: String, + prerequisite: Set = emptySet() +) = makeIrModulePhase(lowering, name, description, prerequisite) + +internal fun makeKonanFileOpPhase( + op: (Context, IrFile) -> Unit, + name: String, + description: String, + prerequisite: Set = emptySet() +) = namedIrFilePhase( + name, description, prerequisite, nlevels = 0, + lower = object : SameTypeCompilerPhase { + override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrFile): IrFile { + op(context, input) + return input + } + } +) + +internal fun makeKonanModuleOpPhase( + op: (Context, IrModuleFragment) -> Unit, + name: String, + description: String, + prerequisite: Set = emptySet() +) = namedIrModulePhase( + name, description, prerequisite, nlevels = 0, + lower = object : SameTypeCompilerPhase { + override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment): IrModuleFragment { + op(context, input) + return input + } + } +) + +internal val removeExpectDeclarationsPhase = makeKonanModuleLoweringPhase( + ::ExpectDeclarationsRemoving, + name = "RemoveExpectDeclarations", + description = "Expect declarations removing" +) + +internal val lowerBeforeInlinePhase = makeKonanModuleLoweringPhase( + ::PreInlineLowering, + name = "LowerBeforeInline", + description = "Special operations processing before inlining" +) + +internal val inlinePhase = namedIrModulePhase( + lower = object : SameTypeCompilerPhase { + override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState, context: Context, input: IrModuleFragment): IrModuleFragment { + FunctionInlining(context).inline(input) + return input + } + }, + name = "Inline", + description = "Functions inlining", + prerequisite = setOf(lowerBeforeInlinePhase), + nlevels = 0 +) + +internal val lowerAfterInlinePhase = makeKonanModuleOpPhase( + { context, irModule -> + irModule.files.forEach(PostInlineLowering(context)::lower) + // TODO: Seems like this should be deleted in PsiToIR. + irModule.files.forEach(ContractsDslRemover(context)::lower) + }, + name = "LowerAfterInline", + description = "Special operations processing after inlining" +) + +internal val interopPart1Phase = makeKonanModuleLoweringPhase( + ::InteropLoweringPart1, + name = "InteropPart1", + description = "Interop lowering, part 1", + prerequisite = setOf(inlinePhase) +) + +internal val patchDeclarationParents1Phase = makeKonanModuleOpPhase( + { _, irModule -> irModule.patchDeclarationParents() }, + name = "PatchDeclarationParents1", + description = "Patch declaration parents 1" +) + +internal val checkDeclarationParentsPhase = makeKonanModuleOpPhase( + { _, irModule -> irModule.checkDeclarationParents() }, + name = "CheckDeclarationParents", + description = "Check declaration parents" +) + +internal val validateIrModulePhase = makeKonanModuleOpPhase( + { context, irModule -> validateIrModule(context, irModule) }, + name = "ValidateIrModule", + description = "Validate generated module" +) + +internal val moduleIndexForCodegenPhase = makeKonanModuleOpPhase( + { context, irModule -> context.ir.moduleIndexForCodegen = ModuleIndex(irModule) }, + name = "ModuleIndexForCodeGen", + description = "Generate module index for codegen" +) + +/* IrFile phases */ + +internal val lateinitPhase = makeKonanFileLoweringPhase( + ::LateinitLowering, + name = "Lateinit", + description = "Lateinit properties lowering", + prerequisite = setOf(inlinePhase) +) + +internal val stringConcatenationPhase = makeKonanFileLoweringPhase( + ::StringConcatenationLowering, + name = "StringConcatenation", + description = "String concatenation lowering" +) + +internal val enumConstructorsPhase = makeKonanFileLoweringPhase( + ::EnumConstructorsLowering, + name = "EnumConstructors", + description = "Enum constructors lowering" +) + +internal val initializersPhase = makeKonanFileLoweringPhase( + ::InitializersLowering, + name = "Initializers", + description = "Initializers lowering", + prerequisite = setOf(enumConstructorsPhase) +) + +internal val sharedVariablesPhase = makeKonanFileLoweringPhase( + ::SharedVariablesLowering, + name = "SharedVariables", + description = "Shared Variable Lowering", + prerequisite = setOf(initializersPhase) +) + +internal val localFunctionsPhase = makeKonanFileOpPhase( + op = { context, irFile -> + LocalDelegatedPropertiesLowering().lower(irFile) + LocalDeclarationsLowering(context).runOnFilePostfix(irFile) + }, + name = "LocalFunctions", + description = "Local Function Lowering", + prerequisite = setOf(sharedVariablesPhase) +) + +internal val tailrecPhase = makeKonanFileLoweringPhase( + ::TailrecLowering, + name = "Tailrec", + description = "tailrec lowering", + prerequisite = setOf(localFunctionsPhase) +) + +internal val defaultParameterExtentPhase = makeKonanFileOpPhase( + { context, irFile -> + DefaultArgumentStubGenerator(context, skipInlineMethods = false).runOnFilePostfix(irFile) + KonanDefaultParameterInjector(context).lower(irFile) + }, + name = "DefaultParameterExtent", + description = "Default Parameter Extent Lowering", + prerequisite = setOf(tailrecPhase, enumConstructorsPhase) +) + +internal val innerClassPhase = makeKonanFileLoweringPhase( + ::InnerClassLowering, + name = "InnerClasses", + description = "Inner classes lowering", + prerequisite = setOf(defaultParameterExtentPhase, genSyntheticFieldsPhase ) +) + +internal val forLoopsPhase = makeKonanFileLoweringPhase( + ::ForLoopsLowering, + name = "ForLoops", + description = "For loops lowering" +) + +internal val dataClassesPhase = makeKonanFileLoweringPhase( + ::DataClassOperatorsLowering, + name = "DataClasses", + description = "Data classes lowering" +) + +internal val builtinOperatorPhase = makeKonanFileLoweringPhase( + ::BuiltinOperatorLowering, + name = "BuiltinOperators", + description = "BuiltIn Operators Lowering", + prerequisite = setOf(defaultParameterExtentPhase) +) + +internal val finallyBlocksPhase = makeKonanFileLoweringPhase( + ::FinallyBlocksLowering, + name = "FinallyBlocks", + description = "Finally blocks lowering", + prerequisite = setOf(initializersPhase, localFunctionsPhase, tailrecPhase) +) + +internal val testProcessorPhase = makeKonanFileOpPhase( + { context, irFile -> TestProcessor(context).process(irFile) }, + name = "TestProcessor", + description = "Unit test processor" +) + +internal val enumClassPhase = makeKonanFileOpPhase( + { context, irFile -> EnumClassLowering(context).run(irFile) }, + name = "Enums", + description = "Enum classes lowering", + prerequisite = setOf(enumConstructorsPhase) // TODO: make weak dependency on `testProcessorPhase` +) + +internal val delegationPhase = makeKonanFileLoweringPhase( + ::PropertyDelegationLowering, + name = "Delegation", + description = "Delegation lowering" +) + +internal val callableReferencePhase = makeKonanFileLoweringPhase( + ::CallableReferenceLowering, + name = "CallableReference", + description = "Callable references Lowering", + prerequisite = setOf(delegationPhase) // TODO: make weak dependency on `testProcessorPhase` +) + +internal val interopPart2Phase = makeKonanFileLoweringPhase( + ::InteropLoweringPart2, + name = "InteropPart2", + description = "Interop lowering, part 2", + prerequisite = setOf(localFunctionsPhase) +) + +internal val varargPhase = makeKonanFileLoweringPhase( + ::VarargInjectionLowering, + name = "Vararg", + description = "Vararg lowering", + prerequisite = setOf(callableReferencePhase, defaultParameterExtentPhase) +) + +internal val compileTimeEvaluatePhase = makeKonanFileLoweringPhase( + ::CompileTimeEvaluateLowering, + name = "CompileTimeEvaluate", + description = "Compile time evaluation lowering", + prerequisite = setOf(varargPhase) +) + +internal val coroutinesPhase = makeKonanFileLoweringPhase( + ::SuspendFunctionsLowering, + name = "Coroutines", + description = "Coroutines lowering", + prerequisite = setOf(localFunctionsPhase, finallyBlocksPhase) +) + +internal val typeOperatorPhase = makeKonanFileLoweringPhase( + ::TypeOperatorLowering, + name = "TypeOperators", + description = "Type operators lowering", + prerequisite = setOf(coroutinesPhase) +) + +internal val bridgesPhase = makeKonanFileOpPhase( + { context, irFile -> + BridgesBuilding(context).runOnFilePostfix(irFile) + WorkersBridgesBuilding(context).lower(irFile) + }, + name = "Bridges", + description = "Bridges building", + prerequisite = setOf(coroutinesPhase) +) + +internal val autoboxPhase = makeKonanFileOpPhase( + { context, irFile -> + // validateIrFile(context, irFile) // Temporarily disabled until moving to new IR finished. + Autoboxing(context).lower(irFile) + }, + name = "Autobox", + description = "Autoboxing of primitive types", + prerequisite = setOf(bridgesPhase, coroutinesPhase) +) + +internal val returnsInsertionPhase = makeKonanFileLoweringPhase( + ::ReturnsInsertionLowering, + name = "ReturnsInsertion", + description = "Returns insertion for Unit functions", + prerequisite = setOf(autoboxPhase, coroutinesPhase, enumClassPhase) +) + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt deleted file mode 100644 index dd2ac827d0b..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package org.jetbrains.kotlin.backend.konan - -import org.jetbrains.kotlin.config.CompilerConfigurationKey -import org.jetbrains.kotlin.konan.util.* -import org.jetbrains.kotlin.konan.target.CompilerOutputKind - -enum class KonanPhase(val description: String, - vararg prerequisite: KonanPhase, - var enabled: Boolean = true, - var verbose: Boolean = false) { - /* */ FRONTEND("Frontend builds AST"), - /* */ PSI_TO_IR("Psi to IR conversion"), - /* */ IR_GENERATOR_PLUGINS("Plugged-in ir generators"), - /* */ GEN_SYNTHETIC_FIELDS("Generate synthetic fields"), - /* */ COPY_DEFAULT_VALUES_TO_ACTUAL("Copy default values from expect to actual declarations"), - /* */ SERIALIZER("Serialize descriptor tree and inline IR bodies", GEN_SYNTHETIC_FIELDS), - /* */ BACKEND("All backend"), - /* ... */ LOWER("IR Lowering"), - /* ... ... */ REMOVE_EXPECT_DECLARATIONS("Expect declarations removing"), - /* ... ... */ TEST_PROCESSOR("Unit test processor"), - /* ... ... */ LOWER_BEFORE_INLINE("Special operations processing before inlining"), - /* ... ... */ LOWER_INLINE("Functions inlining", LOWER_BEFORE_INLINE), - /* ... ... */ LOWER_AFTER_INLINE("Special operations processing after inlining"), - /* ... ... ... */ DESERIALIZER("Deserialize inline bodies"), - /* ... ... */ LOWER_INTEROP_PART1("Interop lowering, part 1", LOWER_INLINE), - /* ... ... */ LOWER_FOR_LOOPS("For loops lowering"), - /* ... ... */ LOWER_ENUM_CONSTRUCTORS("Enum constructors lowering"), - /* ... ... */ LOWER_ENUMS("Enum classes lowering", LOWER_ENUM_CONSTRUCTORS/*TODO: make weak dependence on TEST_PROCESSOR*/), - /* ... ... */ LOWER_DELEGATION("Delegation lowering"), - /* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUM_CONSTRUCTORS), - /* ... ... */ LOWER_LATEINIT("Lateinit properties lowering", LOWER_INLINE), - /* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS), - /* ... ... */ LOWER_CALLABLES("Callable references Lowering", LOWER_DELEGATION/*TODO: make weak dependence on TEST_PROCESSOR*/), - /* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", LOWER_SHARED_VARIABLES), - /* ... ... */ LOWER_INTEROP_PART2("Interop lowering, part 2", LOWER_LOCAL_FUNCTIONS), - /* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS), - /* ... ... */ LOWER_FINALLY("Finally blocks lowering", LOWER_INITIALIZERS, LOWER_LOCAL_FUNCTIONS, LOWER_TAILREC), - /* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", LOWER_TAILREC, LOWER_ENUM_CONSTRUCTORS), - /* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES, LOWER_DEFAULT_PARAMETER_EXTENT), - /* ... ... */ LOWER_COMPILE_TIME_EVAL("Compile time evaluation lowering", LOWER_VARARG, enabled = false), - /* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", LOWER_DEFAULT_PARAMETER_EXTENT, GEN_SYNTHETIC_FIELDS), - /* ... ... */ LOWER_BUILTIN_OPERATORS("BuiltIn Operators Lowering", LOWER_DEFAULT_PARAMETER_EXTENT), - /* ... ... */ LOWER_COROUTINES("Coroutines lowering", LOWER_LOCAL_FUNCTIONS, LOWER_FINALLY), - /* ... ... */ LOWER_TYPE_OPERATORS("Type operators lowering", LOWER_COROUTINES), - /* ... ... */ BRIDGES_BUILDING("Bridges building", LOWER_COROUTINES), - /* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"), - /* ... ... */ LOWER_DATA_CLASSES("Data classes lowering"), - /* ... ... */ AUTOBOX("Autoboxing of primitive types", BRIDGES_BUILDING, LOWER_COROUTINES), - /* ... ... */ RETURNS_INSERTION("Returns insertion for Unit functions", AUTOBOX, LOWER_COROUTINES, LOWER_ENUMS), - /* ... */ BITCODE("LLVM BitCode Generation"), - /* ... ... */ RTTI("RTTI Generation"), - /* ... ... */ BUILD_DFG("Data flow graph building", enabled = false), - /* ... ... */ DESERIALIZE_DFG("Data flow graph deserializing", enabled = false), - /* ... ... */ DEVIRTUALIZATION("Devirtualization", BUILD_DFG, DESERIALIZE_DFG, enabled = false), - /* ... ... */ ESCAPE_ANALYSIS("Escape analysis", BUILD_DFG, DESERIALIZE_DFG, enabled = false), // TODO: Requires devirtualization. - /* ... ... */ SERIALIZE_DFG("Data flow graph serializing", BUILD_DFG, enabled = false), // TODO: Requires escape analysis. - /* ... ... */ CODEGEN("Code Generation"), - /* ... ... */ C_STUBS("C stubs compilation"), - /* ... ... */ BITCODE_LINKER("Bitcode linking"), - /* */ LINK_STAGE("Link stage"), - /* ... */ OBJECT_FILES("Bitcode to object file"), - /* ... */ LINKER("Linker"); - - val prerequisite = prerequisite.toSet() -} - -object KonanPhases { - val phases = KonanPhase.values().associate { it.visibleName to it } - - fun known(name: String): String { - if (phases[name] == null) { - error("Unknown phase: $name. Use --list_phases to see the list of phases.") - } - return name - } - - fun config(config: KonanConfig) { - with (config.configuration) { with (KonanConfigKeys) { - - // Don't serialize anything to a final executable. - KonanPhase.SERIALIZER.enabled = - (config.produce == CompilerOutputKind.LIBRARY) - KonanPhase.LINK_STAGE.enabled = config.produce.isNativeBinary - - KonanPhase.TEST_PROCESSOR.enabled = - getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) != TestRunnerKind.NONE - - val disabled = get(DISABLED_PHASES) - disabled?.forEach { phases[known(it)]!!.enabled = false } - - val enabled = get(ENABLED_PHASES) - enabled?.forEach { phases[known(it)]!!.enabled = true } - - val verbose = get(VERBOSE_PHASES) - verbose?.forEach { phases[known(it)]!!.verbose = true } - }} - } - - fun list() { - phases.forEach { key, phase -> - val enabled = if (phase.enabled) "(Enabled)" else "" - val verbose = if (phase.verbose) "(Verbose)" else "" - - println(String.format("%1$-30s%2$-30s%3$-10s", "${key}:", phase.description, "$enabled $verbose")) - } - } -} - -internal class PhaseManager(val context: Context, val parent: PhaseManager? = null) { - - val previousPhases = mutableSetOf() - - fun createChild() = PhaseManager(context, this) - - private fun checkPrerequisite(phase: KonanPhase): Boolean = - previousPhases.contains(phase) || parent?.checkPrerequisite(phase) == true - - fun phase(phase: KonanPhase, body: () -> Unit) { - - if (!phase.enabled) return - - phase.prerequisite.forEach { - if (!checkPrerequisite(it)) - throw Error("$phase requires $it") - } - - previousPhases.add(phase) - - val savePhase = context.phase - context.phase = phase - context.depth ++ - - with (context) { - profileIf(shouldProfilePhases(), "Phase ${nTabs(depth)} ${phase.name}") { - body() - } - - if (shouldVerifyDescriptors()) { - verifyDescriptors() - } - if (shouldVerifyIr()) { - verifyIr() - } - - if (shouldPrintDescriptors()) { - printDescriptors() - } - if (shouldPrintIr()) { - printIr() - } - if (shouldPrintIrWithDescriptors()) { - printIrWithDescriptors() - } - if (shouldPrintLocations()) { - printLocations() - } - } - - context.depth -- - context.phase = savePhase - } -} - - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt index b0c11463c5e..ef913c489b1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt @@ -15,7 +15,7 @@ typealias BitcodeFile = String typealias ObjectFile = String typealias ExecutableFile = String -internal class LinkStage(val context: Context, val phaser: PhaseManager) { +internal class LinkStage(val context: Context) { private val config = context.config.configuration private val target = context.config.target @@ -122,7 +122,7 @@ internal class LinkStage(val context: Context, val phaser: PhaseManager) { if (context.shouldProfilePhases()) { flags += "-time-passes" } - if (context.phase?.verbose == true) { + if (context.inVerbosePhase) { flags += "-debug-pass=Structure" } return flags @@ -197,33 +197,29 @@ internal class LinkStage(val context: Context, val phaser: PhaseManager) { return executable } - fun linkStage() { + val objectFiles = mutableListOf() + + fun makeObjectFiles() { val bitcodeFiles = listOf(emitted) + libraries.map { it.bitcodePaths }.flatten().filter { it.isBitcode } + objectFiles.add(when (platform.configurables) { + is WasmConfigurables + -> bitcodeToWasm(bitcodeFiles) + is ZephyrConfigurables + -> llvmLinkAndLlc(bitcodeFiles) + else + -> llvmLto(bitcodeFiles) + }) + } + + fun linkStage() { val includedBinaries = libraries.map { it.includedPaths }.flatten() val libraryProvidedLinkerFlags = libraries.map { it.linkerOpts }.flatten() - val objectFiles: MutableList = mutableListOf() - - phaser.phase(KonanPhase.OBJECT_FILES) { - objectFiles.add( - when (platform.configurables) { - is WasmConfigurables - -> bitcodeToWasm(bitcodeFiles) - is ZephyrConfigurables - -> llvmLinkAndLlc(bitcodeFiles) - else - -> llvmLto(bitcodeFiles) - } - ) - } - phaser.phase(KonanPhase.LINKER) { - link(objectFiles, includedBinaries, libraryProvidedLinkerFlags) - } + link(objectFiles, includedBinaries, libraryProvidedLinkerFlags) } } - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt index 7c3a9a9e642..3575fe55797 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt @@ -18,7 +18,6 @@ import org.jetbrains.kotlin.descriptors.konan.isKonanStdlib import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.konan.library.resolver.KonanLibraryResolveResult -import org.jetbrains.kotlin.konan.util.visibleName import org.jetbrains.kotlin.konan.utils.KonanFactories import org.jetbrains.kotlin.konan.utils.KonanFactories.DefaultDescriptorFactory import org.jetbrains.kotlin.name.Name @@ -28,16 +27,17 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProvid import org.jetbrains.kotlin.serialization.konan.KonanResolvedModuleDescriptors import org.jetbrains.kotlin.storage.StorageManager -object TopDownAnalyzerFacadeForKonan { +internal object TopDownAnalyzerFacadeForKonan { - fun analyzeFiles(files: Collection, config: KonanConfig): AnalysisResult { + fun analyzeFiles(files: Collection, context: Context): AnalysisResult { + val config = context.config val moduleName = Name.special("<${config.moduleId}>") val projectContext = ProjectContext(config.project) val module = DefaultDescriptorFactory.createDescriptorAndNewBuiltIns( moduleName, projectContext.storageManager, origin = CurrentKonanModuleOrigin) - val context = MutableModuleContextImpl(module, projectContext) + val moduleContext = MutableModuleContextImpl(module, projectContext) val resolvedDependencies = ResolvedDependencies( config.resolvedLibraries, @@ -51,28 +51,28 @@ object TopDownAnalyzerFacadeForKonan { module.setDependencies(dependencies, resolvedDependencies.friends) } else { assert (resolvedDependencies.moduleDescriptors.resolvedDescriptors.isEmpty()) - context.setDependencies(module) + moduleContext.setDependencies(module) } - return analyzeFilesWithGivenTrace(files, BindingTraceContext(), context, config) + return analyzeFilesWithGivenTrace(files, BindingTraceContext(), moduleContext, context) } fun analyzeFilesWithGivenTrace( files: Collection, trace: BindingTrace, moduleContext: ModuleContext, - config: KonanConfig + context: Context ): AnalysisResult { // we print out each file we compile if frontend phase is verbose - files.takeIf { with (KonanPhases) { - phases[known(KonanPhase.FRONTEND.visibleName)]!!.verbose - }} ?.forEach(::println) + files.takeIf { + frontendPhase in context.phaseConfig.verbose + } ?.forEach(::println) val analyzerForKonan = createTopDownAnalyzerForKonan( moduleContext, trace, FileBasedDeclarationProviderFactory(moduleContext.storageManager, files), - config.configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!! + context.config.configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!! ) analyzerForKonan.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files) 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 new file mode 100644 index 00000000000..30976bb3efb --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -0,0 +1,262 @@ +package org.jetbrains.kotlin.backend.konan + +import org.jetbrains.kotlin.backend.common.LoggingContext +import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension +import org.jetbrains.kotlin.backend.common.phaser.* +import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule +import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary +import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols +import org.jetbrains.kotlin.backend.konan.llvm.* +import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier +import org.jetbrains.kotlin.backend.konan.serialization.* +import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.languageVersionSettings +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.util.patchDeclarationParents +import org.jetbrains.kotlin.konan.target.CompilerOutputKind +import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration +import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator +import java.util.Collections.emptySet + +internal fun konanUnitPhase( + name: String, + description: String, + prerequisite: Set = emptySet(), + op: Context.() -> Unit +) = namedOpUnitPhase(name, description, prerequisite, op) + +internal val frontendPhase = konanUnitPhase( + op = { + val environment = environment + val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector, + environment.configuration.languageVersionSettings) + + // Build AST and binding info. + analyzerWithCompilerReport.analyzeAndReport(environment.getSourceFiles()) { + TopDownAnalyzerFacadeForKonan.analyzeFiles(environment.getSourceFiles(), this) + } + if (analyzerWithCompilerReport.hasErrors()) { + throw KonanCompilationException() + } + moduleDescriptor = analyzerWithCompilerReport.analysisResult.moduleDescriptor + bindingContext = analyzerWithCompilerReport.analysisResult.bindingContext + }, + name = "Frontend", + description = "Frontend builds AST" +) + +internal val psiToIrPhase = konanUnitPhase( + op = { + // Translate AST to high level IR. + val translator = Psi2IrTranslator(config.configuration.languageVersionSettings, + Psi2IrConfiguration(false)) + val generatorContext = translator.createGeneratorContext(moduleDescriptor, bindingContext) + @Suppress("DEPRECATION") + psi2IrGeneratorContext = generatorContext + + val forwardDeclarationsModuleDescriptor = moduleDescriptor.allDependencyModules.firstOrNull { it.isForwardDeclarationModule } + + val deserializer = KonanIrModuleDeserializer( + moduleDescriptor, + this as LoggingContext, + generatorContext.irBuiltIns, + generatorContext.symbolTable, + forwardDeclarationsModuleDescriptor + ) + + val irModules = moduleDescriptor.allDependencyModules.map { + val library = it.konanLibrary + if (library == null) { + return@map null + } + library.irHeader?.let { header -> deserializer.deserializeIrModule(it, header) } + }.filterNotNull() + + val symbols = KonanSymbols(this, generatorContext.symbolTable, generatorContext.symbolTable.lazyWrapper) + val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(), deserializer) + + irModules.forEach { + it.patchDeclarationParents() + } + + irModule = module + ir.symbols = symbols + +// validateIrModule(this, module) + }, + name = "Psi2Ir", + description = "Psi to IR conversion" +) + +internal val irGeneratorPluginsPhase = konanUnitPhase( + op = { + val extensions = IrGenerationExtension.getInstances(config.project) + extensions.forEach { extension -> + irModule!!.files.forEach { + irFile -> extension.generate(irFile, this, bindingContext) + } + } + }, + name = "IrGeneratorPlugins", + description = "Plugged-in ir generators" +) + +internal val genSyntheticFieldsPhase = konanUnitPhase( + op = { markBackingFields(this) }, + name = "GenSyntheticFields", + description = "Generate synthetic fields" +) + +// TODO: We copy default value expressions from expects to actuals before IR serialization, +// because the current infrastructure doesn't allow us to get them at deserialization stage. +// That requires some design and implementation work. +internal val copyDefaultValuesToActualPhase = konanUnitPhase( + op = { + irModule!!.files.forEach(ExpectToActualDefaultValueCopier(this)::lower) + }, + name = "CopyDefaultValuesToActual", + description = "Copy default values from expect to actual declarations" +) + +internal val patchDeclarationParents0Phase = konanUnitPhase( + op = { irModule!!.patchDeclarationParents() }, // why do we need it? + name = "PatchDeclarationParents0", + description = "Patch declaration parents" +) + +internal val serializerPhase = konanUnitPhase( + op = { + val declarationTable = DeclarationTable(irModule!!.irBuiltins, DescriptorTable()) + val serializedIr = IrModuleSerializer( + this, declarationTable, bodiesOnlyForInlines = config.isInteropStubs).serializedIrModule(irModule!!) + val serializer = KonanSerializationUtil(this, config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, declarationTable) + serializedLinkData = + serializer.serializeModule(moduleDescriptor, /*if (!config.isInteropStubs) serializedIr else null*/ serializedIr) + }, + name = "Serializer", + description = "Serialize descriptor tree and inline IR bodies", + prerequisite = setOf(genSyntheticFieldsPhase) +) + +internal val setUpLinkStagePhase = konanUnitPhase( + op = { linkStage = LinkStage(this) }, + name = "SetUpLinkStage", + description = "Set up link stage" +) + +internal val objectFilesPhase = konanUnitPhase( + op = { linkStage.makeObjectFiles() }, + name = "ObjectFiles", + description = "Bitcode to object file" +) + +internal val linkerPhase = konanUnitPhase( + op = { linkStage.linkStage() }, + name = "Linker", + description = "Linker" +) + +internal val linkPhase = namedUnitPhase( + name = "Link", + description = "Link stage", + lower = setUpLinkStagePhase then + objectFilesPhase then + linkerPhase +) + +internal val toplevelPhase = namedUnitPhase( + name = "Compiler", + description = "The whole compilation process", + lower = frontendPhase then + psiToIrPhase then + irGeneratorPluginsPhase then + genSyntheticFieldsPhase then + copyDefaultValuesToActualPhase then + patchDeclarationParents0Phase then + serializerPhase then + namedUnitPhase( + name = "Backend", + description = "All backend", + lower = takeFromContext { it.irModule!! } then + namedIrModulePhase( + name = "IrLowering", + description = "IR Lowering", + lower = removeExpectDeclarationsPhase then + lowerBeforeInlinePhase then + inlinePhase then + lowerAfterInlinePhase then + interopPart1Phase then + patchDeclarationParents1Phase then + performByIrFile( + name = "IrLowerByFile", + description = "IR Lowering by file", + lower = lateinitPhase then + stringConcatenationPhase then + enumConstructorsPhase then + initializersPhase then + sharedVariablesPhase then + localFunctionsPhase then + tailrecPhase then + defaultParameterExtentPhase then + innerClassPhase then + forLoopsPhase then + dataClassesPhase then + builtinOperatorPhase then + finallyBlocksPhase then + testProcessorPhase then + enumClassPhase then + delegationPhase then + callableReferencePhase then + interopPart2Phase then + varargPhase then + compileTimeEvaluatePhase then + coroutinesPhase then + typeOperatorPhase then + bridgesPhase then + autoboxPhase then + returnsInsertionPhase + ) then + checkDeclarationParentsPhase then +// validateIrModulePhase then // Temporarily disabled until moving to new IR finished. + moduleIndexForCodegenPhase + ) then + namedIrModulePhase( + name = "Bitcode", + description = "LLVM BitCode Generation", + lower = contextLLVMSetupPhase then + RTTIPhase then + generateDebugInfoHeaderPhase then + buildDFGPhase then + deserializeDFGPhase then + devirtualizationPhase then + escapeAnalysisPhase then + serializeDFGPhase then + codegenPhase then + finalizeDebugInfoPhase then + cStubsPhase then + bitcodeLinkerPhase + ) then + verifyBitcodePhase then + printBitcodePhase + then + unitSink() + ) then + linkPhase +) + +internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) { + with(config.configuration) { + disable(compileTimeEvaluatePhase) + disable(buildDFGPhase) + disable(deserializeDFGPhase) + disable(devirtualizationPhase) + disable(escapeAnalysisPhase) + disable(serializeDFGPhase) + + // Don't serialize anything to a final executable. + switch(serializerPhase, config.produce == CompilerOutputKind.LIBRARY) + switch(linkPhase, config.produce.isNativeBinary) + switch(testProcessorPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) != TestRunnerKind.NONE) + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..428858dbeb7 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt @@ -0,0 +1,175 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package org.jetbrains.kotlin.backend.konan.llvm + +import llvm.* +import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.optimizations.* +import org.jetbrains.kotlin.ir.visitors.acceptVoid + +internal val contextLLVMSetupPhase = makeKonanModuleOpPhase( + name = "ContextLLVMSetup", + description = "Set up Context for LLVM bitcode generation", + op = { context, _ -> + // Note that we don't set module target explicitly. + // It is determined by the target of runtime.bc + // (see Llvm class in ContextUtils) + // Which in turn is determined by the clang flags + // used to compile runtime.bc. + val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose + context.llvmModule = llvmModule + context.debugInfo.builder = DICreateBuilder(llvmModule) + context.llvmDeclarations = createLlvmDeclarations(context) + context.lifetimes = mutableMapOf() + context.codegenVisitor = CodeGeneratorVisitor(context, context.lifetimes) + } +) + +internal val RTTIPhase = makeKonanModuleOpPhase( + name = "RTTI", + description = "RTTI Generation", + op = { context, irModule -> irModule.acceptVoid(RTTIGeneratorVisitor(context)) } +) + +internal val generateDebugInfoHeaderPhase = makeKonanModuleOpPhase( + name = "GenerateDebugInfoHeader", + description = "Generate debug info header", + op = { context, _ -> generateDebugInfoHeader(context) } +) + +internal val buildDFGPhase = makeKonanModuleOpPhase( + name = "BuildDFG", + description = "Data flow graph building", + op = { context, irModule -> + context.moduleDFG = ModuleDFGBuilder(context, irModule).build() + } +) + +internal val deserializeDFGPhase = makeKonanModuleOpPhase( + name = "DeserializeDFG", + description = "Data flow graph deserializing", + op = { context, _ -> + context.externalModulesDFG = DFGSerializer.deserialize( + context, + context.moduleDFG!!.symbolTable.privateTypeIndex, + context.moduleDFG!!.symbolTable.privateFunIndex + ) + } +) + +internal val devirtualizationPhase = makeKonanModuleOpPhase( + name = "Devirtualization", + description = "Devirtualization", + prerequisite = setOf(buildDFGPhase, deserializeDFGPhase), + op = { context, irModule -> + context.externalModulesDFG?.let { externalModulesDFG -> + context.devirtualizationAnalysisResult = Devirtualization.run( + irModule, context, context.moduleDFG!!, externalModulesDFG + ) + + val privateFunctions = context.moduleDFG!!.symbolTable.getPrivateFunctionsTableForExport() + privateFunctions.forEachIndexed { index, it -> + val function = context.codegenVisitor.codegen.llvmFunction(it.first) + LLVMAddAlias( + context.llvmModule, + function.type, + function, + irModule.descriptor.privateFunctionSymbolName(index, it.second.name) + )!! + } + context.privateFunctions = privateFunctions + + val privateClasses = context.moduleDFG!!.symbolTable.getPrivateClassesTableForExport() + + privateClasses.forEachIndexed { index, it -> + val typeInfoPtr = context.codegenVisitor.codegen.typeInfoValue(it.first) + LLVMAddAlias( + context.llvmModule, + typeInfoPtr.type, + typeInfoPtr, + irModule.descriptor.privateClassSymbolName(index, it.second.name) + )!! + } + context.privateClasses = privateClasses + } + } +) + +internal val escapeAnalysisPhase = makeKonanModuleOpPhase( + // Disabled by default !!!! + name = "EscapeAnalysis", + description = "Escape analysis", + prerequisite = setOf(buildDFGPhase, deserializeDFGPhase), // TODO: Requires devirtualization. + op = { context, _ -> + context.externalModulesDFG?.let { externalModulesDFG -> + val callGraph = CallGraphBuilder( + context, context.moduleDFG!!, + externalModulesDFG, + context.devirtualizationAnalysisResult, + false + ).build() + EscapeAnalysis.computeLifetimes( + context, context.moduleDFG!!, externalModulesDFG, callGraph, context.lifetimes + ) + } + } +) + +internal val serializeDFGPhase = makeKonanModuleOpPhase( + name = "SerializeDFG", + description = "Data flow graph serializing", + prerequisite = setOf(buildDFGPhase), // TODO: Requires escape analysis. + op = { context, _ -> + DFGSerializer.serialize(context, context.moduleDFG!!) + } +) + +internal val codegenPhase = makeKonanModuleOpPhase( + name = "Codegen", + description = "Code Generation", + op = { context, irModule -> + irModule.acceptVoid(context.codegenVisitor) + } +) + +internal val finalizeDebugInfoPhase = makeKonanModuleOpPhase( + name = "FinalizeDebugInfo", + description = "Finalize debug info", + op = { context, _ -> + if (context.shouldContainDebugInfo()) { + DIFinalize(context.debugInfo.builder) + } + } +) + +internal val cStubsPhase = makeKonanModuleOpPhase( + name = "CStubs", + description = "C stubs compilation", + op = { context, _ -> produceCStubs(context) } +) + +internal val bitcodeLinkerPhase = makeKonanModuleOpPhase( + name = "BitcodeLinker", + description = "Bitcode linking", + op = { context, _ -> produceOutput(context) } +) + +internal val verifyBitcodePhase = makeKonanModuleOpPhase( + name = "VerifyBitcode", + description = "Verify bitcode", + op = { context, _ -> context.verifyBitCode() } +) + +internal val printBitcodePhase = makeKonanModuleOpPhase( + name = "PrintBitcode", + description = "Print bitcode", + op = { context, _ -> + if (context.shouldPrintBitCode()) { + context.printBitCode() + } + } +) + 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 149d44165f9..acfb13cbcad 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 @@ -22,7 +22,6 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor @@ -80,92 +79,6 @@ val IrField.isMainOnlyNonPrimitive get() = when { else -> storageClass == FieldStorage.MAIN_THREAD } -internal fun emitLLVM(context: Context, phaser: PhaseManager) { - val irModule = context.irModule!! - - // Note that we don't set module target explicitly. - // It is determined by the target of runtime.bc - // (see Llvm class in ContextUtils) - // Which in turn is determined by the clang flags - // used to compile runtime.bc. - val llvmModule = LLVMModuleCreateWithName("out")!! // TODO: dispose - context.llvmModule = llvmModule - context.debugInfo.builder = DICreateBuilder(llvmModule) - context.llvmDeclarations = createLlvmDeclarations(context) - - phaser.phase(KonanPhase.RTTI) { - irModule.acceptVoid(RTTIGeneratorVisitor(context)) - } - - generateDebugInfoHeader(context) - - var moduleDFG: ModuleDFG? = null - phaser.phase(KonanPhase.BUILD_DFG) { - moduleDFG = ModuleDFGBuilder(context, irModule).build() - } - - val lifetimes = mutableMapOf() - val codegenVisitor = CodeGeneratorVisitor(context, lifetimes) - - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - var externalModulesDFG: ExternalModulesDFG? = null - phaser.phase(KonanPhase.DESERIALIZE_DFG) { - externalModulesDFG = DFGSerializer.deserialize(context, moduleDFG!!.symbolTable.privateTypeIndex, moduleDFG!!.symbolTable.privateFunIndex) - } - - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - var devirtualizationAnalysisResult: Devirtualization.AnalysisResult? = null - phaser.phase(KonanPhase.DEVIRTUALIZATION) { - externalModulesDFG?.let { externalModulesDFG -> - devirtualizationAnalysisResult = Devirtualization.run(irModule, context, moduleDFG!!, externalModulesDFG) - - val privateFunctions = moduleDFG!!.symbolTable.getPrivateFunctionsTableForExport() - privateFunctions.forEachIndexed { index, it -> - val function = codegenVisitor.codegen.llvmFunction(it.first) - LLVMAddAlias( - context.llvmModule, - function.type, - function, - irModule.descriptor.privateFunctionSymbolName(index, it.second.name) - )!! - } - context.privateFunctions = privateFunctions - - val privateClasses = moduleDFG!!.symbolTable.getPrivateClassesTableForExport() - - privateClasses.forEachIndexed { index, it -> - val typeInfoPtr = codegenVisitor.codegen.typeInfoValue(it.first) - LLVMAddAlias( - context.llvmModule, - typeInfoPtr.type, - typeInfoPtr, - irModule.descriptor.privateClassSymbolName(index, it.second.name) - )!! - } - context.privateClasses = privateClasses - } - } - - phaser.phase(KonanPhase.ESCAPE_ANALYSIS) { - externalModulesDFG?.let { externalModulesDFG -> - val callGraph = CallGraphBuilder(context, moduleDFG!!, externalModulesDFG, devirtualizationAnalysisResult, false).build() - EscapeAnalysis.computeLifetimes(context, moduleDFG!!, externalModulesDFG, callGraph, lifetimes) - } - } - - phaser.phase(KonanPhase.SERIALIZE_DFG) { - DFGSerializer.serialize(context, moduleDFG!!) - } - - phaser.phase(KonanPhase.CODEGEN) { - irModule.acceptVoid(codegenVisitor) - } - - if (context.shouldContainDebugInfo()) { - DIFinalize(context.debugInfo.builder) - } -} - internal fun verifyModule(llvmModule: LLVMModuleRef, current: String = "") { memScoped { val errorRef = allocPointerTo()