Introduce flag for bitcode to native compilation This enables splitting the compilation pipeline into multiple invocations of the compiler.
diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt index b4181e3..f574068 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt
@@ -412,6 +412,19 @@ @Argument(value = "-Xomit-framework-binary", description = "Omit binary when compiling framework") var omitFrameworkBinary: Boolean = false + @Argument(value = "-Xcompile-from-bitcode", description = "Continue compilation from bitcode file", valueDescription = "<path>") + var compileFromBitcode: String? = null + + @Argument( + value = "-Xread-dependencies-from", + description = "Serialized dependencies to use for linking", + valueDescription = "<path>" + ) + var serializedDependencies: String? = null + + @Argument(value = "-Xwrite-dependencies-to", description = "Path for writing backend dependencies") + var saveDependenciesPath: String? = null + @Argument(value = "-Xsave-llvm-ir-directory", description = "Directory that should contain results of -Xsave-llvm-ir-after=<phase>") var saveLlvmIrDirectory: String? = null
diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 5ba62ff..7d37831 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt
@@ -133,7 +133,7 @@ private val K2NativeCompilerArguments.isUsefulWithoutFreeArgs: Boolean get() = listTargets || listPhases || checkDependencies || !includes.isNullOrEmpty() || - libraryToAddToCache != null || !exportedLibraries.isNullOrEmpty() + libraryToAddToCache != null || !exportedLibraries.isNullOrEmpty() || !compileFromBitcode.isNullOrEmpty() // It is executed before doExecute(). override fun setupPlatformSpecificArgumentsAndServices(
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt index 441544f..8feb250 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt
@@ -167,7 +167,7 @@ } } -private fun embedAppleLinkerOptionsToBitcode(llvm: Llvm, config: KonanConfig) { +private fun embedAppleLinkerOptionsToBitcode(llvm: CodegenLlvmHelpers, config: KonanConfig) { fun findEmbeddableOptions(options: List<String>): List<List<String>> { val result = mutableListOf<List<String>>() val iterator = options.iterator()
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DependenciesTracker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DependenciesTracker.kt index e60688a..be37c72 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DependenciesTracker.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DependenciesTracker.kt
@@ -371,5 +371,49 @@ data class DependenciesTrackingResult( val nativeDependenciesToLink: List<KonanLibrary>, val allNativeDependencies: List<KonanLibrary>, - val allCachedBitcodeDependencies: List<DependenciesTracker.ResolvedDependency> -) \ No newline at end of file + val allCachedBitcodeDependencies: List<DependenciesTracker.ResolvedDependency>) { + + companion object { + private const val NATIVE_DEPENDENCIES_TO_LINK = "NATIVE_DEPENDENCIES_TO_LINK" + private const val ALL_NATIVE_DEPENDENCIES = "ALL_NATIVE_DEPENDENCIES" + private const val ALL_CACHED_BITCODE_DEPENDENCIES = "ALL_CACHED_BITCODE_DEPENDENCIES" + + fun serialize(res: DependenciesTrackingResult): List<String> { + val nativeDepsToLink = DependenciesSerializer.serialize(res.nativeDependenciesToLink.map { DependenciesTracker.ResolvedDependency.wholeModule(it) }) + val allNativeDeps = DependenciesSerializer.serialize(res.allNativeDependencies.map { DependenciesTracker.ResolvedDependency.wholeModule(it) }) + val allCachedBitcodeDeps = DependenciesSerializer.serialize(res.allCachedBitcodeDependencies) + return listOf(NATIVE_DEPENDENCIES_TO_LINK) + nativeDepsToLink + + listOf(ALL_NATIVE_DEPENDENCIES) + allNativeDeps + + listOf(ALL_CACHED_BITCODE_DEPENDENCIES) + allCachedBitcodeDeps + } + + fun deserialize(path: String, dependencies: List<String>, config: KonanConfig): DependenciesTrackingResult { + + val nativeDepsToLinkIndex = dependencies.indexOf(NATIVE_DEPENDENCIES_TO_LINK) + require(nativeDepsToLinkIndex >= 0) { "Invalid dependency file at $path" } + val allNativeDepsIndex = dependencies.indexOf(ALL_NATIVE_DEPENDENCIES) + require(allNativeDepsIndex >= 0) { "Invalid dependency file at $path" } + val allCachedBitcodeDepsIndex = dependencies.indexOf(ALL_CACHED_BITCODE_DEPENDENCIES) + require(allCachedBitcodeDepsIndex >= 0) { "Invalid dependency file at $path" } + + val nativeLibsToLink = DependenciesSerializer.deserialize(path, dependencies.subList(nativeDepsToLinkIndex + 1, allNativeDepsIndex)).map { it.libName } + val allNativeLibs = DependenciesSerializer.deserialize(path, dependencies.subList(allNativeDepsIndex + 1, allCachedBitcodeDepsIndex)).map { it.libName } + val allCachedBitcodeDeps = DependenciesSerializer.deserialize(path, dependencies.subList(allCachedBitcodeDepsIndex + 1, dependencies.size)) + + val topSortedLibraries = config.resolvedLibraries.getFullList(TopologicalLibraryOrder) + val nativeDependenciesToLink = topSortedLibraries.mapNotNull { if (it.uniqueName in nativeLibsToLink && it is KonanLibrary) it else null } + val allNativeDependencies = topSortedLibraries.mapNotNull { if (it.uniqueName in allNativeLibs && it is KonanLibrary) it else null } + val allCachedBitcodeDependencies = allCachedBitcodeDeps.map { unresolvedDep -> + val lib = topSortedLibraries.find { it.uniqueName == unresolvedDep.libName } + require(lib != null && lib is KonanLibrary) { "Invalid dependency ${unresolvedDep.libName} at $path" } + when (unresolvedDep.kind) { + is DependenciesTracker.DependencyKind.CertainFiles -> + DependenciesTracker.ResolvedDependency.certainFiles(lib, unresolvedDep.kind.files) + else -> DependenciesTracker.ResolvedDependency.wholeModule(lib) + } + } + + return DependenciesTrackingResult(nativeDependenciesToLink, allNativeDependencies, allCachedBitcodeDependencies) + } + } +}
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index 1252c38..bbe8129 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt
@@ -476,11 +476,6 @@ } ?: File(outputPath).name - val infoArgsOnly = (configuration.kotlinSourceRoots.isEmpty() - && configuration[KonanConfigKeys.INCLUDED_LIBRARIES].isNullOrEmpty() - && configuration[KonanConfigKeys.EXPORTED_LIBRARIES].isNullOrEmpty() - && libraryToCache == null) - /** * Do not compile binary when compiling framework. * This is useful when user care only about framework's interface. @@ -495,6 +490,40 @@ } /** + * Continue from bitcode. Skips the frontend and codegen phase of the compiler + * and instead reads the provided bitcode file. + * This option can be used for continuing the compilation from a previous invocation. + */ + internal val compileFromBitcode: String? by lazy { + configuration.get(KonanConfigKeys.COMPILE_FROM_BITCODE) + } + + /** + * Path to serialized dependencies to use for bitcode compilation. + */ + internal val readSerializedDependencies: String? by lazy { + configuration.get(KonanConfigKeys.SERIALIZED_DEPENDENCIES).also { + if (compileFromBitcode.isNullOrEmpty()) { + configuration.report(CompilerMessageSeverity.STRONG_WARNING, + "Providing serialized dependencies only works in conjunction with a bitcode file to compile.") + } + } + } + + /** + * Path to store backend dependency information. + */ + internal val writeSerializedDependencies: String? by lazy { + configuration.get(KonanConfigKeys.SAVE_DEPENDENCIES_PATH) + } + + val infoArgsOnly = (configuration.kotlinSourceRoots.isEmpty() + && configuration[KonanConfigKeys.INCLUDED_LIBRARIES].isNullOrEmpty() + && configuration[KonanConfigKeys.EXPORTED_LIBRARIES].isNullOrEmpty() + && libraryToCache == null && compileFromBitcode.isNullOrEmpty()) + + + /** * Directory to store LLVM IR from -Xsave-llvm-ir-after. */ internal val saveLlvmIrDirectory: java.io.File by lazy {
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index c9cd246..b2c0590 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt
@@ -161,6 +161,9 @@ val PARTIAL_LINKAGE: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("allows some symbols in klibs be missed") val TEST_DUMP_OUTPUT_PATH: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("path to a file to dump the list of all available tests") val OMIT_FRAMEWORK_BINARY: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("do not generate binary in framework") + val COMPILE_FROM_BITCODE: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("path to bitcode file to compile") + val SERIALIZED_DEPENDENCIES: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("path to serialized dependencies for native linking") + val SAVE_DEPENDENCIES_PATH: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("path to save serialized dependencies to") val SAVE_LLVM_IR_DIRECTORY: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("directory to store LLVM IR from phases") } }
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt index b473355..a3d60ad 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt
@@ -7,6 +7,7 @@ import llvm.* import org.jetbrains.kotlin.backend.konan.driver.BasicPhaseContext +import org.jetbrains.kotlin.backend.konan.driver.PhaseContext import org.jetbrains.kotlin.backend.konan.driver.utilities.BackendContextHolder import org.jetbrains.kotlin.backend.konan.driver.utilities.LlvmIrHolder import org.jetbrains.kotlin.backend.konan.llvm.* @@ -16,7 +17,6 @@ import org.jetbrains.kotlin.backend.konan.serialization.SerializedEagerInitializedFile import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.konan.TempFiles internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int) @@ -38,6 +38,19 @@ "$prefix${cStubCount++}" } +internal interface BitcodePostProcessingContext : PhaseContext, LlvmIrHolder { + val llvm: BasicLlvmHelpers + val llvmContext: LLVMContextRef +} + +internal class BitcodePostProcessingContextImpl( + config: KonanConfig, + override val llvmModule: LLVMModuleRef, + override val llvmContext: LLVMContextRef +) : BitcodePostProcessingContext, BasicPhaseContext(config) { + override val llvm: BasicLlvmHelpers = BasicLlvmHelpers(this, llvmModule) +} + internal class NativeGenerationState( config: KonanConfig, // TODO: Get rid of this property completely once transition to the dynamic driver is complete. @@ -48,7 +61,7 @@ val llvmModuleSpecification: LlvmModuleSpecification, val outputFiles: OutputFiles, val llvmModuleName: String, -) : BasicPhaseContext(config), BackendContextHolder<Context>, LlvmIrHolder { +) : BasicPhaseContext(config), BackendContextHolder<Context>, LlvmIrHolder, BitcodePostProcessingContext { val outputFile = outputFiles.mainFileName val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>() @@ -72,12 +85,12 @@ val producedLlvmModuleContainsStdlib get() = llvmModuleSpecification.containsModule(context.stdlibModule) private val runtimeDelegate = lazy { Runtime(llvmContext, config.distribution.compilerInterface(config.target)) } - private val llvmDelegate = lazy { Llvm(this, LLVMModuleCreateWithNameInContext(llvmModuleName, llvmContext)!!) } + private val llvmDelegate = lazy { CodegenLlvmHelpers(this, LLVMModuleCreateWithNameInContext(llvmModuleName, llvmContext)!!) } private val debugInfoDelegate = lazy { DebugInfo(this) } - val llvmContext = LLVMContextCreate()!! + override val llvmContext = LLVMContextCreate()!! val runtime by runtimeDelegate - val llvm by llvmDelegate + override val llvm by llvmDelegate val debugInfo by debugInfoDelegate val cStubsManager = CStubsManager(config.target, this) lateinit var llvmDeclarations: LlvmDeclarations
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/SetupConfiguration.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/SetupConfiguration.kt index 42bd119..f6c6a95 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/SetupConfiguration.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/SetupConfiguration.kt
@@ -259,6 +259,9 @@ arguments.testDumpOutputPath?.let { put(TEST_DUMP_OUTPUT_PATH, it) } put(PARTIAL_LINKAGE, arguments.partialLinkage) put(OMIT_FRAMEWORK_BINARY, arguments.omitFrameworkBinary) + putIfNotNull(COMPILE_FROM_BITCODE, arguments.compileFromBitcode) + putIfNotNull(SERIALIZED_DEPENDENCIES, arguments.serializedDependencies) + putIfNotNull(SAVE_DEPENDENCIES_PATH, arguments.saveDependenciesPath) putIfNotNull(SAVE_LLVM_IR_DIRECTORY, arguments.saveLlvmIrDirectory) }
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt index 81dc38f..0703696 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.ir.* -import org.jetbrains.kotlin.backend.konan.llvm.Llvm +import org.jetbrains.kotlin.backend.konan.llvm.CodegenLlvmHelpers import org.jetbrains.kotlin.backend.konan.llvm.computeFunctionName import org.jetbrains.kotlin.backend.konan.llvm.toLLVMType import org.jetbrains.kotlin.backend.konan.llvm.localHash @@ -263,7 +263,7 @@ } } -internal fun IrField.requiredAlignment(llvm: Llvm): Int { +internal fun IrField.requiredAlignment(llvm: CodegenLlvmHelpers): Int { val llvmType = type.toLLVMType(llvm) val abiAlignment = if (llvmType == llvm.vector128Type) { 8 // over-aligned objects are not supported now, and this worked somehow, so let's keep it as it for now @@ -283,7 +283,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) { - private fun IrField.toFieldInfo(llvm: Llvm): FieldInfo { + private fun IrField.toFieldInfo(llvm: CodegenLlvmHelpers): FieldInfo { val isConst = correspondingPropertySymbol?.owner?.isConst ?: false require(!isConst || initializer?.expression is IrConst<*>) { "A const val field ${render()} must have constant initializer" } return FieldInfo(name.asString(), type, isConst, symbol, requiredAlignment(llvm)) @@ -435,7 +435,7 @@ * All fields of the class instance. * The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix. */ - fun getFields(llvm: Llvm): List<FieldInfo> = getFieldsInternal(llvm).map { fieldInfo -> + fun getFields(llvm: CodegenLlvmHelpers): List<FieldInfo> = getFieldsInternal(llvm).map { fieldInfo -> val mappedField = fieldInfo.irField?.let { context.mapping.lateInitFieldToNullableField[it] ?: it } if (mappedField == fieldInfo.irField) fieldInfo @@ -445,7 +445,7 @@ private var fields: List<FieldInfo>? = null - private fun getFieldsInternal(llvm: Llvm): List<FieldInfo> { + private fun getFieldsInternal(llvm: CodegenLlvmHelpers): List<FieldInfo> { fields?.let { return it } val superClass = irClass.getSuperClassNotAny() @@ -503,7 +503,7 @@ /** * Fields declared in the class. */ - fun getDeclaredFields(llvm: Llvm): List<FieldInfo> { + fun getDeclaredFields(llvm: CodegenLlvmHelpers): List<FieldInfo> { val outerThisField = if (irClass.isInner) context.innerClassesSupport.getOuterThisField(irClass) else null
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/DynamicCompilerDriver.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/DynamicCompilerDriver.kt index 962aa15..763c8a8 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/DynamicCompilerDriver.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/DynamicCompilerDriver.kt
@@ -6,14 +6,20 @@ package org.jetbrains.kotlin.backend.konan.driver import kotlinx.cinterop.usingJvmCInteropCallbacks +import llvm.LLVMContextCreate +import llvm.LLVMContextDispose +import llvm.LLVMDisposeModule +import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.BitcodePostProcessingContextImpl import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.KonanConfig import org.jetbrains.kotlin.backend.konan.driver.phases.* import org.jetbrains.kotlin.backend.konan.getIncludedLibraryDescriptors -import org.jetbrains.kotlin.backend.konan.isCache +import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator @@ -26,7 +32,8 @@ usingNativeMemoryAllocator { usingJvmCInteropCallbacks { PhaseEngine.startTopLevel(config) { engine -> - when (config.produce) { + if (!config.compileFromBitcode.isNullOrEmpty()) produceBinaryFromBitcode(engine, config, config.compileFromBitcode!!) + else when (config.produce) { CompilerOutputKind.PROGRAM -> produceBinary(engine, config, environment) CompilerOutputKind.DYNAMIC -> produceCLibrary(engine, config, environment) CompilerOutputKind.STATIC -> produceCLibrary(engine, config, environment) @@ -124,6 +131,22 @@ engine.runBackend(backendContext, psiToIrOutput.irModule) } + private fun produceBinaryFromBitcode(engine: PhaseEngine<PhaseContext>, config: KonanConfig, bitcodeFilePath: String) { + val llvmContext = LLVMContextCreate()!! + val llvmModule = parseBitcodeFile(llvmContext, bitcodeFilePath) + try { + val context = BitcodePostProcessingContextImpl(config, llvmModule, llvmContext) + val depsPath = config.readSerializedDependencies + val dependencies = if (depsPath.isNullOrEmpty()) DependenciesTrackingResult(emptyList(), emptyList(), emptyList()).also { + config.configuration.report(CompilerMessageSeverity.WARNING, "No backend dependencies provided.") + } else DependenciesTrackingResult.deserialize(depsPath, File(depsPath).readStrings(), config) + engine.runBitcodeBackend(context, dependencies) + } finally { + LLVMDisposeModule(llvmModule) + LLVMContextDispose(llvmContext) + } + } + private fun createBackendContext( config: KonanConfig, frontendOutput: FrontendPhaseOutput.Full,
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/Machinery.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/Machinery.kt index 90612ec..5671d8a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/Machinery.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/Machinery.kt
@@ -118,6 +118,15 @@ } } + /** + * Create a new PhaseEngine instance for an existing context that should not be disposed after the action. + * This is useful for creating engines for a sub/super context type. + */ + inline fun <T : PhaseContext, R> newEngine(newContext: T, action: (PhaseEngine<T>) -> R): R { + val newEngine = PhaseEngine(phaseConfig, phaserState, newContext) + return action(newEngine) + } + fun <Input, Output, P : AbstractNamedCompilerPhase<C, Input, Output>> runPhase( phase: P, input: Input,
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Bitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Bitcode.kt index 82187a7..cc97add 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Bitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Bitcode.kt
@@ -108,7 +108,7 @@ op = { context, _ -> runCoveragePass(context) } ) -internal val RemoveRedundantSafepointsPhase = createSimpleNamedCompilerPhase<NativeGenerationState, Unit>( +internal val RemoveRedundantSafepointsPhase = createSimpleNamedCompilerPhase<BitcodePostProcessingContext, Unit>( name = "RemoveRedundantSafepoints", description = "Remove function prologue safepoints inlined to another function", postactions = getDefaultLlvmModuleActions(), @@ -120,7 +120,7 @@ } ) -internal val OptimizeTLSDataLoadsPhase = createSimpleNamedCompilerPhase<NativeGenerationState, Unit>( +internal val OptimizeTLSDataLoadsPhase = createSimpleNamedCompilerPhase<BitcodePostProcessingContext, Unit>( name = "OptimizeTLSDataLoads", description = "Optimize multiple loads of thread data", postactions = getDefaultLlvmModuleActions(), @@ -153,15 +153,11 @@ op = { _, llvmModule -> LLVMDumpModule(llvmModule) } ) -internal fun PhaseEngine<NativeGenerationState>.runBitcodePostProcessing() { - val checkExternalCalls = context.config.configuration.getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS) - if (checkExternalCalls) { - runPhase(CheckExternalCallsPhase) - } +internal fun <T : BitcodePostProcessingContext> PhaseEngine<T>.runBitcodePostProcessing() { val optimizationConfig = createLTOFinalPipelineConfig( context, context.llvm.targetTriple, - closedWorld = context.llvmModuleSpecification.isFinal, + closedWorld = context.config.isFinalBinary, timePasses = context.config.flexiblePhaseConfig.needProfiling, ) useContext(OptimizationState(context.config, optimizationConfig)) { @@ -175,14 +171,14 @@ null -> {} } } - runPhase(CoveragePhase) + val checkExternalCalls = context.config.configuration.getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS) + if (checkExternalCalls && context is NativeGenerationState) { + newEngine(context) { it.runPhase(CoveragePhase) } + } if (context.config.memoryModel == MemoryModel.EXPERIMENTAL) { runPhase(RemoveRedundantSafepointsPhase) } if (context.config.optimizationsEnabled) { runPhase(OptimizeTLSDataLoadsPhase) } - if (checkExternalCalls) { - runPhase(RewriteExternalCallsCheckerGlobals) - } -} \ No newline at end of file +}
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt index 2375a00..ed5d04c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.Family import org.jetbrains.kotlin.library.impl.javaFile -import java.io.File +import org.jetbrains.kotlin.konan.file.File internal fun PhaseEngine<PhaseContext>.runFrontend(config: KonanConfig, environment: KotlinCoreEnvironment): FrontendPhaseOutput.Full? { val frontendOutput = useContext(FrontendContextImpl(config)) { it.runPhase(FrontendPhase, environment) } @@ -80,7 +80,12 @@ // TODO: Make this work if we first compile all the fragments and only after that run the link phases. generationStateEngine.compileModule(fragment.irModule, bitcodeFile, cExportFiles) // Split here - val moduleCompilationOutput = ModuleCompilationOutput(bitcodeFile, generationState.dependenciesTracker.collectResult()) + val dependenciesTrackingResult = generationState.dependenciesTracker.collectResult() + val depsFilePath = config.writeSerializedDependencies + if (!depsFilePath.isNullOrEmpty()) { + depsFilePath.File().writeLines(DependenciesTrackingResult.serialize(dependenciesTrackingResult)) + } + val moduleCompilationOutput = ModuleCompilationOutput(bitcodeFile, dependenciesTrackingResult) compileAndLink(moduleCompilationOutput, outputFiles.mainFileName, outputFiles, tempFiles, isCoverageEnabled = false) } } finally { @@ -90,6 +95,19 @@ } } +internal fun <C : PhaseContext> PhaseEngine<C>.runBitcodeBackend(context: BitcodePostProcessingContext, dependencies: DependenciesTrackingResult) { + useContext(context) { bitcodeEngine -> + val tempFiles = createTempFiles(context.config, null) + val bitcodeFile = tempFiles.create(context.config.shortModuleName ?: "out", ".bc").javaFile() + val outputPath = context.config.outputPath + val outputFiles = OutputFiles(outputPath, context.config.target, context.config.produce) + bitcodeEngine.runBitcodePostProcessing() + runPhase(WriteBitcodeFilePhase, WriteBitcodeFileInput(context.llvm.module, bitcodeFile)) + val moduleCompilationOutput = ModuleCompilationOutput(bitcodeFile, dependencies) + compileAndLink(moduleCompilationOutput, outputFiles.mainFileName, outputFiles, tempFiles, isCoverageEnabled = false) + } +} + private fun isReferencedByNativeRuntime(declarations: List<IrDeclaration>): Boolean = declarations.any { it.hasAnnotation(RuntimeNames.exportTypeInfoAnnotation) @@ -159,7 +177,7 @@ } internal data class ModuleCompilationOutput( - val bitcodeFile: File, + val bitcodeFile: java.io.File, val dependenciesTrackingResult: DependenciesTrackingResult, ) @@ -170,7 +188,7 @@ * 4. Optimizes it. * 5. Serializes it to a bitcode file. */ -internal fun PhaseEngine<NativeGenerationState>.compileModule(module: IrModuleFragment, bitcodeFile: File, cExportFiles: CExportFiles?) { +internal fun PhaseEngine<NativeGenerationState>.compileModule(module: IrModuleFragment, bitcodeFile: java.io.File, cExportFiles: CExportFiles?) { if (context.config.produce.isCache) { runPhase(BuildAdditionalCacheInfoPhase, module) } @@ -178,13 +196,21 @@ runPhase(EntryPointPhase, module) } runBackendCodegen(module, cExportFiles) - runBitcodePostProcessing() + val checkExternalCalls = context.config.configuration.getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS) + if (checkExternalCalls) { + runPhase(CheckExternalCallsPhase) + } + newEngine(context as BitcodePostProcessingContext) { it.runBitcodePostProcessing() } + if (checkExternalCalls) { + runPhase(RewriteExternalCallsCheckerGlobals) + } if (context.config.produce.isCache) { runPhase(SaveAdditionalCacheInfoPhase) } runPhase(WriteBitcodeFilePhase, WriteBitcodeFileInput(context.llvm.module, bitcodeFile)) } + internal fun <C : PhaseContext> PhaseEngine<C>.compileAndLink( moduleCompilationOutput: ModuleCompilationOutput, linkerOutputFile: String,
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 09b895a..d0b33a1 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt
@@ -1298,7 +1298,7 @@ assert(!irClass.isInterface) return if (irClass.isExternalObjCClass()) { - llvm.dependenciesTracker.add(irClass) + generationState.dependenciesTracker.add(irClass) if (irClass.isObjCMetaClass()) { val name = irClass.descriptor.getExternalObjCMetaClassBinaryName() val objCClass = getObjCClass(name) @@ -1337,7 +1337,7 @@ private fun getObjCClass(binaryName: String) = load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm) fun getObjCClassFromNativeRuntime(binaryName: String): LLVMValueRef { - llvm.dependenciesTracker.addNativeRuntime() + generationState.dependenciesTracker.addNativeRuntime() return getObjCClass(binaryName) }
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index d3b39c4..b9d2c3a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt
@@ -148,7 +148,7 @@ val llvmTargetData: LLVMTargetDataRef get() = runtime.targetData - val llvm: Llvm + val llvm: CodegenLlvmHelpers get() = generationState.llvm val staticData: KotlinStaticData @@ -256,42 +256,61 @@ } } -internal class ConstInt1(llvm: Llvm, val value: Boolean) : ConstValue { +internal class ConstInt1(llvm: CodegenLlvmHelpers, val value: Boolean) : ConstValue { override val llvm = LLVMConstInt(llvm.int1Type, if (value) 1 else 0, 1)!! } -internal class ConstInt8(llvm: Llvm, val value: Byte) : ConstValue { +internal class ConstInt8(llvm: CodegenLlvmHelpers, val value: Byte) : ConstValue { override val llvm = LLVMConstInt(llvm.int8Type, value.toLong(), 1)!! } -internal class ConstInt16(llvm: Llvm, val value: Short) : ConstValue { +internal class ConstInt16(llvm: CodegenLlvmHelpers, val value: Short) : ConstValue { override val llvm = LLVMConstInt(llvm.int16Type, value.toLong(), 1)!! } -internal class ConstChar16(llvm: Llvm, val value: Char) : ConstValue { +internal class ConstChar16(llvm: CodegenLlvmHelpers, val value: Char) : ConstValue { override val llvm = LLVMConstInt(llvm.int16Type, value.code.toLong(), 1)!! } -internal class ConstInt32(llvm: Llvm, val value: Int) : ConstValue { +internal class ConstInt32(llvm: CodegenLlvmHelpers, val value: Int) : ConstValue { override val llvm = LLVMConstInt(llvm.int32Type, value.toLong(), 1)!! } -internal class ConstInt64(llvm: Llvm, val value: Long) : ConstValue { +internal class ConstInt64(llvm: CodegenLlvmHelpers, val value: Long) : ConstValue { override val llvm = LLVMConstInt(llvm.int64Type, value, 1)!! } -internal class ConstFloat32(llvm: Llvm, val value: Float) : ConstValue { +internal class ConstFloat32(llvm: CodegenLlvmHelpers, val value: Float) : ConstValue { override val llvm = LLVMConstReal(llvm.floatType, value.toDouble())!! } -internal class ConstFloat64(llvm: Llvm, val value: Double) : ConstValue { +internal class ConstFloat64(llvm: CodegenLlvmHelpers, val value: Double) : ConstValue { override val llvm = LLVMConstReal(llvm.doubleType, value)!! } +internal open class BasicLlvmHelpers(bitcodeContext: BitcodePostProcessingContext, val module: LLVMModuleRef) { + + val llvmContext = bitcodeContext.llvmContext + val targetTriple by lazy { + LLVMGetTarget(module)!!.toKString() + } + + val runtimeAnnotationMap by lazy { + StaticData.getGlobal(module, "llvm.global.annotations") + ?.getInitializer() + ?.let { getOperands(it) } + ?.groupBy( + { LLVMGetInitializer(LLVMGetOperand(LLVMGetOperand(it, 1), 0))?.getAsCString() ?: "" }, + { LLVMGetOperand(LLVMGetOperand(it, 0), 0)!! } + ) + ?.filterKeys { it != "" } + ?: emptyMap() + } +} + @Suppress("FunctionName", "PropertyName", "PrivatePropertyName") -internal class Llvm(private val generationState: NativeGenerationState, val module: LLVMModuleRef) : RuntimeAware { +internal class CodegenLlvmHelpers(private val generationState: NativeGenerationState, module: LLVMModuleRef) : BasicLlvmHelpers(generationState, module), RuntimeAware { private val context = generationState.context - val llvmContext = generationState.llvmContext private fun importFunction(name: String, otherModule: LLVMModuleRef): LlvmCallable { if (LLVMGetNamedFunction(module, name) != null) { @@ -378,11 +397,9 @@ override val runtime get() = generationState.runtime - val targetTriple = runtime.target - init { LLVMSetDataLayout(module, runtime.dataLayout) - LLVMSetTarget(module, targetTriple) + LLVMSetTarget(module, runtime.target) } private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule) @@ -480,27 +497,14 @@ val initializersGenerationState = InitializersGenerationState() val boxCacheGlobals = mutableMapOf<BoxCache, StaticData.Global>() - val runtimeAnnotationMap by lazy { - staticData.getGlobal("llvm.global.annotations") - ?.getInitializer() - ?.let { getOperands(it) } - ?.groupBy( - { LLVMGetInitializer(LLVMGetOperand(LLVMGetOperand(it, 1), 0))?.getAsCString() ?: "" }, - { LLVMGetOperand(LLVMGetOperand(it, 0), 0)!! } - ) - ?.filterKeys { it != "" } - ?: emptyMap() - } - - private object lazyRtFunction { operator fun provideDelegate( - thisRef: Llvm, property: KProperty<*> - ) = object : ReadOnlyProperty<Llvm, LlvmCallable> { + thisRef: CodegenLlvmHelpers, property: KProperty<*> + ) = object : ReadOnlyProperty<CodegenLlvmHelpers, LlvmCallable> { val value: LlvmCallable by lazy { thisRef.importRtFunction(property.name) } - override fun getValue(thisRef: Llvm, property: KProperty<*>): LlvmCallable = value + override fun getValue(thisRef: CodegenLlvmHelpers, property: KProperty<*>): LlvmCallable = value } }
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt index a9e8ccd..4bc2afb 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DataLayout.kt
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.types.isUnit -private fun PrimitiveBinaryType?.toLlvmType(llvm: Llvm) = when (this) { +private fun PrimitiveBinaryType?.toLlvmType(llvm: CodegenLlvmHelpers) = when (this) { null -> llvm.kObjHeaderPtr PrimitiveBinaryType.BOOLEAN -> llvm.int1Type @@ -26,12 +26,12 @@ PrimitiveBinaryType.POINTER -> llvm.int8PtrType } -internal fun IrType.toLLVMType(llvm: Llvm): LLVMTypeRef = +internal fun IrType.toLLVMType(llvm: CodegenLlvmHelpers): LLVMTypeRef = llvm.runtime.calculatedLLVMTypes.getOrPut(this) { computePrimitiveBinaryTypeOrNull().toLlvmType(llvm) } internal fun IrType.isVoidAsReturnType() = isUnit() || isNothing() -internal fun IrType.getLLVMReturnType(llvm: Llvm) = when { +internal fun IrType.getLLVMReturnType(llvm: CodegenLlvmHelpers) = when { isVoidAsReturnType() -> llvm.voidType else -> toLLVMType(llvm) }
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index a67b6ca..3a9cb48 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.konan.target.Family import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.uniqueName -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.descriptorUtil.classId @@ -472,7 +471,7 @@ private fun createInitBody(state: ScopeInitializersGenerationState): LLVMValueRef { val initFunction = addLlvmFunctionWithDefaultAttributes( - context, + generationState.context, llvm.module, "", kInitFuncType @@ -551,7 +550,7 @@ // Create static object of class InitNode. val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!! // Create global variable with init record data. - return llvm.staticData.placeGlobal("init_node", constPointer(initNode), isExported = false).llvmGlobal + return codegen.staticData.placeGlobal("init_node", constPointer(initNode), isExported = false).llvmGlobal } //-------------------------------------------------------------------------// @@ -842,7 +841,7 @@ recordCoverage(body) if (declaration.isReifiedInline) { callDirect(context.ir.symbols.throwIllegalStateExceptionWithMessage.owner, - listOf(llvm.staticData.kotlinStringLiteral( + listOf(codegen.staticData.kotlinStringLiteral( "unsupported call of reified inlined function `${declaration.fqNameForIrSerialization}`").llvm), Lifetime.IRRELEVANT, null) return@usingVariableScope @@ -1288,7 +1287,7 @@ functionGenerationContext.positionAtEnd(whenEmittingContext.bbExit.value) return when { - expression.type.isUnit() -> functionGenerationContext.theUnitInstanceRef.llvm + expression.type.isUnit() -> codegen.theUnitInstanceRef.llvm expression.type.isNothing() -> functionGenerationContext.kNothingFakeValue whenEmittingContext.resultPhi.isInitialized() -> whenEmittingContext.resultPhi.value else -> LLVMGetUndef(whenEmittingContext.llvmType)!! @@ -1346,7 +1345,7 @@ } assert(loop.type.isUnit()) - return functionGenerationContext.theUnitInstanceRef.llvm + return codegen.theUnitInstanceRef.llvm } //-------------------------------------------------------------------------// @@ -1371,7 +1370,7 @@ } assert(loop.type.isUnit()) - return functionGenerationContext.theUnitInstanceRef.llvm + return codegen.theUnitInstanceRef.llvm } //-------------------------------------------------------------------------// @@ -1395,7 +1394,7 @@ val variable = currentCodeContext.getDeclaredValue(value.symbol.owner) functionGenerationContext.vars.store(result, variable) assert(value.type.isUnit()) - return functionGenerationContext.theUnitInstanceRef.llvm + return codegen.theUnitInstanceRef.llvm } //-------------------------------------------------------------------------// @@ -1465,7 +1464,7 @@ IrTypeOperator.IMPLICIT_NOTNULL -> TODO(ir2string(value)) IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { evaluateExpression(value.argument) - functionGenerationContext.theUnitInstanceRef.llvm + codegen.theUnitInstanceRef.llvm } IrTypeOperator.SAFE_CAST -> throw IllegalStateException("safe cast wasn't lowered") IrTypeOperator.INSTANCEOF -> evaluateInstanceOf(value) @@ -1533,7 +1532,7 @@ val dstFullClassName = dstClass.fqNameWhenAvailable?.toString() ?: dstClass.name.toString() callDirect( context.ir.symbols.throwTypeCastException.owner, - listOf(srcArg, llvm.staticData.kotlinStringLiteral(dstFullClassName).llvm), + listOf(srcArg, codegen.staticData.kotlinStringLiteral(dstFullClassName).llvm), Lifetime.GLOBAL, null ) @@ -1810,7 +1809,7 @@ //-------------------------------------------------------------------------// private fun evaluateStringConst(value: IrConst<String>) = - llvm.staticData.kotlinStringLiteral(value.value) + codegen.staticData.kotlinStringLiteral(value.value) private fun evaluateConst(value: IrConst<*>): ConstValue { context.log{"evaluateConst : ${ir2string(value)}"} @@ -1862,7 +1861,7 @@ require(value.type.toLLVMType(llvm) == codegen.kObjHeaderPtr) { "Can't wrap ${value.value.kind.asString} constant to type ${value.type.render()}" } - value.toBoxCacheValue(generationState) ?: llvm.staticData.createConstKotlinObject( + value.toBoxCacheValue(generationState) ?: codegen.staticData.createConstKotlinObject( constructedType.getClass()!!, evaluateConst(value.value) ) @@ -1876,7 +1875,7 @@ require(clazz.symbol == symbols.array || clazz.symbol in symbols.primitiveTypesToPrimitiveArrays.values) { "Statically initialized array should have array type" } - llvm.staticData.createConstKotlinArray( + codegen.staticData.createConstKotlinArray( value.type.getClass()!!, value.elements.map { evaluateConstantValue(it) } ) @@ -1937,7 +1936,7 @@ } require(value.type.toLLVMType(llvm) == codegen.kObjHeaderPtr) { "Constant object is not an object, but ${value.type.render()}" } - llvm.staticData.createConstKotlinObject( + codegen.staticData.createConstKotlinObject( constructedClass, *fields.toTypedArray() ) @@ -2717,7 +2716,7 @@ if (args.isEmpty()) return val argsCasted = args.map { constPointer(it).bitcast(llvm.int8PtrType) } - val llvmUsedGlobal = llvm.staticData.placeGlobalArray(name, llvm.int8PtrType, argsCasted) + val llvmUsedGlobal = codegen.staticData.placeGlobalArray(name, llvm.int8PtrType, argsCasted) LLVMSetLinkage(llvmUsedGlobal.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage) LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata") @@ -2802,7 +2801,7 @@ fun addCtorFunction(ctorName: String) = addLlvmFunctionWithDefaultAttributes( - context, + generationState.context, llvm.module, ctorName, kVoidFuncType @@ -2898,7 +2897,7 @@ LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMPrivateLinkage) // Append initializers of global variables in "llvm.global_ctors" array. - val globalCtors = llvm.staticData.placeGlobalArray("llvm.global_ctors", kCtorType, + val globalCtors = codegen.staticData.placeGlobalArray("llvm.global_ctors", kCtorType, listOf(createGlobalCtor(globalCtorFunction))) LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage) if (context.config.produce == CompilerOutputKind.PROGRAM) {
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt index 18d1f0d..f3d0297 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt
@@ -7,9 +7,7 @@ import kotlinx.cinterop.cValuesOf import llvm.* -import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.NativeGenerationState -import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.expressions.IrConst @@ -17,7 +15,7 @@ return constPointer(LLVMConstGEP(llvm, cValuesOf(index), 1)!!) } -internal class KotlinStaticData(override val generationState: NativeGenerationState, override val llvm: Llvm, module: LLVMModuleRef) : ContextUtils, StaticData(module, llvm) { +internal class KotlinStaticData(override val generationState: NativeGenerationState, override val llvm: CodegenLlvmHelpers, module: LLVMModuleRef) : ContextUtils, StaticData(module, llvm) { private val stringLiterals = mutableMapOf<String, ConstPointer>() // Must match OBJECT_TAG_PERMANENT_CONTAINER in C++.
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt index 4775b6c..06b1766 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt
@@ -23,7 +23,7 @@ get() = this.llvm.type internal interface ConstPointer : ConstValue { - fun getElementPtr(llvm: Llvm, index: Int): ConstPointer = ConstGetElementPtr(llvm, this, index) + fun getElementPtr(llvm: CodegenLlvmHelpers, index: Int): ConstPointer = ConstGetElementPtr(llvm, this, index) } internal fun constPointer(value: LLVMValueRef) = object : ConstPointer { @@ -34,7 +34,7 @@ override val llvm = value } -private class ConstGetElementPtr(llvm: Llvm, pointer: ConstPointer, index: Int) : ConstPointer { +private class ConstGetElementPtr(llvm: CodegenLlvmHelpers, pointer: ConstPointer, index: Int) : ConstPointer { override val llvm = LLVMConstInBoundsGEP(pointer.llvm, cValuesOf(llvm.int32(0), llvm.int32(index)), 2)!! // TODO: squash multiple GEPs } @@ -182,12 +182,12 @@ } internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, declaration: IrDeclaration) = - importGlobal(name, type).also { llvm.dependenciesTracker.add(declaration) } + importGlobal(name, type).also { generationState.dependenciesTracker.add(declaration) } internal fun ContextUtils.importObjCGlobal(name: String, type: LLVMTypeRef) = importGlobal(name, type) internal fun ContextUtils.importNativeRuntimeGlobal(name: String, type: LLVMTypeRef) = - importGlobal(name, type).also { llvm.dependenciesTracker.addNativeRuntime() } + importGlobal(name, type).also { generationState.dependenciesTracker.addNativeRuntime() } private fun CodeGenerator.replaceExternalWeakOrCommonGlobal(name: String, value: ConstValue) { if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt index 6a86709..2ce7ace 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticData.kt
@@ -10,7 +10,7 @@ /** * Provides utilities to create static data. */ -internal open class StaticData(val module: LLVMModuleRef, private val llvm: Llvm) { +internal open class StaticData(val module: LLVMModuleRef, private val llvm: CodegenLlvmHelpers) { /** * Represents the LLVM global variable. @@ -52,6 +52,11 @@ val llvmGlobal = LLVMGetNamedGlobal(staticData.module, name) ?: return null return Global(llvmGlobal) } + + fun get(module: LLVMModuleRef, name: String): Global? { + val llvmGlobal = LLVMGetNamedGlobal(module, name) ?: return null + return Global(llvmGlobal) + } } val type get() = getGlobalType(this.llvmGlobal) @@ -150,4 +155,8 @@ } internal fun cStringLiteral(value: String) = cStringLiterals.getOrPut(value) { placeCStringLiteral(value) } + + companion object { + fun getGlobal(module: LLVMModuleRef, name: String) = Global.get(module, name) + } }
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/ObjCDataGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/ObjCDataGenerator.kt index 96fd623..2f21ae6 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/ObjCDataGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/ObjCDataGenerator.kt
@@ -116,7 +116,7 @@ ) val globalName = "\u0001l_OBJC_\$_INSTANCE_METHODS_$name" - val global = llvm.staticData.placeGlobal(globalName, methodList).also { + val global = codegen.staticData.placeGlobal(globalName, methodList).also { it.setLinkage(LLVMLinkage.LLVMPrivateLinkage) it.setAlignment(runtime.pointerAlignment) it.setSection("__DATA, __objc_const") @@ -165,7 +165,7 @@ "\u0001l_OBJC_CLASS_RO_\$_" } + name - val roGlobal = llvm.staticData.placeGlobal(roLabel, roValue).also { + val roGlobal = codegen.staticData.placeGlobal(roLabel, roValue).also { it.setLinkage(LLVMLinkage.LLVMPrivateLinkage) it.setAlignment(runtime.pointerAlignment) it.setSection("__DATA, __objc_const") @@ -223,7 +223,7 @@ private fun addModuleClassList(elements: List<ConstPointer>, name: String, section: String) { if (elements.isEmpty()) return - val global = llvm.staticData.placeGlobalArray( + val global = codegen.staticData.placeGlobalArray( name, llvm.int8PtrType, elements.map { it.bitcast(llvm.int8PtrType) } @@ -270,7 +270,7 @@ } class CStringLiteralsGenerator(val label: String, val section: String) { - fun generate(module: LLVMModuleRef, llvm: Llvm, value: String): ConstPointer { + fun generate(module: LLVMModuleRef, llvm: CodegenLlvmHelpers, value: String): ConstPointer { val bytes = value.toByteArray(Charsets.UTF_8).map { llvm.constInt8(it) } + llvm.constInt8(0) val initializer = ConstArray(llvm.int8Type, bytes) val llvmGlobal = LLVMAddGlobal(module, initializer.llvmType, label)!!
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/linkObjC.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/linkObjC.kt index 8274f17..43d9980 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/linkObjC.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objc/linkObjC.kt
@@ -7,7 +7,6 @@ import kotlinx.cinterop.* import llvm.* -import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.NativeGenerationState import org.jetbrains.kotlin.backend.konan.isFinalBinary import org.jetbrains.kotlin.backend.konan.llvm.* @@ -127,7 +126,7 @@ } } -private fun PatchBuilder.buildAndApply(llvmModule: LLVMModuleRef, llvm: Llvm) { +private fun PatchBuilder.buildAndApply(llvmModule: LLVMModuleRef, llvm: CodegenLlvmHelpers) { val nameToGlobalPatch = globalPatches.associateNonRepeatingBy { it.globalName } val sectionToValueToLiteralPatch = literalPatches.groupBy { it.generator.section } @@ -197,10 +196,10 @@ } private fun patchLiteral( - global: LLVMValueRef, - llvm: Llvm, - generator: ObjCDataGenerator.CStringLiteralsGenerator, - newValue: String + global: LLVMValueRef, + llvm: CodegenLlvmHelpers, + generator: ObjCDataGenerator.CStringLiteralsGenerator, + newValue: String ) { val module = LLVMGetGlobalParent(global)!! @@ -216,7 +215,7 @@ } } -private fun LLVMValueRef.isFirstCharPtr(llvm: Llvm, global: LLVMValueRef): Boolean = +private fun LLVMValueRef.isFirstCharPtr(llvm: CodegenLlvmHelpers, global: LLVMValueRef): Boolean = this.type == llvm.int8PtrType && LLVMIsConstant(this) != 0 && LLVMGetConstOpcode(this) == LLVMOpcode.LLVMGetElementPtr && LLVMGetNumOperands(this) == 3
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt index 7604a7d..afaf917 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt
@@ -148,7 +148,7 @@ */ internal data class BlockType(val numberOfParameters: Int, val returnsVoid: Boolean) -private fun BlockType.toBlockInvokeLlvmType(llvm: Llvm): LlvmFunctionSignature = +private fun BlockType.toBlockInvokeLlvmType(llvm: CodegenLlvmHelpers): LlvmFunctionSignature = LlvmFunctionSignature( LlvmRetType(if (returnsVoid) llvm.voidType else llvm.int8PtrType), (0..numberOfParameters).map { LlvmParamType(llvm.int8PtrType) }
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index a34c295..8045948 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt
@@ -43,7 +43,7 @@ import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors import org.jetbrains.kotlin.utils.DFS -internal fun TypeBridge.makeNothing(llvm: Llvm) = when (this) { +internal fun TypeBridge.makeNothing(llvm: CodegenLlvmHelpers) = when (this) { is ReferenceBridge, is BlockPointerBridge -> llvm.kNullInt8Ptr is ValueTypeBridge -> LLVMConstNull(this.objCValueType.toLlvmType(llvm))!! } @@ -1929,7 +1929,7 @@ return LlvmFunctionSignature(returnType, paramTypes, isVararg = false) } -private fun ObjCValueType.toLlvmType(llvm: Llvm): LLVMTypeRef = when (this) { +private fun ObjCValueType.toLlvmType(llvm: CodegenLlvmHelpers): LLVMTypeRef = when (this) { ObjCValueType.BOOL -> llvm.int8Type ObjCValueType.UNICHAR -> llvm.int16Type ObjCValueType.CHAR -> llvm.int8Type @@ -1945,7 +1945,7 @@ ObjCValueType.POINTER -> llvm.int8PtrType } -private fun MethodBridgeParameter.toLlvmParamType(llvm: Llvm): LlvmParamType = when (this) { +private fun MethodBridgeParameter.toLlvmParamType(llvm: CodegenLlvmHelpers): LlvmParamType = when (this) { is MethodBridgeValueParameter.Mapped -> this.bridge.toLlvmParamType(llvm) is MethodBridgeReceiver -> ReferenceBridge.toLlvmParamType(llvm) MethodBridgeSelector -> LlvmParamType(llvm.int8PtrType) @@ -1972,7 +1972,7 @@ } } -private fun TypeBridge.toLlvmParamType(llvm: Llvm): LlvmParamType = when (this) { +private fun TypeBridge.toLlvmParamType(llvm: CodegenLlvmHelpers): LlvmParamType = when (this) { is ReferenceBridge, is BlockPointerBridge -> LlvmParamType(llvm.int8PtrType) is ValueTypeBridge -> LlvmParamType(this.objCValueType.toLlvmType(llvm), this.objCValueType.defaultParameterAttributes) }
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/RemoveMultipleThreadDataLoads.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/RemoveMultipleThreadDataLoads.kt index e19287e..b6e575d 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/RemoveMultipleThreadDataLoads.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/RemoveMultipleThreadDataLoads.kt
@@ -6,8 +6,7 @@ package org.jetbrains.kotlin.backend.konan.optimizations import llvm.* -import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.NativeGenerationState +import org.jetbrains.kotlin.backend.konan.BitcodePostProcessingContext import org.jetbrains.kotlin.backend.konan.llvm.getBasicBlocks import org.jetbrains.kotlin.backend.konan.llvm.getFunctions import org.jetbrains.kotlin.backend.konan.llvm.getInstructions @@ -32,10 +31,10 @@ } } -internal fun removeMultipleThreadDataLoads(generationState: NativeGenerationState) { - val currentThreadTLV = generationState.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return +internal fun removeMultipleThreadDataLoads(context: BitcodePostProcessingContext) { + val currentThreadTLV = context.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return - getFunctions(generationState.llvm.module) + getFunctions(context.llvm.module) .filter { it.name?.startsWith("kfun:") == true } .filterNot { LLVMIsDeclaration(it) == 1 } .forEach { process(it, currentThreadTLV) }
diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 892c896..6f29399 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle
@@ -5600,6 +5600,19 @@ useGoldenData = true } +standaloneTest("split_compilation_pipeline") { + def dir = buildDir.absolutePath + source = "link/private_fake_overrides/override_main.kt" + doBeforeBuild { + konanc("$projectDir/link/private_fake_overrides/override_lib.kt -p library -target ${target.name} -o $dir/lib") + konanc("$projectDir/$source -target ${target.name} -o $dir/out -r $dir -l lib " + + "-Xtemporary-files-dir=$dir/tmp/split " + + "-Xwrite-dependencies-to=${dir}/split_compilation_pipeline.deps") + } + flags = ["-Xread-dependencies-from=${dir}/split_compilation_pipeline.deps", "-Xcompile-from-bitcode=${dir}/tmp/split/out.bc"] + useGoldenData = true +} + linkTest("private_fake_overrides_0") { source = "link/private_fake_overrides/inherit_main.kt" lib = "link/private_fake_overrides/inherit_lib.kt"