[K/N] Add runtime.bc to runtime LTO
Fixes KT-52799
This commit is contained in:
+58
-19
@@ -14,14 +14,16 @@ import org.jetbrains.kotlin.backend.common.phaser.BeforeOrAfter
|
||||
import org.jetbrains.kotlin.backend.common.serialization.KlibIrVersion
|
||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.linkObjC
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.patchObjCRuntimeModule
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.konan.CURRENT
|
||||
import org.jetbrains.kotlin.konan.CompilerVersion
|
||||
import org.jetbrains.kotlin.konan.file.isBitcode
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||
import org.jetbrains.kotlin.konan.library.impl.buildLibrary
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
/**
|
||||
* Supposed to be true for a single LLVM module within final binary.
|
||||
@@ -75,36 +77,73 @@ internal fun produceCStubs(context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun linkAllDependencies(context: Context, generatedBitcodeFiles: List<String>) {
|
||||
private val BaseKotlinLibrary.isStdlib: Boolean
|
||||
get() = uniqueName == KONAN_STDLIB_NAME
|
||||
|
||||
|
||||
private data class LlvmModules(
|
||||
val runtimeModules: List<LLVMModuleRef>,
|
||||
val additionalModules: List<LLVMModuleRef>
|
||||
)
|
||||
|
||||
/**
|
||||
* Deserialize, generate, patch all bitcode dependencies and classify them into two sets:
|
||||
* - Runtime modules. These may be used as an input for a separate LTO (e.g. for debug builds).
|
||||
* - Everything else.
|
||||
*/
|
||||
private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<String>): LlvmModules {
|
||||
val config = context.config
|
||||
|
||||
// TODO: Possibly slow, maybe to a separate phase?
|
||||
val runtimeModules = RuntimeLinkageStrategy.pick(context).run()
|
||||
val (bitcodePartOfStdlib, bitcodeLibraries) = context.llvm.bitcodeToLink
|
||||
.partition { it.isStdlib && context.producedLlvmModuleContainsStdlib }
|
||||
.toList()
|
||||
.map { libraries ->
|
||||
libraries.flatMap { it.bitcodePaths }.filter { it.isBitcode }
|
||||
}
|
||||
|
||||
val launcherNativeLibraries = config.launcherNativeLibraries
|
||||
val nativeLibraries = config.nativeLibraries + config.launcherNativeLibraries
|
||||
.takeIf { config.produce == CompilerOutputKind.PROGRAM }.orEmpty()
|
||||
|
||||
linkObjC(context)
|
||||
|
||||
val nativeLibraries = config.nativeLibraries + launcherNativeLibraries
|
||||
|
||||
val bitcodeLibraries = context.llvm.bitcodeToLink.map { it.bitcodePaths }.flatten().filter { it.isBitcode }
|
||||
val additionalBitcodeFilesToLink = context.llvm.additionalProducedBitcodeFiles
|
||||
val exceptionsSupportNativeLibrary = config.exceptionsSupportNativeLibrary
|
||||
val bitcodeFiles = (nativeLibraries + generatedBitcodeFiles + additionalBitcodeFilesToLink + bitcodeLibraries).toMutableSet()
|
||||
if (config.produce == CompilerOutputKind.DYNAMIC_CACHE)
|
||||
bitcodeFiles += exceptionsSupportNativeLibrary
|
||||
val exceptionsSupportNativeLibrary = listOf(config.exceptionsSupportNativeLibrary)
|
||||
.takeIf { config.produce == CompilerOutputKind.DYNAMIC_CACHE }.orEmpty()
|
||||
val additionalBitcodeFiles = nativeLibraries +
|
||||
generatedBitcodeFiles +
|
||||
additionalBitcodeFilesToLink +
|
||||
bitcodeLibraries +
|
||||
exceptionsSupportNativeLibrary
|
||||
|
||||
val runtimeNativeLibraries = context.config.runtimeNativeLibraries
|
||||
.takeIf { context.producedLlvmModuleContainsStdlib }.orEmpty()
|
||||
|
||||
|
||||
fun parseBitcodeFiles(files: List<String>): List<LLVMModuleRef> = files.map { bitcodeFile ->
|
||||
val parsedModule = parseBitcodeFile(bitcodeFile)
|
||||
if (!context.shouldUseDebugInfoFromNativeLibs()) {
|
||||
LLVMStripModuleDebugInfo(parsedModule)
|
||||
}
|
||||
parsedModule
|
||||
}
|
||||
|
||||
val runtimeModules = parseBitcodeFiles(runtimeNativeLibraries + bitcodePartOfStdlib)
|
||||
val additionalModules = parseBitcodeFiles(additionalBitcodeFiles)
|
||||
return LlvmModules(
|
||||
runtimeModules.ifNotEmpty { this + context.generateRuntimeConstantsModule() } ?: emptyList(),
|
||||
additionalModules + listOfNotNull(patchObjCRuntimeModule(context))
|
||||
)
|
||||
}
|
||||
|
||||
private fun linkAllDependencies(context: Context, generatedBitcodeFiles: List<String>) {
|
||||
val (runtimeModules, additionalModules) = collectLlvmModules(context, generatedBitcodeFiles)
|
||||
// TODO: Possibly slow, maybe to a separate phase?
|
||||
val optimizedRuntimeModules = RuntimeLinkageStrategy.pick(context, runtimeModules).run()
|
||||
|
||||
val llvmModule = context.llvmModule!!
|
||||
runtimeModules.forEach {
|
||||
(optimizedRuntimeModules + additionalModules).forEach {
|
||||
val failed = llvmLinkModules2(context, llvmModule, it)
|
||||
if (failed != 0) {
|
||||
error("Failed to link ${it.getName()}")
|
||||
}
|
||||
}
|
||||
bitcodeFiles.forEach {
|
||||
parseAndLinkBitcodeFile(context, llvmModule, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun insertAliasToEntryPoint(context: Context) {
|
||||
|
||||
+1
-20
@@ -61,32 +61,13 @@ internal sealed class RuntimeLinkageStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in cases when runtime is not linked directly, e.g. it is a part of stdlib cache.
|
||||
*/
|
||||
object None : RuntimeLinkageStrategy() {
|
||||
override fun run(): List<LLVMModuleRef> = emptyList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Choose runtime linkage strategy based on current compiler configuration and [BinaryOptions.linkRuntime].
|
||||
*/
|
||||
internal fun pick(context: Context): RuntimeLinkageStrategy {
|
||||
internal fun pick(context: Context, runtimeLlvmModules: List<LLVMModuleRef>): RuntimeLinkageStrategy {
|
||||
val binaryOption = context.config.configuration.get(BinaryOptions.linkRuntime)
|
||||
val runtimeNativeLibraries = context.config.runtimeNativeLibraries
|
||||
.takeIf { context.producedLlvmModuleContainsStdlib }
|
||||
val runtimeLlvmModules = runtimeNativeLibraries?.map {
|
||||
val parsedModule = parseBitcodeFile(it)
|
||||
if (!context.shouldUseDebugInfoFromNativeLibs()) {
|
||||
LLVMStripModuleDebugInfo(parsedModule)
|
||||
}
|
||||
parsedModule
|
||||
}?.let {
|
||||
it + context.generateRuntimeConstantsModule()
|
||||
}
|
||||
return when {
|
||||
runtimeLlvmModules == null -> return None
|
||||
binaryOption == RuntimeLinkageStrategyBinaryOption.Raw -> Raw(runtimeLlvmModules)
|
||||
binaryOption == RuntimeLinkageStrategyBinaryOption.Optimize -> LinkAndOptimize(context, runtimeLlvmModules)
|
||||
context.config.debug -> LinkAndOptimize(context, runtimeLlvmModules)
|
||||
|
||||
+3
-11
@@ -13,9 +13,9 @@ import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.NSNumberKind
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamer
|
||||
|
||||
internal fun linkObjC(context: Context) {
|
||||
internal fun patchObjCRuntimeModule(context: Context): LLVMModuleRef? {
|
||||
val config = context.config
|
||||
if (!(config.produce.isFinalBinary && config.target.family.isAppleFamily)) return
|
||||
if (!(config.produce.isFinalBinary && config.target.family.isAppleFamily)) return null
|
||||
|
||||
val patchBuilder = PatchBuilder(context)
|
||||
patchBuilder.addObjCPatches()
|
||||
@@ -24,15 +24,7 @@ internal fun linkObjC(context: Context) {
|
||||
val parsedModule = parseBitcodeFile(bitcodeFile)
|
||||
|
||||
patchBuilder.buildAndApply(parsedModule)
|
||||
|
||||
if (!context.shouldUseDebugInfoFromNativeLibs()) {
|
||||
LLVMStripModuleDebugInfo(parsedModule)
|
||||
}
|
||||
|
||||
val failed = llvmLinkModules2(context, context.llvmModule!!, parsedModule)
|
||||
if (failed != 0) {
|
||||
throw Error("failed to link $bitcodeFile")
|
||||
}
|
||||
return parsedModule
|
||||
}
|
||||
|
||||
private class PatchBuilder(val context: Context) {
|
||||
|
||||
Reference in New Issue
Block a user