[K/N] Add runtime.bc to runtime LTO

Fixes KT-52799
This commit is contained in:
Sergey Bogolepov
2022-06-16 12:27:59 +03:00
committed by Space
parent 872b5a6a33
commit 0dcf638519
3 changed files with 62 additions and 50 deletions
@@ -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.KlibIrVersion
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
import org.jetbrains.kotlin.backend.konan.llvm.* 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.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.konan.CURRENT import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.CompilerVersion import org.jetbrains.kotlin.konan.CompilerVersion
import org.jetbrains.kotlin.konan.file.isBitcode 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.library.impl.buildLibrary
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.library.* import org.jetbrains.kotlin.library.*
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
/** /**
* Supposed to be true for a single LLVM module within final binary. * 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 val config = context.config
// TODO: Possibly slow, maybe to a separate phase? val (bitcodePartOfStdlib, bitcodeLibraries) = context.llvm.bitcodeToLink
val runtimeModules = RuntimeLinkageStrategy.pick(context).run() .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() .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 additionalBitcodeFilesToLink = context.llvm.additionalProducedBitcodeFiles
val exceptionsSupportNativeLibrary = config.exceptionsSupportNativeLibrary val exceptionsSupportNativeLibrary = listOf(config.exceptionsSupportNativeLibrary)
val bitcodeFiles = (nativeLibraries + generatedBitcodeFiles + additionalBitcodeFilesToLink + bitcodeLibraries).toMutableSet() .takeIf { config.produce == CompilerOutputKind.DYNAMIC_CACHE }.orEmpty()
if (config.produce == CompilerOutputKind.DYNAMIC_CACHE) val additionalBitcodeFiles = nativeLibraries +
bitcodeFiles += exceptionsSupportNativeLibrary 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!! val llvmModule = context.llvmModule!!
runtimeModules.forEach { (optimizedRuntimeModules + additionalModules).forEach {
val failed = llvmLinkModules2(context, llvmModule, it) val failed = llvmLinkModules2(context, llvmModule, it)
if (failed != 0) { if (failed != 0) {
error("Failed to link ${it.getName()}") error("Failed to link ${it.getName()}")
} }
} }
bitcodeFiles.forEach {
parseAndLinkBitcodeFile(context, llvmModule, it)
}
} }
private fun insertAliasToEntryPoint(context: Context) { private fun insertAliasToEntryPoint(context: Context) {
@@ -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 { companion object {
/** /**
* Choose runtime linkage strategy based on current compiler configuration and [BinaryOptions.linkRuntime]. * 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 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 { return when {
runtimeLlvmModules == null -> return None
binaryOption == RuntimeLinkageStrategyBinaryOption.Raw -> Raw(runtimeLlvmModules) binaryOption == RuntimeLinkageStrategyBinaryOption.Raw -> Raw(runtimeLlvmModules)
binaryOption == RuntimeLinkageStrategyBinaryOption.Optimize -> LinkAndOptimize(context, runtimeLlvmModules) binaryOption == RuntimeLinkageStrategyBinaryOption.Optimize -> LinkAndOptimize(context, runtimeLlvmModules)
context.config.debug -> LinkAndOptimize(context, runtimeLlvmModules) context.config.debug -> LinkAndOptimize(context, runtimeLlvmModules)
@@ -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.NSNumberKind
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamer import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamer
internal fun linkObjC(context: Context) { internal fun patchObjCRuntimeModule(context: Context): LLVMModuleRef? {
val config = context.config 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) val patchBuilder = PatchBuilder(context)
patchBuilder.addObjCPatches() patchBuilder.addObjCPatches()
@@ -24,15 +24,7 @@ internal fun linkObjC(context: Context) {
val parsedModule = parseBitcodeFile(bitcodeFile) val parsedModule = parseBitcodeFile(bitcodeFile)
patchBuilder.buildAndApply(parsedModule) patchBuilder.buildAndApply(parsedModule)
return parsedModule
if (!context.shouldUseDebugInfoFromNativeLibs()) {
LLVMStripModuleDebugInfo(parsedModule)
}
val failed = llvmLinkModules2(context, context.llvmModule!!, parsedModule)
if (failed != 0) {
throw Error("failed to link $bitcodeFile")
}
} }
private class PatchBuilder(val context: Context) { private class PatchBuilder(val context: Context) {