Introduce flag for bitcode to native compilation
This enables splitting the compilation pipeline into multiple invocations of the compiler.
This commit is contained in:
+13
@@ -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(
|
||||||
|
|||||||
+1
-1
@@ -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()
|
||||||
|
|||||||
+46
-2
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+34
-5
@@ -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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+3
@@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-5
@@ -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
|
||||||
|
|||||||
+3
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -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
|
||||||
|
|||||||
+26
-3
@@ -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,
|
||||||
|
|||||||
+9
@@ -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,
|
||||||
|
|||||||
+9
-13
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+31
-5
@@ -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,
|
||||||
|
|||||||
+2
-2
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-30
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-17
@@ -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) {
|
||||||
|
|||||||
+1
-3
@@ -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++.
|
||||||
|
|||||||
+4
-4
@@ -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
-1
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -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)!!
|
||||||
|
|||||||
+6
-7
@@ -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
|
||||||
|
|||||||
+1
-1
@@ -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) }
|
||||||
|
|||||||
+4
-4
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user