Introduce flag for bitcode to native compilation

This enables splitting the compilation pipeline into multiple
invocations of the compiler.
This commit is contained in:
Johan Bay
2023-02-18 08:22:26 +01:00
committed by Space Team
parent 7033d78641
commit 349a6b6e82
26 changed files with 302 additions and 122 deletions
@@ -421,6 +421,19 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xomit-framework-binary", description = "Omit binary when compiling framework") @Argument(value = "-Xomit-framework-binary", description = "Omit binary when compiling framework")
var omitFrameworkBinary: Boolean = false 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>") @Argument(value = "-Xsave-llvm-ir-directory", description = "Directory that should contain results of -Xsave-llvm-ir-after=<phase>")
var saveLlvmIrDirectory: String? = null var saveLlvmIrDirectory: String? = null
@@ -133,7 +133,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
private val K2NativeCompilerArguments.isUsefulWithoutFreeArgs: Boolean private val K2NativeCompilerArguments.isUsefulWithoutFreeArgs: Boolean
get() = listTargets || listPhases || checkDependencies || !includes.isNullOrEmpty() || get() = listTargets || listPhases || checkDependencies || !includes.isNullOrEmpty() ||
libraryToAddToCache != null || !exportedLibraries.isNullOrEmpty() libraryToAddToCache != null || !exportedLibraries.isNullOrEmpty() || !compileFromBitcode.isNullOrEmpty()
// It is executed before doExecute(). // It is executed before doExecute().
override fun setupPlatformSpecificArgumentsAndServices( override fun setupPlatformSpecificArgumentsAndServices(
@@ -167,7 +167,7 @@ private fun parseAndLinkBitcodeFile(generationState: NativeGenerationState, llvm
} }
} }
private fun embedAppleLinkerOptionsToBitcode(llvm: Llvm, config: KonanConfig) { private fun embedAppleLinkerOptionsToBitcode(llvm: CodegenLlvmHelpers, config: KonanConfig) {
fun findEmbeddableOptions(options: List<String>): List<List<String>> { fun findEmbeddableOptions(options: List<String>): List<List<String>> {
val result = mutableListOf<List<String>>() val result = mutableListOf<List<String>>()
val iterator = options.iterator() val iterator = options.iterator()
@@ -371,5 +371,49 @@ internal object DependenciesSerializer {
data class DependenciesTrackingResult( data class DependenciesTrackingResult(
val nativeDependenciesToLink: List<KonanLibrary>, val nativeDependenciesToLink: List<KonanLibrary>,
val allNativeDependencies: List<KonanLibrary>, val allNativeDependencies: List<KonanLibrary>,
val allCachedBitcodeDependencies: List<DependenciesTracker.ResolvedDependency> 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)
}
}
}
@@ -476,11 +476,6 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
} }
?: File(outputPath).name ?: 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. * Do not compile binary when compiling framework.
* This is useful when user care only about framework's interface. * This is useful when user care only about framework's interface.
@@ -494,6 +489,40 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
} }
} }
/**
* 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. * Directory to store LLVM IR from -Xsave-llvm-ir-after.
*/ */
@@ -161,6 +161,9 @@ class KonanConfigKeys {
val PARTIAL_LINKAGE: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("allows some symbols in klibs be missed") 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 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 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") val SAVE_LLVM_IR_DIRECTORY: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("directory to store LLVM IR from phases")
} }
} }
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.driver.BasicPhaseContext 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.BackendContextHolder
import org.jetbrains.kotlin.backend.konan.driver.utilities.LlvmIrHolder import org.jetbrains.kotlin.backend.konan.driver.utilities.LlvmIrHolder
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
@@ -16,7 +17,6 @@ import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
import org.jetbrains.kotlin.backend.konan.serialization.SerializedEagerInitializedFile import org.jetbrains.kotlin.backend.konan.serialization.SerializedEagerInitializedFile
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
import org.jetbrains.kotlin.ir.declarations.* 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) internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
@@ -38,6 +38,19 @@ internal class FileLowerState {
"$prefix${cStubCount++}" "$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( internal class NativeGenerationState(
config: KonanConfig, config: KonanConfig,
// TODO: Get rid of this property completely once transition to the dynamic driver is complete. // TODO: Get rid of this property completely once transition to the dynamic driver is complete.
@@ -48,7 +61,7 @@ internal class NativeGenerationState(
val llvmModuleSpecification: LlvmModuleSpecification, val llvmModuleSpecification: LlvmModuleSpecification,
val outputFiles: OutputFiles, val outputFiles: OutputFiles,
val llvmModuleName: String, val llvmModuleName: String,
) : BasicPhaseContext(config), BackendContextHolder<Context>, LlvmIrHolder { ) : BasicPhaseContext(config), BackendContextHolder<Context>, LlvmIrHolder, BitcodePostProcessingContext {
val outputFile = outputFiles.mainFileName val outputFile = outputFiles.mainFileName
val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>() val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>()
@@ -72,12 +85,12 @@ internal class NativeGenerationState(
val producedLlvmModuleContainsStdlib get() = llvmModuleSpecification.containsModule(context.stdlibModule) val producedLlvmModuleContainsStdlib get() = llvmModuleSpecification.containsModule(context.stdlibModule)
private val runtimeDelegate = lazy { Runtime(llvmContext, config.distribution.compilerInterface(config.target)) } 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) } private val debugInfoDelegate = lazy { DebugInfo(this) }
val llvmContext = LLVMContextCreate()!! override val llvmContext = LLVMContextCreate()!!
val runtime by runtimeDelegate val runtime by runtimeDelegate
val llvm by llvmDelegate override val llvm by llvmDelegate
val debugInfo by debugInfoDelegate val debugInfo by debugInfoDelegate
val cStubsManager = CStubsManager(config.target, this) val cStubsManager = CStubsManager(config.target, this)
lateinit var llvmDeclarations: LlvmDeclarations lateinit var llvmDeclarations: LlvmDeclarations
@@ -262,6 +262,9 @@ fun CompilerConfiguration.setupFromArguments(arguments: K2NativeCompilerArgument
arguments.testDumpOutputPath?.let { put(TEST_DUMP_OUTPUT_PATH, it) } arguments.testDumpOutputPath?.let { put(TEST_DUMP_OUTPUT_PATH, it) }
put(PARTIAL_LINKAGE, arguments.partialLinkage) put(PARTIAL_LINKAGE, arguments.partialLinkage)
put(OMIT_FRAMEWORK_BINARY, arguments.omitFrameworkBinary) 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) putIfNotNull(SAVE_LLVM_IR_DIRECTORY, arguments.saveLlvmIrDirectory)
} }
@@ -12,7 +12,7 @@ import llvm.LLVMStoreSizeOfType
import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.ir.* 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.computeFunctionName
import org.jetbrains.kotlin.backend.konan.llvm.toLLVMType import org.jetbrains.kotlin.backend.konan.llvm.toLLVMType
import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.llvm.localHash
@@ -263,7 +263,7 @@ internal class GlobalHierarchyAnalysis(val context: Context, val irModule: IrMod
} }
} }
internal fun IrField.requiredAlignment(llvm: Llvm): Int { internal fun IrField.requiredAlignment(llvm: CodegenLlvmHelpers): Int {
val llvmType = type.toLLVMType(llvm) val llvmType = type.toLLVMType(llvm)
val abiAlignment = if (llvmType == llvm.vector128Type) { 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 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 fun IrField.requiredAlignment(llvm: Llvm): Int {
internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) { 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 val isConst = correspondingPropertySymbol?.owner?.isConst ?: false
require(!isConst || initializer?.expression is IrConst<*>) { "A const val field ${render()} must have constant initializer" } require(!isConst || initializer?.expression is IrConst<*>) { "A const val field ${render()} must have constant initializer" }
return FieldInfo(name.asString(), type, isConst, symbol, requiredAlignment(llvm)) return FieldInfo(name.asString(), type, isConst, symbol, requiredAlignment(llvm))
@@ -435,7 +435,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
* All fields of the class instance. * All fields of the class instance.
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix. * 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 } val mappedField = fieldInfo.irField?.let { context.mapping.lateInitFieldToNullableField[it] ?: it }
if (mappedField == fieldInfo.irField) if (mappedField == fieldInfo.irField)
fieldInfo fieldInfo
@@ -445,7 +445,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
private var fields: List<FieldInfo>? = null private var fields: List<FieldInfo>? = null
private fun getFieldsInternal(llvm: Llvm): List<FieldInfo> { private fun getFieldsInternal(llvm: CodegenLlvmHelpers): List<FieldInfo> {
fields?.let { return it } fields?.let { return it }
val superClass = irClass.getSuperClassNotAny() val superClass = irClass.getSuperClassNotAny()
@@ -503,7 +503,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
/** /**
* Fields declared in the class. * Fields declared in the class.
*/ */
fun getDeclaredFields(llvm: Llvm): List<FieldInfo> { fun getDeclaredFields(llvm: CodegenLlvmHelpers): List<FieldInfo> {
val outerThisField = if (irClass.isInner) val outerThisField = if (irClass.isInner)
context.innerClassesSupport.getOuterThisField(irClass) context.innerClassesSupport.getOuterThisField(irClass)
else null else null
@@ -6,14 +6,20 @@
package org.jetbrains.kotlin.backend.konan.driver package org.jetbrains.kotlin.backend.konan.driver
import kotlinx.cinterop.usingJvmCInteropCallbacks 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.Context
import org.jetbrains.kotlin.backend.konan.KonanConfig
import org.jetbrains.kotlin.backend.konan.driver.phases.* import org.jetbrains.kotlin.backend.konan.driver.phases.*
import org.jetbrains.kotlin.backend.konan.getIncludedLibraryDescriptors 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.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.CommonConfigurationKeys 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.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator
@@ -26,7 +32,8 @@ internal class DynamicCompilerDriver : CompilerDriver() {
usingNativeMemoryAllocator { usingNativeMemoryAllocator {
usingJvmCInteropCallbacks { usingJvmCInteropCallbacks {
PhaseEngine.startTopLevel(config) { engine -> 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.PROGRAM -> produceBinary(engine, config, environment)
CompilerOutputKind.DYNAMIC -> produceCLibrary(engine, config, environment) CompilerOutputKind.DYNAMIC -> produceCLibrary(engine, config, environment)
CompilerOutputKind.STATIC -> produceCLibrary(engine, config, environment) CompilerOutputKind.STATIC -> produceCLibrary(engine, config, environment)
@@ -124,6 +131,22 @@ internal class DynamicCompilerDriver : CompilerDriver() {
engine.runBackend(backendContext, psiToIrOutput.irModule) 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( private fun createBackendContext(
config: KonanConfig, config: KonanConfig,
frontendOutput: FrontendPhaseOutput.Full, frontendOutput: FrontendPhaseOutput.Full,
@@ -118,6 +118,15 @@ internal class PhaseEngine<C : PhaseContext>(
} }
} }
/**
* 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( fun <Input, Output, P : AbstractNamedCompilerPhase<C, Input, Output>> runPhase(
phase: P, phase: P,
input: Input, input: Input,
@@ -108,7 +108,7 @@ internal val CoveragePhase = createSimpleNamedCompilerPhase<NativeGenerationStat
op = { context, _ -> runCoveragePass(context) } op = { context, _ -> runCoveragePass(context) }
) )
internal val RemoveRedundantSafepointsPhase = createSimpleNamedCompilerPhase<NativeGenerationState, Unit>( internal val RemoveRedundantSafepointsPhase = createSimpleNamedCompilerPhase<BitcodePostProcessingContext, Unit>(
name = "RemoveRedundantSafepoints", name = "RemoveRedundantSafepoints",
description = "Remove function prologue safepoints inlined to another function", description = "Remove function prologue safepoints inlined to another function",
postactions = getDefaultLlvmModuleActions(), postactions = getDefaultLlvmModuleActions(),
@@ -120,7 +120,7 @@ internal val RemoveRedundantSafepointsPhase = createSimpleNamedCompilerPhase<Nat
} }
) )
internal val OptimizeTLSDataLoadsPhase = createSimpleNamedCompilerPhase<NativeGenerationState, Unit>( internal val OptimizeTLSDataLoadsPhase = createSimpleNamedCompilerPhase<BitcodePostProcessingContext, Unit>(
name = "OptimizeTLSDataLoads", name = "OptimizeTLSDataLoads",
description = "Optimize multiple loads of thread data", description = "Optimize multiple loads of thread data",
postactions = getDefaultLlvmModuleActions(), postactions = getDefaultLlvmModuleActions(),
@@ -153,15 +153,11 @@ internal val PrintBitcodePhase = createSimpleNamedCompilerPhase<PhaseContext, LL
op = { _, llvmModule -> LLVMDumpModule(llvmModule) } op = { _, llvmModule -> LLVMDumpModule(llvmModule) }
) )
internal fun PhaseEngine<NativeGenerationState>.runBitcodePostProcessing() { internal fun <T : BitcodePostProcessingContext> PhaseEngine<T>.runBitcodePostProcessing() {
val checkExternalCalls = context.config.configuration.getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS)
if (checkExternalCalls) {
runPhase(CheckExternalCallsPhase)
}
val optimizationConfig = createLTOFinalPipelineConfig( val optimizationConfig = createLTOFinalPipelineConfig(
context, context,
context.llvm.targetTriple, context.llvm.targetTriple,
closedWorld = context.llvmModuleSpecification.isFinal, closedWorld = context.config.isFinalBinary,
timePasses = context.config.flexiblePhaseConfig.needProfiling, timePasses = context.config.flexiblePhaseConfig.needProfiling,
) )
useContext(OptimizationState(context.config, optimizationConfig)) { useContext(OptimizationState(context.config, optimizationConfig)) {
@@ -175,14 +171,14 @@ internal fun PhaseEngine<NativeGenerationState>.runBitcodePostProcessing() {
null -> {} 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) { if (context.config.memoryModel == MemoryModel.EXPERIMENTAL) {
runPhase(RemoveRedundantSafepointsPhase) runPhase(RemoveRedundantSafepointsPhase)
} }
if (context.config.optimizationsEnabled) { if (context.config.optimizationsEnabled) {
runPhase(OptimizeTLSDataLoadsPhase) runPhase(OptimizeTLSDataLoadsPhase)
} }
if (checkExternalCalls) {
runPhase(RewriteExternalCallsCheckerGlobals)
}
} }
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.konan.TempFiles
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.Family import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.library.impl.javaFile 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? { internal fun PhaseEngine<PhaseContext>.runFrontend(config: KonanConfig, environment: KotlinCoreEnvironment): FrontendPhaseOutput.Full? {
val frontendOutput = useContext(FrontendContextImpl(config)) { it.runPhase(FrontendPhase, environment) } val frontendOutput = useContext(FrontendContextImpl(config)) { it.runPhase(FrontendPhase, environment) }
@@ -80,7 +80,12 @@ internal fun <C : PhaseContext> PhaseEngine<C>.runBackend(backendContext: Contex
// TODO: Make this work if we first compile all the fragments and only after that run the link phases. // 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) generationStateEngine.compileModule(fragment.irModule, bitcodeFile, cExportFiles)
// Split here // 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) compileAndLink(moduleCompilationOutput, outputFiles.mainFileName, outputFiles, tempFiles, isCoverageEnabled = false)
} }
} finally { } finally {
@@ -90,6 +95,19 @@ internal fun <C : PhaseContext> PhaseEngine<C>.runBackend(backendContext: Contex
} }
} }
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 = private fun isReferencedByNativeRuntime(declarations: List<IrDeclaration>): Boolean =
declarations.any { declarations.any {
it.hasAnnotation(RuntimeNames.exportTypeInfoAnnotation) it.hasAnnotation(RuntimeNames.exportTypeInfoAnnotation)
@@ -159,7 +177,7 @@ private fun PhaseEngine<out Context>.splitIntoFragments(
} }
internal data class ModuleCompilationOutput( internal data class ModuleCompilationOutput(
val bitcodeFile: File, val bitcodeFile: java.io.File,
val dependenciesTrackingResult: DependenciesTrackingResult, val dependenciesTrackingResult: DependenciesTrackingResult,
) )
@@ -170,7 +188,7 @@ internal data class ModuleCompilationOutput(
* 4. Optimizes it. * 4. Optimizes it.
* 5. Serializes it to a bitcode file. * 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) { if (context.config.produce.isCache) {
runPhase(BuildAdditionalCacheInfoPhase, module) runPhase(BuildAdditionalCacheInfoPhase, module)
} }
@@ -178,13 +196,21 @@ internal fun PhaseEngine<NativeGenerationState>.compileModule(module: IrModuleFr
runPhase(EntryPointPhase, module) runPhase(EntryPointPhase, module)
} }
runBackendCodegen(module, cExportFiles) 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) { if (context.config.produce.isCache) {
runPhase(SaveAdditionalCacheInfoPhase) runPhase(SaveAdditionalCacheInfoPhase)
} }
runPhase(WriteBitcodeFilePhase, WriteBitcodeFileInput(context.llvm.module, bitcodeFile)) runPhase(WriteBitcodeFilePhase, WriteBitcodeFileInput(context.llvm.module, bitcodeFile))
} }
internal fun <C : PhaseContext> PhaseEngine<C>.compileAndLink( internal fun <C : PhaseContext> PhaseEngine<C>.compileAndLink(
moduleCompilationOutput: ModuleCompilationOutput, moduleCompilationOutput: ModuleCompilationOutput,
linkerOutputFile: String, linkerOutputFile: String,
@@ -1298,7 +1298,7 @@ internal abstract class FunctionGenerationContext(
assert(!irClass.isInterface) assert(!irClass.isInterface)
return if (irClass.isExternalObjCClass()) { return if (irClass.isExternalObjCClass()) {
llvm.dependenciesTracker.add(irClass) generationState.dependenciesTracker.add(irClass)
if (irClass.isObjCMetaClass()) { if (irClass.isObjCMetaClass()) {
val name = irClass.descriptor.getExternalObjCMetaClassBinaryName() val name = irClass.descriptor.getExternalObjCMetaClassBinaryName()
val objCClass = getObjCClass(name) val objCClass = getObjCClass(name)
@@ -1337,7 +1337,7 @@ internal abstract class FunctionGenerationContext(
private fun getObjCClass(binaryName: String) = load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm) private fun getObjCClass(binaryName: String) = load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm)
fun getObjCClassFromNativeRuntime(binaryName: String): LLVMValueRef { fun getObjCClassFromNativeRuntime(binaryName: String): LLVMValueRef {
llvm.dependenciesTracker.addNativeRuntime() generationState.dependenciesTracker.addNativeRuntime()
return getObjCClass(binaryName) return getObjCClass(binaryName)
} }
@@ -148,7 +148,7 @@ internal interface ContextUtils : RuntimeAware {
val llvmTargetData: LLVMTargetDataRef val llvmTargetData: LLVMTargetDataRef
get() = runtime.targetData get() = runtime.targetData
val llvm: Llvm val llvm: CodegenLlvmHelpers
get() = generationState.llvm get() = generationState.llvm
val staticData: KotlinStaticData val staticData: KotlinStaticData
@@ -256,42 +256,61 @@ internal class InitializersGenerationState {
} }
} }
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)!! 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)!! 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)!! 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)!! 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)!! 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)!! 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())!! 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)!! 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") @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 private val context = generationState.context
val llvmContext = generationState.llvmContext
private fun importFunction(name: String, otherModule: LLVMModuleRef): LlvmCallable { private fun importFunction(name: String, otherModule: LLVMModuleRef): LlvmCallable {
if (LLVMGetNamedFunction(module, name) != null) { if (LLVMGetNamedFunction(module, name) != null) {
@@ -378,11 +397,9 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu
override val runtime get() = generationState.runtime override val runtime get() = generationState.runtime
val targetTriple = runtime.target
init { init {
LLVMSetDataLayout(module, runtime.dataLayout) LLVMSetDataLayout(module, runtime.dataLayout)
LLVMSetTarget(module, targetTriple) LLVMSetTarget(module, runtime.target)
} }
private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule) private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule)
@@ -480,27 +497,14 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu
val initializersGenerationState = InitializersGenerationState() val initializersGenerationState = InitializersGenerationState()
val boxCacheGlobals = mutableMapOf<BoxCache, StaticData.Global>() 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 { private object lazyRtFunction {
operator fun provideDelegate( operator fun provideDelegate(
thisRef: Llvm, property: KProperty<*> thisRef: CodegenLlvmHelpers, property: KProperty<*>
) = object : ReadOnlyProperty<Llvm, LlvmCallable> { ) = object : ReadOnlyProperty<CodegenLlvmHelpers, LlvmCallable> {
val value: LlvmCallable by lazy { thisRef.importRtFunction(property.name) } 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
} }
} }
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.types.isUnit 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 null -> llvm.kObjHeaderPtr
PrimitiveBinaryType.BOOLEAN -> llvm.int1Type PrimitiveBinaryType.BOOLEAN -> llvm.int1Type
@@ -26,12 +26,12 @@ private fun PrimitiveBinaryType?.toLlvmType(llvm: Llvm) = when (this) {
PrimitiveBinaryType.POINTER -> llvm.int8PtrType 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) } llvm.runtime.calculatedLLVMTypes.getOrPut(this) { computePrimitiveBinaryTypeOrNull().toLlvmType(llvm) }
internal fun IrType.isVoidAsReturnType() = isUnit() || isNothing() internal fun IrType.isVoidAsReturnType() = isUnit() || isNothing()
internal fun IrType.getLLVMReturnType(llvm: Llvm) = when { internal fun IrType.getLLVMReturnType(llvm: CodegenLlvmHelpers) = when {
isVoidAsReturnType() -> llvm.voidType isVoidAsReturnType() -> llvm.voidType
else -> toLLVMType(llvm) else -> toLLVMType(llvm)
} }
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.Family import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.uniqueName import org.jetbrains.kotlin.library.uniqueName
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.classId
@@ -472,7 +471,7 @@ internal class CodeGeneratorVisitor(
private fun createInitBody(state: ScopeInitializersGenerationState): LLVMValueRef { private fun createInitBody(state: ScopeInitializersGenerationState): LLVMValueRef {
val initFunction = addLlvmFunctionWithDefaultAttributes( val initFunction = addLlvmFunctionWithDefaultAttributes(
context, generationState.context,
llvm.module, llvm.module,
"", "",
kInitFuncType kInitFuncType
@@ -551,7 +550,7 @@ internal class CodeGeneratorVisitor(
// Create static object of class InitNode. // Create static object of class InitNode.
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!! val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!!
// Create global variable with init record data. // 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 @@ internal class CodeGeneratorVisitor(
recordCoverage(body) recordCoverage(body)
if (declaration.isReifiedInline) { if (declaration.isReifiedInline) {
callDirect(context.ir.symbols.throwIllegalStateExceptionWithMessage.owner, callDirect(context.ir.symbols.throwIllegalStateExceptionWithMessage.owner,
listOf(llvm.staticData.kotlinStringLiteral( listOf(codegen.staticData.kotlinStringLiteral(
"unsupported call of reified inlined function `${declaration.fqNameForIrSerialization}`").llvm), "unsupported call of reified inlined function `${declaration.fqNameForIrSerialization}`").llvm),
Lifetime.IRRELEVANT, null) Lifetime.IRRELEVANT, null)
return@usingVariableScope return@usingVariableScope
@@ -1288,7 +1287,7 @@ internal class CodeGeneratorVisitor(
functionGenerationContext.positionAtEnd(whenEmittingContext.bbExit.value) functionGenerationContext.positionAtEnd(whenEmittingContext.bbExit.value)
return when { return when {
expression.type.isUnit() -> functionGenerationContext.theUnitInstanceRef.llvm expression.type.isUnit() -> codegen.theUnitInstanceRef.llvm
expression.type.isNothing() -> functionGenerationContext.kNothingFakeValue expression.type.isNothing() -> functionGenerationContext.kNothingFakeValue
whenEmittingContext.resultPhi.isInitialized() -> whenEmittingContext.resultPhi.value whenEmittingContext.resultPhi.isInitialized() -> whenEmittingContext.resultPhi.value
else -> LLVMGetUndef(whenEmittingContext.llvmType)!! else -> LLVMGetUndef(whenEmittingContext.llvmType)!!
@@ -1346,7 +1345,7 @@ internal class CodeGeneratorVisitor(
} }
assert(loop.type.isUnit()) assert(loop.type.isUnit())
return functionGenerationContext.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -1371,7 +1370,7 @@ internal class CodeGeneratorVisitor(
} }
assert(loop.type.isUnit()) assert(loop.type.isUnit())
return functionGenerationContext.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -1395,7 +1394,7 @@ internal class CodeGeneratorVisitor(
val variable = currentCodeContext.getDeclaredValue(value.symbol.owner) val variable = currentCodeContext.getDeclaredValue(value.symbol.owner)
functionGenerationContext.vars.store(result, variable) functionGenerationContext.vars.store(result, variable)
assert(value.type.isUnit()) assert(value.type.isUnit())
return functionGenerationContext.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -1465,7 +1464,7 @@ internal class CodeGeneratorVisitor(
IrTypeOperator.IMPLICIT_NOTNULL -> TODO(ir2string(value)) IrTypeOperator.IMPLICIT_NOTNULL -> TODO(ir2string(value))
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
evaluateExpression(value.argument) evaluateExpression(value.argument)
functionGenerationContext.theUnitInstanceRef.llvm codegen.theUnitInstanceRef.llvm
} }
IrTypeOperator.SAFE_CAST -> throw IllegalStateException("safe cast wasn't lowered") IrTypeOperator.SAFE_CAST -> throw IllegalStateException("safe cast wasn't lowered")
IrTypeOperator.INSTANCEOF -> evaluateInstanceOf(value) IrTypeOperator.INSTANCEOF -> evaluateInstanceOf(value)
@@ -1533,7 +1532,7 @@ internal class CodeGeneratorVisitor(
val dstFullClassName = dstClass.fqNameWhenAvailable?.toString() ?: dstClass.name.toString() val dstFullClassName = dstClass.fqNameWhenAvailable?.toString() ?: dstClass.name.toString()
callDirect( callDirect(
context.ir.symbols.throwTypeCastException.owner, context.ir.symbols.throwTypeCastException.owner,
listOf(srcArg, llvm.staticData.kotlinStringLiteral(dstFullClassName).llvm), listOf(srcArg, codegen.staticData.kotlinStringLiteral(dstFullClassName).llvm),
Lifetime.GLOBAL, Lifetime.GLOBAL,
null null
) )
@@ -1810,7 +1809,7 @@ internal class CodeGeneratorVisitor(
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun evaluateStringConst(value: IrConst<String>) = private fun evaluateStringConst(value: IrConst<String>) =
llvm.staticData.kotlinStringLiteral(value.value) codegen.staticData.kotlinStringLiteral(value.value)
private fun evaluateConst(value: IrConst<*>): ConstValue { private fun evaluateConst(value: IrConst<*>): ConstValue {
context.log{"evaluateConst : ${ir2string(value)}"} context.log{"evaluateConst : ${ir2string(value)}"}
@@ -1862,7 +1861,7 @@ internal class CodeGeneratorVisitor(
require(value.type.toLLVMType(llvm) == codegen.kObjHeaderPtr) { require(value.type.toLLVMType(llvm) == codegen.kObjHeaderPtr) {
"Can't wrap ${value.value.kind.asString} constant to type ${value.type.render()}" "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()!!, constructedType.getClass()!!,
evaluateConst(value.value) evaluateConst(value.value)
) )
@@ -1876,7 +1875,7 @@ internal class CodeGeneratorVisitor(
require(clazz.symbol == symbols.array || clazz.symbol in symbols.primitiveTypesToPrimitiveArrays.values) { require(clazz.symbol == symbols.array || clazz.symbol in symbols.primitiveTypesToPrimitiveArrays.values) {
"Statically initialized array should have array type" "Statically initialized array should have array type"
} }
llvm.staticData.createConstKotlinArray( codegen.staticData.createConstKotlinArray(
value.type.getClass()!!, value.type.getClass()!!,
value.elements.map { evaluateConstantValue(it) } value.elements.map { evaluateConstantValue(it) }
) )
@@ -1937,7 +1936,7 @@ internal class CodeGeneratorVisitor(
} }
require(value.type.toLLVMType(llvm) == codegen.kObjHeaderPtr) { "Constant object is not an object, but ${value.type.render()}" } require(value.type.toLLVMType(llvm) == codegen.kObjHeaderPtr) { "Constant object is not an object, but ${value.type.render()}" }
llvm.staticData.createConstKotlinObject( codegen.staticData.createConstKotlinObject(
constructedClass, constructedClass,
*fields.toTypedArray() *fields.toTypedArray()
) )
@@ -2717,7 +2716,7 @@ internal class CodeGeneratorVisitor(
if (args.isEmpty()) return if (args.isEmpty()) return
val argsCasted = args.map { constPointer(it).bitcast(llvm.int8PtrType) } 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) LLVMSetLinkage(llvmUsedGlobal.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata") LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata")
@@ -2802,7 +2801,7 @@ internal class CodeGeneratorVisitor(
fun addCtorFunction(ctorName: String) = fun addCtorFunction(ctorName: String) =
addLlvmFunctionWithDefaultAttributes( addLlvmFunctionWithDefaultAttributes(
context, generationState.context,
llvm.module, llvm.module,
ctorName, ctorName,
kVoidFuncType kVoidFuncType
@@ -2898,7 +2897,7 @@ internal class CodeGeneratorVisitor(
LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMPrivateLinkage) LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMPrivateLinkage)
// Append initializers of global variables in "llvm.global_ctors" array. // 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))) listOf(createGlobalCtor(globalCtorFunction)))
LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage) LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
if (context.config.produce == CompilerOutputKind.PROGRAM) { if (context.config.produce == CompilerOutputKind.PROGRAM) {
@@ -7,9 +7,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.cValuesOf import kotlinx.cinterop.cValuesOf
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState 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.declarations.IrClass
import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrConst
@@ -17,7 +15,7 @@ private fun ConstPointer.add(index: LLVMValueRef): ConstPointer {
return constPointer(LLVMConstGEP(llvm, cValuesOf(index), 1)!!) 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>() private val stringLiterals = mutableMapOf<String, ConstPointer>()
// Must match OBJECT_TAG_PERMANENT_CONTAINER in C++. // Must match OBJECT_TAG_PERMANENT_CONTAINER in C++.
@@ -23,7 +23,7 @@ internal val ConstValue.llvmType: LLVMTypeRef
get() = this.llvm.type get() = this.llvm.type
internal interface ConstPointer : ConstValue { 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 { internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
@@ -34,7 +34,7 @@ internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
override val llvm = value 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)!! override val llvm = LLVMConstInBoundsGEP(pointer.llvm, cValuesOf(llvm.int32(0), llvm.int32(index)), 2)!!
// TODO: squash multiple GEPs // TODO: squash multiple GEPs
} }
@@ -182,12 +182,12 @@ private fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef): LLVMValu
} }
internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, declaration: IrDeclaration) = 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.importObjCGlobal(name: String, type: LLVMTypeRef) = importGlobal(name, type)
internal fun ContextUtils.importNativeRuntimeGlobal(name: String, type: LLVMTypeRef) = 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) { private fun CodeGenerator.replaceExternalWeakOrCommonGlobal(name: String, value: ConstValue) {
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) { if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
@@ -10,7 +10,7 @@ import llvm.*
/** /**
* Provides utilities to create static data. * 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. * Represents the LLVM global variable.
@@ -52,6 +52,11 @@ internal open class StaticData(val module: LLVMModuleRef, private val llvm: Llvm
val llvmGlobal = LLVMGetNamedGlobal(staticData.module, name) ?: return null val llvmGlobal = LLVMGetNamedGlobal(staticData.module, name) ?: return null
return Global(llvmGlobal) 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) val type get() = getGlobalType(this.llvmGlobal)
@@ -150,4 +155,8 @@ internal open class StaticData(val module: LLVMModuleRef, private val llvm: Llvm
} }
internal fun cStringLiteral(value: String) = cStringLiterals.getOrPut(value) { placeCStringLiteral(value) } internal fun cStringLiteral(value: String) = cStringLiterals.getOrPut(value) { placeCStringLiteral(value) }
companion object {
fun getGlobal(module: LLVMModuleRef, name: String) = Global.get(module, name)
}
} }
@@ -116,7 +116,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
) )
val globalName = "\u0001l_OBJC_\$_INSTANCE_METHODS_$name" 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.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
it.setAlignment(runtime.pointerAlignment) it.setAlignment(runtime.pointerAlignment)
it.setSection("__DATA, __objc_const") it.setSection("__DATA, __objc_const")
@@ -165,7 +165,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
"\u0001l_OBJC_CLASS_RO_\$_" "\u0001l_OBJC_CLASS_RO_\$_"
} + name } + name
val roGlobal = llvm.staticData.placeGlobal(roLabel, roValue).also { val roGlobal = codegen.staticData.placeGlobal(roLabel, roValue).also {
it.setLinkage(LLVMLinkage.LLVMPrivateLinkage) it.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
it.setAlignment(runtime.pointerAlignment) it.setAlignment(runtime.pointerAlignment)
it.setSection("__DATA, __objc_const") it.setSection("__DATA, __objc_const")
@@ -223,7 +223,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
private fun addModuleClassList(elements: List<ConstPointer>, name: String, section: String) { private fun addModuleClassList(elements: List<ConstPointer>, name: String, section: String) {
if (elements.isEmpty()) return if (elements.isEmpty()) return
val global = llvm.staticData.placeGlobalArray( val global = codegen.staticData.placeGlobalArray(
name, name,
llvm.int8PtrType, llvm.int8PtrType,
elements.map { it.bitcast(llvm.int8PtrType) } elements.map { it.bitcast(llvm.int8PtrType) }
@@ -270,7 +270,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
} }
class CStringLiteralsGenerator(val label: String, val section: String) { 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 bytes = value.toByteArray(Charsets.UTF_8).map { llvm.constInt8(it) } + llvm.constInt8(0)
val initializer = ConstArray(llvm.int8Type, bytes) val initializer = ConstArray(llvm.int8Type, bytes)
val llvmGlobal = LLVMAddGlobal(module, initializer.llvmType, label)!! val llvmGlobal = LLVMAddGlobal(module, initializer.llvmType, label)!!
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.konan.llvm.objc
import kotlinx.cinterop.* import kotlinx.cinterop.*
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.isFinalBinary import org.jetbrains.kotlin.backend.konan.isFinalBinary
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
@@ -127,7 +126,7 @@ private fun PatchBuilder.addObjCPatches() {
} }
} }
private fun PatchBuilder.buildAndApply(llvmModule: LLVMModuleRef, llvm: Llvm) { private fun PatchBuilder.buildAndApply(llvmModule: LLVMModuleRef, llvm: CodegenLlvmHelpers) {
val nameToGlobalPatch = globalPatches.associateNonRepeatingBy { it.globalName } val nameToGlobalPatch = globalPatches.associateNonRepeatingBy { it.globalName }
val sectionToValueToLiteralPatch = literalPatches.groupBy { it.generator.section } val sectionToValueToLiteralPatch = literalPatches.groupBy { it.generator.section }
@@ -197,10 +196,10 @@ private fun <T, K> List<T>.associateNonRepeatingBy(keySelector: (T) -> K): Map<K
} }
private fun patchLiteral( private fun patchLiteral(
global: LLVMValueRef, global: LLVMValueRef,
llvm: Llvm, llvm: CodegenLlvmHelpers,
generator: ObjCDataGenerator.CStringLiteralsGenerator, generator: ObjCDataGenerator.CStringLiteralsGenerator,
newValue: String newValue: String
) { ) {
val module = LLVMGetGlobalParent(global)!! val module = LLVMGetGlobalParent(global)!!
@@ -216,7 +215,7 @@ private fun patchLiteral(
} }
} }
private fun LLVMValueRef.isFirstCharPtr(llvm: Llvm, global: LLVMValueRef): Boolean = private fun LLVMValueRef.isFirstCharPtr(llvm: CodegenLlvmHelpers, global: LLVMValueRef): Boolean =
this.type == llvm.int8PtrType && this.type == llvm.int8PtrType &&
LLVMIsConstant(this) != 0 && LLVMGetConstOpcode(this) == LLVMOpcode.LLVMGetElementPtr LLVMIsConstant(this) != 0 && LLVMGetConstOpcode(this) == LLVMOpcode.LLVMGetElementPtr
&& LLVMGetNumOperands(this) == 3 && LLVMGetNumOperands(this) == 3
@@ -148,7 +148,7 @@ private val BlockPointerBridge.blockType: BlockType
*/ */
internal data class BlockType(val numberOfParameters: Int, val returnsVoid: Boolean) 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( LlvmFunctionSignature(
LlvmRetType(if (returnsVoid) llvm.voidType else llvm.int8PtrType), LlvmRetType(if (returnsVoid) llvm.voidType else llvm.int8PtrType),
(0..numberOfParameters).map { LlvmParamType(llvm.int8PtrType) } (0..numberOfParameters).map { LlvmParamType(llvm.int8PtrType) }
@@ -43,7 +43,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors
import org.jetbrains.kotlin.utils.DFS 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 ReferenceBridge, is BlockPointerBridge -> llvm.kNullInt8Ptr
is ValueTypeBridge -> LLVMConstNull(this.objCValueType.toLlvmType(llvm))!! is ValueTypeBridge -> LLVMConstNull(this.objCValueType.toLlvmType(llvm))!!
} }
@@ -1929,7 +1929,7 @@ private fun objCFunctionType(generationState: NativeGenerationState, methodBridg
return LlvmFunctionSignature(returnType, paramTypes, isVararg = false) 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.BOOL -> llvm.int8Type
ObjCValueType.UNICHAR -> llvm.int16Type ObjCValueType.UNICHAR -> llvm.int16Type
ObjCValueType.CHAR -> llvm.int8Type ObjCValueType.CHAR -> llvm.int8Type
@@ -1945,7 +1945,7 @@ private fun ObjCValueType.toLlvmType(llvm: Llvm): LLVMTypeRef = when (this) {
ObjCValueType.POINTER -> llvm.int8PtrType 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 MethodBridgeValueParameter.Mapped -> this.bridge.toLlvmParamType(llvm)
is MethodBridgeReceiver -> ReferenceBridge.toLlvmParamType(llvm) is MethodBridgeReceiver -> ReferenceBridge.toLlvmParamType(llvm)
MethodBridgeSelector -> LlvmParamType(llvm.int8PtrType) MethodBridgeSelector -> LlvmParamType(llvm.int8PtrType)
@@ -1972,7 +1972,7 @@ private fun MethodBridge.ReturnValue.toLlvmRetType(
} }
} }
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 ReferenceBridge, is BlockPointerBridge -> LlvmParamType(llvm.int8PtrType)
is ValueTypeBridge -> LlvmParamType(this.objCValueType.toLlvmType(llvm), this.objCValueType.defaultParameterAttributes) is ValueTypeBridge -> LlvmParamType(this.objCValueType.toLlvmType(llvm), this.objCValueType.defaultParameterAttributes)
} }
@@ -6,8 +6,7 @@
package org.jetbrains.kotlin.backend.konan.optimizations package org.jetbrains.kotlin.backend.konan.optimizations
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.BitcodePostProcessingContext
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.llvm.getBasicBlocks import org.jetbrains.kotlin.backend.konan.llvm.getBasicBlocks
import org.jetbrains.kotlin.backend.konan.llvm.getFunctions import org.jetbrains.kotlin.backend.konan.llvm.getFunctions
import org.jetbrains.kotlin.backend.konan.llvm.getInstructions import org.jetbrains.kotlin.backend.konan.llvm.getInstructions
@@ -32,10 +31,10 @@ private fun process(function: LLVMValueRef, currentThreadTLV: LLVMValueRef) {
} }
} }
internal fun removeMultipleThreadDataLoads(generationState: NativeGenerationState) { internal fun removeMultipleThreadDataLoads(context: BitcodePostProcessingContext) {
val currentThreadTLV = generationState.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return val currentThreadTLV = context.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return
getFunctions(generationState.llvm.module) getFunctions(context.llvm.module)
.filter { it.name?.startsWith("kfun:") == true } .filter { it.name?.startsWith("kfun:") == true }
.filterNot { LLVMIsDeclaration(it) == 1 } .filterNot { LLVMIsDeclaration(it) == 1 }
.forEach { process(it, currentThreadTLV) } .forEach { process(it, currentThreadTLV) }
@@ -5581,6 +5581,19 @@ standaloneTest("fake_override_0") {
useGoldenData = true 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") { linkTest("private_fake_overrides_0") {
source = "link/private_fake_overrides/inherit_main.kt" source = "link/private_fake_overrides/inherit_main.kt"
lib = "link/private_fake_overrides/inherit_lib.kt" lib = "link/private_fake_overrides/inherit_lib.kt"