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")
|
||||
var omitFrameworkBinary: Boolean = false
|
||||
|
||||
@Argument(value = "-Xcompile-from-bitcode", description = "Continue compilation from bitcode file", valueDescription = "<path>")
|
||||
var compileFromBitcode: String? = null
|
||||
|
||||
@Argument(
|
||||
value = "-Xread-dependencies-from",
|
||||
description = "Serialized dependencies to use for linking",
|
||||
valueDescription = "<path>"
|
||||
)
|
||||
var serializedDependencies: String? = null
|
||||
|
||||
@Argument(value = "-Xwrite-dependencies-to", description = "Path for writing backend dependencies")
|
||||
var saveDependenciesPath: String? = null
|
||||
|
||||
@Argument(value = "-Xsave-llvm-ir-directory", description = "Directory that should contain results of -Xsave-llvm-ir-after=<phase>")
|
||||
var saveLlvmIrDirectory: String? = null
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
|
||||
private val K2NativeCompilerArguments.isUsefulWithoutFreeArgs: Boolean
|
||||
get() = listTargets || listPhases || checkDependencies || !includes.isNullOrEmpty() ||
|
||||
libraryToAddToCache != null || !exportedLibraries.isNullOrEmpty()
|
||||
libraryToAddToCache != null || !exportedLibraries.isNullOrEmpty() || !compileFromBitcode.isNullOrEmpty()
|
||||
|
||||
// It is executed before doExecute().
|
||||
override fun setupPlatformSpecificArgumentsAndServices(
|
||||
|
||||
+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>> {
|
||||
val result = mutableListOf<List<String>>()
|
||||
val iterator = options.iterator()
|
||||
|
||||
+46
-2
@@ -371,5 +371,49 @@ internal object DependenciesSerializer {
|
||||
data class DependenciesTrackingResult(
|
||||
val nativeDependenciesToLink: 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
|
||||
|
||||
val infoArgsOnly = (configuration.kotlinSourceRoots.isEmpty()
|
||||
&& configuration[KonanConfigKeys.INCLUDED_LIBRARIES].isNullOrEmpty()
|
||||
&& configuration[KonanConfigKeys.EXPORTED_LIBRARIES].isNullOrEmpty()
|
||||
&& libraryToCache == null)
|
||||
|
||||
/**
|
||||
* Do not compile binary when compiling framework.
|
||||
* This is useful when user care only about framework's interface.
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
+3
@@ -161,6 +161,9 @@ class KonanConfigKeys {
|
||||
val PARTIAL_LINKAGE: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("allows some symbols in klibs be missed")
|
||||
val TEST_DUMP_OUTPUT_PATH: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("path to a file to dump the list of all available tests")
|
||||
val OMIT_FRAMEWORK_BINARY: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("do not generate binary in framework")
|
||||
val COMPILE_FROM_BITCODE: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("path to bitcode file to compile")
|
||||
val SERIALIZED_DEPENDENCIES: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("path to serialized dependencies for native linking")
|
||||
val SAVE_DEPENDENCIES_PATH: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("path to save serialized dependencies to")
|
||||
val SAVE_LLVM_IR_DIRECTORY: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("directory to store LLVM IR from phases")
|
||||
}
|
||||
}
|
||||
|
||||
+18
-5
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.driver.BasicPhaseContext
|
||||
import org.jetbrains.kotlin.backend.konan.driver.PhaseContext
|
||||
import org.jetbrains.kotlin.backend.konan.driver.utilities.BackendContextHolder
|
||||
import org.jetbrains.kotlin.backend.konan.driver.utilities.LlvmIrHolder
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
@@ -16,7 +17,6 @@ import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.SerializedEagerInitializedFile
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.konan.TempFiles
|
||||
|
||||
internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
|
||||
|
||||
@@ -38,6 +38,19 @@ internal class FileLowerState {
|
||||
"$prefix${cStubCount++}"
|
||||
}
|
||||
|
||||
internal interface BitcodePostProcessingContext : PhaseContext, LlvmIrHolder {
|
||||
val llvm: BasicLlvmHelpers
|
||||
val llvmContext: LLVMContextRef
|
||||
}
|
||||
|
||||
internal class BitcodePostProcessingContextImpl(
|
||||
config: KonanConfig,
|
||||
override val llvmModule: LLVMModuleRef,
|
||||
override val llvmContext: LLVMContextRef
|
||||
) : BitcodePostProcessingContext, BasicPhaseContext(config) {
|
||||
override val llvm: BasicLlvmHelpers = BasicLlvmHelpers(this, llvmModule)
|
||||
}
|
||||
|
||||
internal class NativeGenerationState(
|
||||
config: KonanConfig,
|
||||
// TODO: Get rid of this property completely once transition to the dynamic driver is complete.
|
||||
@@ -48,7 +61,7 @@ internal class NativeGenerationState(
|
||||
val llvmModuleSpecification: LlvmModuleSpecification,
|
||||
val outputFiles: OutputFiles,
|
||||
val llvmModuleName: String,
|
||||
) : BasicPhaseContext(config), BackendContextHolder<Context>, LlvmIrHolder {
|
||||
) : BasicPhaseContext(config), BackendContextHolder<Context>, LlvmIrHolder, BitcodePostProcessingContext {
|
||||
val outputFile = outputFiles.mainFileName
|
||||
|
||||
val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>()
|
||||
@@ -72,12 +85,12 @@ internal class NativeGenerationState(
|
||||
val producedLlvmModuleContainsStdlib get() = llvmModuleSpecification.containsModule(context.stdlibModule)
|
||||
|
||||
private val runtimeDelegate = lazy { Runtime(llvmContext, config.distribution.compilerInterface(config.target)) }
|
||||
private val llvmDelegate = lazy { Llvm(this, LLVMModuleCreateWithNameInContext(llvmModuleName, llvmContext)!!) }
|
||||
private val llvmDelegate = lazy { CodegenLlvmHelpers(this, LLVMModuleCreateWithNameInContext(llvmModuleName, llvmContext)!!) }
|
||||
private val debugInfoDelegate = lazy { DebugInfo(this) }
|
||||
|
||||
val llvmContext = LLVMContextCreate()!!
|
||||
override val llvmContext = LLVMContextCreate()!!
|
||||
val runtime by runtimeDelegate
|
||||
val llvm by llvmDelegate
|
||||
override val llvm by llvmDelegate
|
||||
val debugInfo by debugInfoDelegate
|
||||
val cStubsManager = CStubsManager(config.target, this)
|
||||
lateinit var llvmDeclarations: LlvmDeclarations
|
||||
|
||||
+3
@@ -262,6 +262,9 @@ fun CompilerConfiguration.setupFromArguments(arguments: K2NativeCompilerArgument
|
||||
arguments.testDumpOutputPath?.let { put(TEST_DUMP_OUTPUT_PATH, it) }
|
||||
put(PARTIAL_LINKAGE, arguments.partialLinkage)
|
||||
put(OMIT_FRAMEWORK_BINARY, arguments.omitFrameworkBinary)
|
||||
putIfNotNull(COMPILE_FROM_BITCODE, arguments.compileFromBitcode)
|
||||
putIfNotNull(SERIALIZED_DEPENDENCIES, arguments.serializedDependencies)
|
||||
putIfNotNull(SAVE_DEPENDENCIES_PATH, arguments.saveDependenciesPath)
|
||||
putIfNotNull(SAVE_LLVM_IR_DIRECTORY, arguments.saveLlvmIrDirectory)
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -12,7 +12,7 @@ import llvm.LLVMStoreSizeOfType
|
||||
import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.Llvm
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.CodegenLlvmHelpers
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.computeFunctionName
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.toLLVMType
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.localHash
|
||||
@@ -263,7 +263,7 @@ internal 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 abiAlignment = if (llvmType == llvm.vector128Type) {
|
||||
8 // over-aligned objects are not supported now, and this worked somehow, so let's keep it as it for now
|
||||
@@ -283,7 +283,7 @@ internal fun IrField.requiredAlignment(llvm: Llvm): Int {
|
||||
|
||||
|
||||
internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
|
||||
private fun IrField.toFieldInfo(llvm: Llvm): FieldInfo {
|
||||
private fun IrField.toFieldInfo(llvm: CodegenLlvmHelpers): FieldInfo {
|
||||
val isConst = correspondingPropertySymbol?.owner?.isConst ?: false
|
||||
require(!isConst || initializer?.expression is IrConst<*>) { "A const val field ${render()} must have constant initializer" }
|
||||
return FieldInfo(name.asString(), type, isConst, symbol, requiredAlignment(llvm))
|
||||
@@ -435,7 +435,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
|
||||
* All fields of the class instance.
|
||||
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix.
|
||||
*/
|
||||
fun getFields(llvm: Llvm): List<FieldInfo> = getFieldsInternal(llvm).map { fieldInfo ->
|
||||
fun getFields(llvm: CodegenLlvmHelpers): List<FieldInfo> = getFieldsInternal(llvm).map { fieldInfo ->
|
||||
val mappedField = fieldInfo.irField?.let { context.mapping.lateInitFieldToNullableField[it] ?: it }
|
||||
if (mappedField == fieldInfo.irField)
|
||||
fieldInfo
|
||||
@@ -445,7 +445,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
|
||||
|
||||
private var fields: List<FieldInfo>? = null
|
||||
|
||||
private fun getFieldsInternal(llvm: Llvm): List<FieldInfo> {
|
||||
private fun getFieldsInternal(llvm: CodegenLlvmHelpers): List<FieldInfo> {
|
||||
fields?.let { return it }
|
||||
|
||||
val superClass = irClass.getSuperClassNotAny()
|
||||
@@ -503,7 +503,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
|
||||
/**
|
||||
* Fields declared in the class.
|
||||
*/
|
||||
fun getDeclaredFields(llvm: Llvm): List<FieldInfo> {
|
||||
fun getDeclaredFields(llvm: CodegenLlvmHelpers): List<FieldInfo> {
|
||||
val outerThisField = if (irClass.isInner)
|
||||
context.innerClassesSupport.getOuterThisField(irClass)
|
||||
else null
|
||||
|
||||
+26
-3
@@ -6,14 +6,20 @@
|
||||
package org.jetbrains.kotlin.backend.konan.driver
|
||||
|
||||
import kotlinx.cinterop.usingJvmCInteropCallbacks
|
||||
import llvm.LLVMContextCreate
|
||||
import llvm.LLVMContextDispose
|
||||
import llvm.LLVMDisposeModule
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.BitcodePostProcessingContextImpl
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfig
|
||||
import org.jetbrains.kotlin.backend.konan.driver.phases.*
|
||||
import org.jetbrains.kotlin.backend.konan.getIncludedLibraryDescriptors
|
||||
import org.jetbrains.kotlin.backend.konan.isCache
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile
|
||||
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator
|
||||
|
||||
@@ -26,7 +32,8 @@ internal class DynamicCompilerDriver : CompilerDriver() {
|
||||
usingNativeMemoryAllocator {
|
||||
usingJvmCInteropCallbacks {
|
||||
PhaseEngine.startTopLevel(config) { engine ->
|
||||
when (config.produce) {
|
||||
if (!config.compileFromBitcode.isNullOrEmpty()) produceBinaryFromBitcode(engine, config, config.compileFromBitcode!!)
|
||||
else when (config.produce) {
|
||||
CompilerOutputKind.PROGRAM -> produceBinary(engine, config, environment)
|
||||
CompilerOutputKind.DYNAMIC -> produceCLibrary(engine, config, environment)
|
||||
CompilerOutputKind.STATIC -> produceCLibrary(engine, config, environment)
|
||||
@@ -124,6 +131,22 @@ internal class DynamicCompilerDriver : CompilerDriver() {
|
||||
engine.runBackend(backendContext, psiToIrOutput.irModule)
|
||||
}
|
||||
|
||||
private fun produceBinaryFromBitcode(engine: PhaseEngine<PhaseContext>, config: KonanConfig, bitcodeFilePath: String) {
|
||||
val llvmContext = LLVMContextCreate()!!
|
||||
val llvmModule = parseBitcodeFile(llvmContext, bitcodeFilePath)
|
||||
try {
|
||||
val context = BitcodePostProcessingContextImpl(config, llvmModule, llvmContext)
|
||||
val depsPath = config.readSerializedDependencies
|
||||
val dependencies = if (depsPath.isNullOrEmpty()) DependenciesTrackingResult(emptyList(), emptyList(), emptyList()).also {
|
||||
config.configuration.report(CompilerMessageSeverity.WARNING, "No backend dependencies provided.")
|
||||
} else DependenciesTrackingResult.deserialize(depsPath, File(depsPath).readStrings(), config)
|
||||
engine.runBitcodeBackend(context, dependencies)
|
||||
} finally {
|
||||
LLVMDisposeModule(llvmModule)
|
||||
LLVMContextDispose(llvmContext)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBackendContext(
|
||||
config: KonanConfig,
|
||||
frontendOutput: FrontendPhaseOutput.Full,
|
||||
|
||||
+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(
|
||||
phase: P,
|
||||
input: Input,
|
||||
|
||||
+9
-13
@@ -108,7 +108,7 @@ internal val CoveragePhase = createSimpleNamedCompilerPhase<NativeGenerationStat
|
||||
op = { context, _ -> runCoveragePass(context) }
|
||||
)
|
||||
|
||||
internal val RemoveRedundantSafepointsPhase = createSimpleNamedCompilerPhase<NativeGenerationState, Unit>(
|
||||
internal val RemoveRedundantSafepointsPhase = createSimpleNamedCompilerPhase<BitcodePostProcessingContext, Unit>(
|
||||
name = "RemoveRedundantSafepoints",
|
||||
description = "Remove function prologue safepoints inlined to another function",
|
||||
postactions = getDefaultLlvmModuleActions(),
|
||||
@@ -120,7 +120,7 @@ internal val RemoveRedundantSafepointsPhase = createSimpleNamedCompilerPhase<Nat
|
||||
}
|
||||
)
|
||||
|
||||
internal val OptimizeTLSDataLoadsPhase = createSimpleNamedCompilerPhase<NativeGenerationState, Unit>(
|
||||
internal val OptimizeTLSDataLoadsPhase = createSimpleNamedCompilerPhase<BitcodePostProcessingContext, Unit>(
|
||||
name = "OptimizeTLSDataLoads",
|
||||
description = "Optimize multiple loads of thread data",
|
||||
postactions = getDefaultLlvmModuleActions(),
|
||||
@@ -153,15 +153,11 @@ internal val PrintBitcodePhase = createSimpleNamedCompilerPhase<PhaseContext, LL
|
||||
op = { _, llvmModule -> LLVMDumpModule(llvmModule) }
|
||||
)
|
||||
|
||||
internal fun PhaseEngine<NativeGenerationState>.runBitcodePostProcessing() {
|
||||
val checkExternalCalls = context.config.configuration.getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS)
|
||||
if (checkExternalCalls) {
|
||||
runPhase(CheckExternalCallsPhase)
|
||||
}
|
||||
internal fun <T : BitcodePostProcessingContext> PhaseEngine<T>.runBitcodePostProcessing() {
|
||||
val optimizationConfig = createLTOFinalPipelineConfig(
|
||||
context,
|
||||
context.llvm.targetTriple,
|
||||
closedWorld = context.llvmModuleSpecification.isFinal,
|
||||
closedWorld = context.config.isFinalBinary,
|
||||
timePasses = context.config.flexiblePhaseConfig.needProfiling,
|
||||
)
|
||||
useContext(OptimizationState(context.config, optimizationConfig)) {
|
||||
@@ -175,14 +171,14 @@ internal fun PhaseEngine<NativeGenerationState>.runBitcodePostProcessing() {
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
runPhase(CoveragePhase)
|
||||
val checkExternalCalls = context.config.configuration.getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS)
|
||||
if (checkExternalCalls && context is NativeGenerationState) {
|
||||
newEngine(context) { it.runPhase(CoveragePhase) }
|
||||
}
|
||||
if (context.config.memoryModel == MemoryModel.EXPERIMENTAL) {
|
||||
runPhase(RemoveRedundantSafepointsPhase)
|
||||
}
|
||||
if (context.config.optimizationsEnabled) {
|
||||
runPhase(OptimizeTLSDataLoadsPhase)
|
||||
}
|
||||
if (checkExternalCalls) {
|
||||
runPhase(RewriteExternalCallsCheckerGlobals)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+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.Family
|
||||
import org.jetbrains.kotlin.library.impl.javaFile
|
||||
import java.io.File
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
|
||||
internal fun PhaseEngine<PhaseContext>.runFrontend(config: KonanConfig, environment: KotlinCoreEnvironment): FrontendPhaseOutput.Full? {
|
||||
val frontendOutput = useContext(FrontendContextImpl(config)) { it.runPhase(FrontendPhase, environment) }
|
||||
@@ -80,7 +80,12 @@ 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.
|
||||
generationStateEngine.compileModule(fragment.irModule, bitcodeFile, cExportFiles)
|
||||
// Split here
|
||||
val moduleCompilationOutput = ModuleCompilationOutput(bitcodeFile, generationState.dependenciesTracker.collectResult())
|
||||
val dependenciesTrackingResult = generationState.dependenciesTracker.collectResult()
|
||||
val depsFilePath = config.writeSerializedDependencies
|
||||
if (!depsFilePath.isNullOrEmpty()) {
|
||||
depsFilePath.File().writeLines(DependenciesTrackingResult.serialize(dependenciesTrackingResult))
|
||||
}
|
||||
val moduleCompilationOutput = ModuleCompilationOutput(bitcodeFile, dependenciesTrackingResult)
|
||||
compileAndLink(moduleCompilationOutput, outputFiles.mainFileName, outputFiles, tempFiles, isCoverageEnabled = false)
|
||||
}
|
||||
} finally {
|
||||
@@ -90,6 +95,19 @@ internal fun <C : PhaseContext> PhaseEngine<C>.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 =
|
||||
declarations.any {
|
||||
it.hasAnnotation(RuntimeNames.exportTypeInfoAnnotation)
|
||||
@@ -159,7 +177,7 @@ private fun PhaseEngine<out Context>.splitIntoFragments(
|
||||
}
|
||||
|
||||
internal data class ModuleCompilationOutput(
|
||||
val bitcodeFile: File,
|
||||
val bitcodeFile: java.io.File,
|
||||
val dependenciesTrackingResult: DependenciesTrackingResult,
|
||||
)
|
||||
|
||||
@@ -170,7 +188,7 @@ internal data class ModuleCompilationOutput(
|
||||
* 4. Optimizes it.
|
||||
* 5. Serializes it to a bitcode file.
|
||||
*/
|
||||
internal fun PhaseEngine<NativeGenerationState>.compileModule(module: IrModuleFragment, bitcodeFile: File, cExportFiles: CExportFiles?) {
|
||||
internal fun PhaseEngine<NativeGenerationState>.compileModule(module: IrModuleFragment, bitcodeFile: java.io.File, cExportFiles: CExportFiles?) {
|
||||
if (context.config.produce.isCache) {
|
||||
runPhase(BuildAdditionalCacheInfoPhase, module)
|
||||
}
|
||||
@@ -178,13 +196,21 @@ internal fun PhaseEngine<NativeGenerationState>.compileModule(module: IrModuleFr
|
||||
runPhase(EntryPointPhase, module)
|
||||
}
|
||||
runBackendCodegen(module, cExportFiles)
|
||||
runBitcodePostProcessing()
|
||||
val checkExternalCalls = context.config.configuration.getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS)
|
||||
if (checkExternalCalls) {
|
||||
runPhase(CheckExternalCallsPhase)
|
||||
}
|
||||
newEngine(context as BitcodePostProcessingContext) { it.runBitcodePostProcessing() }
|
||||
if (checkExternalCalls) {
|
||||
runPhase(RewriteExternalCallsCheckerGlobals)
|
||||
}
|
||||
if (context.config.produce.isCache) {
|
||||
runPhase(SaveAdditionalCacheInfoPhase)
|
||||
}
|
||||
runPhase(WriteBitcodeFilePhase, WriteBitcodeFileInput(context.llvm.module, bitcodeFile))
|
||||
}
|
||||
|
||||
|
||||
internal fun <C : PhaseContext> PhaseEngine<C>.compileAndLink(
|
||||
moduleCompilationOutput: ModuleCompilationOutput,
|
||||
linkerOutputFile: String,
|
||||
|
||||
+2
-2
@@ -1298,7 +1298,7 @@ internal abstract class FunctionGenerationContext(
|
||||
assert(!irClass.isInterface)
|
||||
|
||||
return if (irClass.isExternalObjCClass()) {
|
||||
llvm.dependenciesTracker.add(irClass)
|
||||
generationState.dependenciesTracker.add(irClass)
|
||||
if (irClass.isObjCMetaClass()) {
|
||||
val name = irClass.descriptor.getExternalObjCMetaClassBinaryName()
|
||||
val objCClass = getObjCClass(name)
|
||||
@@ -1337,7 +1337,7 @@ internal abstract class FunctionGenerationContext(
|
||||
private fun getObjCClass(binaryName: String) = load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm)
|
||||
|
||||
fun getObjCClassFromNativeRuntime(binaryName: String): LLVMValueRef {
|
||||
llvm.dependenciesTracker.addNativeRuntime()
|
||||
generationState.dependenciesTracker.addNativeRuntime()
|
||||
return getObjCClass(binaryName)
|
||||
}
|
||||
|
||||
|
||||
+34
-30
@@ -148,7 +148,7 @@ internal interface ContextUtils : RuntimeAware {
|
||||
val llvmTargetData: LLVMTargetDataRef
|
||||
get() = runtime.targetData
|
||||
|
||||
val llvm: Llvm
|
||||
val llvm: CodegenLlvmHelpers
|
||||
get() = generationState.llvm
|
||||
|
||||
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)!!
|
||||
}
|
||||
|
||||
internal class ConstInt8(llvm: Llvm, val value: Byte) : ConstValue {
|
||||
internal class ConstInt8(llvm: CodegenLlvmHelpers, val value: Byte) : ConstValue {
|
||||
override val llvm = LLVMConstInt(llvm.int8Type, value.toLong(), 1)!!
|
||||
}
|
||||
|
||||
internal class ConstInt16(llvm: Llvm, val value: Short) : ConstValue {
|
||||
internal class ConstInt16(llvm: CodegenLlvmHelpers, val value: Short) : ConstValue {
|
||||
override val llvm = LLVMConstInt(llvm.int16Type, value.toLong(), 1)!!
|
||||
}
|
||||
|
||||
internal class ConstChar16(llvm: Llvm, val value: Char) : ConstValue {
|
||||
internal class ConstChar16(llvm: CodegenLlvmHelpers, val value: Char) : ConstValue {
|
||||
override val llvm = LLVMConstInt(llvm.int16Type, value.code.toLong(), 1)!!
|
||||
}
|
||||
|
||||
internal class ConstInt32(llvm: Llvm, val value: Int) : ConstValue {
|
||||
internal class ConstInt32(llvm: CodegenLlvmHelpers, val value: Int) : ConstValue {
|
||||
override val llvm = LLVMConstInt(llvm.int32Type, value.toLong(), 1)!!
|
||||
}
|
||||
|
||||
internal class ConstInt64(llvm: Llvm, val value: Long) : ConstValue {
|
||||
internal class ConstInt64(llvm: CodegenLlvmHelpers, val value: Long) : ConstValue {
|
||||
override val llvm = LLVMConstInt(llvm.int64Type, value, 1)!!
|
||||
}
|
||||
|
||||
internal class ConstFloat32(llvm: Llvm, val value: Float) : ConstValue {
|
||||
internal class ConstFloat32(llvm: CodegenLlvmHelpers, val value: Float) : ConstValue {
|
||||
override val llvm = LLVMConstReal(llvm.floatType, value.toDouble())!!
|
||||
}
|
||||
|
||||
internal class ConstFloat64(llvm: Llvm, val value: Double) : ConstValue {
|
||||
internal class ConstFloat64(llvm: CodegenLlvmHelpers, val value: Double) : ConstValue {
|
||||
override val llvm = LLVMConstReal(llvm.doubleType, value)!!
|
||||
}
|
||||
|
||||
internal open class BasicLlvmHelpers(bitcodeContext: BitcodePostProcessingContext, val module: LLVMModuleRef) {
|
||||
|
||||
val llvmContext = bitcodeContext.llvmContext
|
||||
val targetTriple by lazy {
|
||||
LLVMGetTarget(module)!!.toKString()
|
||||
}
|
||||
|
||||
val runtimeAnnotationMap by lazy {
|
||||
StaticData.getGlobal(module, "llvm.global.annotations")
|
||||
?.getInitializer()
|
||||
?.let { getOperands(it) }
|
||||
?.groupBy(
|
||||
{ LLVMGetInitializer(LLVMGetOperand(LLVMGetOperand(it, 1), 0))?.getAsCString() ?: "" },
|
||||
{ LLVMGetOperand(LLVMGetOperand(it, 0), 0)!! }
|
||||
)
|
||||
?.filterKeys { it != "" }
|
||||
?: emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("FunctionName", "PropertyName", "PrivatePropertyName")
|
||||
internal class Llvm(private val generationState: NativeGenerationState, val module: LLVMModuleRef) : RuntimeAware {
|
||||
internal class CodegenLlvmHelpers(private val generationState: NativeGenerationState, module: LLVMModuleRef) : BasicLlvmHelpers(generationState, module), RuntimeAware {
|
||||
private val context = generationState.context
|
||||
val llvmContext = generationState.llvmContext
|
||||
|
||||
private fun importFunction(name: String, otherModule: LLVMModuleRef): LlvmCallable {
|
||||
if (LLVMGetNamedFunction(module, name) != null) {
|
||||
@@ -378,11 +397,9 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu
|
||||
|
||||
override val runtime get() = generationState.runtime
|
||||
|
||||
val targetTriple = runtime.target
|
||||
|
||||
init {
|
||||
LLVMSetDataLayout(module, runtime.dataLayout)
|
||||
LLVMSetTarget(module, targetTriple)
|
||||
LLVMSetTarget(module, runtime.target)
|
||||
}
|
||||
|
||||
private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule)
|
||||
@@ -480,27 +497,14 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu
|
||||
val initializersGenerationState = InitializersGenerationState()
|
||||
val boxCacheGlobals = mutableMapOf<BoxCache, StaticData.Global>()
|
||||
|
||||
val runtimeAnnotationMap by lazy {
|
||||
staticData.getGlobal("llvm.global.annotations")
|
||||
?.getInitializer()
|
||||
?.let { getOperands(it) }
|
||||
?.groupBy(
|
||||
{ LLVMGetInitializer(LLVMGetOperand(LLVMGetOperand(it, 1), 0))?.getAsCString() ?: "" },
|
||||
{ LLVMGetOperand(LLVMGetOperand(it, 0), 0)!! }
|
||||
)
|
||||
?.filterKeys { it != "" }
|
||||
?: emptyMap()
|
||||
}
|
||||
|
||||
|
||||
private object lazyRtFunction {
|
||||
operator fun provideDelegate(
|
||||
thisRef: Llvm, property: KProperty<*>
|
||||
) = object : ReadOnlyProperty<Llvm, LlvmCallable> {
|
||||
thisRef: CodegenLlvmHelpers, property: KProperty<*>
|
||||
) = object : ReadOnlyProperty<CodegenLlvmHelpers, LlvmCallable> {
|
||||
|
||||
val value: LlvmCallable by lazy { thisRef.importRtFunction(property.name) }
|
||||
|
||||
override fun getValue(thisRef: Llvm, property: KProperty<*>): LlvmCallable = value
|
||||
override fun getValue(thisRef: CodegenLlvmHelpers, property: KProperty<*>): LlvmCallable = value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+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.isUnit
|
||||
|
||||
private fun PrimitiveBinaryType?.toLlvmType(llvm: Llvm) = when (this) {
|
||||
private fun PrimitiveBinaryType?.toLlvmType(llvm: CodegenLlvmHelpers) = when (this) {
|
||||
null -> llvm.kObjHeaderPtr
|
||||
|
||||
PrimitiveBinaryType.BOOLEAN -> llvm.int1Type
|
||||
@@ -26,12 +26,12 @@ private fun PrimitiveBinaryType?.toLlvmType(llvm: Llvm) = when (this) {
|
||||
PrimitiveBinaryType.POINTER -> llvm.int8PtrType
|
||||
}
|
||||
|
||||
internal fun IrType.toLLVMType(llvm: Llvm): LLVMTypeRef =
|
||||
internal fun IrType.toLLVMType(llvm: CodegenLlvmHelpers): LLVMTypeRef =
|
||||
llvm.runtime.calculatedLLVMTypes.getOrPut(this) { computePrimitiveBinaryTypeOrNull().toLlvmType(llvm) }
|
||||
|
||||
internal fun IrType.isVoidAsReturnType() = isUnit() || isNothing()
|
||||
|
||||
internal fun IrType.getLLVMReturnType(llvm: Llvm) = when {
|
||||
internal fun IrType.getLLVMReturnType(llvm: CodegenLlvmHelpers) = when {
|
||||
isVoidAsReturnType() -> llvm.voidType
|
||||
else -> toLLVMType(llvm)
|
||||
}
|
||||
|
||||
+16
-17
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.uniqueName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
|
||||
@@ -472,7 +471,7 @@ internal class CodeGeneratorVisitor(
|
||||
|
||||
private fun createInitBody(state: ScopeInitializersGenerationState): LLVMValueRef {
|
||||
val initFunction = addLlvmFunctionWithDefaultAttributes(
|
||||
context,
|
||||
generationState.context,
|
||||
llvm.module,
|
||||
"",
|
||||
kInitFuncType
|
||||
@@ -551,7 +550,7 @@ internal class CodeGeneratorVisitor(
|
||||
// Create static object of class InitNode.
|
||||
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!!
|
||||
// Create global variable with init record data.
|
||||
return llvm.staticData.placeGlobal("init_node", constPointer(initNode), isExported = false).llvmGlobal
|
||||
return codegen.staticData.placeGlobal("init_node", constPointer(initNode), isExported = false).llvmGlobal
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -842,7 +841,7 @@ internal class CodeGeneratorVisitor(
|
||||
recordCoverage(body)
|
||||
if (declaration.isReifiedInline) {
|
||||
callDirect(context.ir.symbols.throwIllegalStateExceptionWithMessage.owner,
|
||||
listOf(llvm.staticData.kotlinStringLiteral(
|
||||
listOf(codegen.staticData.kotlinStringLiteral(
|
||||
"unsupported call of reified inlined function `${declaration.fqNameForIrSerialization}`").llvm),
|
||||
Lifetime.IRRELEVANT, null)
|
||||
return@usingVariableScope
|
||||
@@ -1288,7 +1287,7 @@ internal class CodeGeneratorVisitor(
|
||||
functionGenerationContext.positionAtEnd(whenEmittingContext.bbExit.value)
|
||||
|
||||
return when {
|
||||
expression.type.isUnit() -> functionGenerationContext.theUnitInstanceRef.llvm
|
||||
expression.type.isUnit() -> codegen.theUnitInstanceRef.llvm
|
||||
expression.type.isNothing() -> functionGenerationContext.kNothingFakeValue
|
||||
whenEmittingContext.resultPhi.isInitialized() -> whenEmittingContext.resultPhi.value
|
||||
else -> LLVMGetUndef(whenEmittingContext.llvmType)!!
|
||||
@@ -1346,7 +1345,7 @@ internal class CodeGeneratorVisitor(
|
||||
}
|
||||
|
||||
assert(loop.type.isUnit())
|
||||
return functionGenerationContext.theUnitInstanceRef.llvm
|
||||
return codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -1371,7 +1370,7 @@ internal class CodeGeneratorVisitor(
|
||||
}
|
||||
|
||||
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)
|
||||
functionGenerationContext.vars.store(result, variable)
|
||||
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_COERCION_TO_UNIT -> {
|
||||
evaluateExpression(value.argument)
|
||||
functionGenerationContext.theUnitInstanceRef.llvm
|
||||
codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
IrTypeOperator.SAFE_CAST -> throw IllegalStateException("safe cast wasn't lowered")
|
||||
IrTypeOperator.INSTANCEOF -> evaluateInstanceOf(value)
|
||||
@@ -1533,7 +1532,7 @@ internal class CodeGeneratorVisitor(
|
||||
val dstFullClassName = dstClass.fqNameWhenAvailable?.toString() ?: dstClass.name.toString()
|
||||
callDirect(
|
||||
context.ir.symbols.throwTypeCastException.owner,
|
||||
listOf(srcArg, llvm.staticData.kotlinStringLiteral(dstFullClassName).llvm),
|
||||
listOf(srcArg, codegen.staticData.kotlinStringLiteral(dstFullClassName).llvm),
|
||||
Lifetime.GLOBAL,
|
||||
null
|
||||
)
|
||||
@@ -1810,7 +1809,7 @@ internal class CodeGeneratorVisitor(
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
private fun evaluateStringConst(value: IrConst<String>) =
|
||||
llvm.staticData.kotlinStringLiteral(value.value)
|
||||
codegen.staticData.kotlinStringLiteral(value.value)
|
||||
|
||||
private fun evaluateConst(value: IrConst<*>): ConstValue {
|
||||
context.log{"evaluateConst : ${ir2string(value)}"}
|
||||
@@ -1862,7 +1861,7 @@ internal class CodeGeneratorVisitor(
|
||||
require(value.type.toLLVMType(llvm) == codegen.kObjHeaderPtr) {
|
||||
"Can't wrap ${value.value.kind.asString} constant to type ${value.type.render()}"
|
||||
}
|
||||
value.toBoxCacheValue(generationState) ?: llvm.staticData.createConstKotlinObject(
|
||||
value.toBoxCacheValue(generationState) ?: codegen.staticData.createConstKotlinObject(
|
||||
constructedType.getClass()!!,
|
||||
evaluateConst(value.value)
|
||||
)
|
||||
@@ -1876,7 +1875,7 @@ internal class CodeGeneratorVisitor(
|
||||
require(clazz.symbol == symbols.array || clazz.symbol in symbols.primitiveTypesToPrimitiveArrays.values) {
|
||||
"Statically initialized array should have array type"
|
||||
}
|
||||
llvm.staticData.createConstKotlinArray(
|
||||
codegen.staticData.createConstKotlinArray(
|
||||
value.type.getClass()!!,
|
||||
value.elements.map { evaluateConstantValue(it) }
|
||||
)
|
||||
@@ -1937,7 +1936,7 @@ internal class CodeGeneratorVisitor(
|
||||
}
|
||||
|
||||
require(value.type.toLLVMType(llvm) == codegen.kObjHeaderPtr) { "Constant object is not an object, but ${value.type.render()}" }
|
||||
llvm.staticData.createConstKotlinObject(
|
||||
codegen.staticData.createConstKotlinObject(
|
||||
constructedClass,
|
||||
*fields.toTypedArray()
|
||||
)
|
||||
@@ -2717,7 +2716,7 @@ internal class CodeGeneratorVisitor(
|
||||
if (args.isEmpty()) return
|
||||
|
||||
val argsCasted = args.map { constPointer(it).bitcast(llvm.int8PtrType) }
|
||||
val llvmUsedGlobal = llvm.staticData.placeGlobalArray(name, llvm.int8PtrType, argsCasted)
|
||||
val llvmUsedGlobal = codegen.staticData.placeGlobalArray(name, llvm.int8PtrType, argsCasted)
|
||||
|
||||
LLVMSetLinkage(llvmUsedGlobal.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
|
||||
LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata")
|
||||
@@ -2802,7 +2801,7 @@ internal class CodeGeneratorVisitor(
|
||||
|
||||
fun addCtorFunction(ctorName: String) =
|
||||
addLlvmFunctionWithDefaultAttributes(
|
||||
context,
|
||||
generationState.context,
|
||||
llvm.module,
|
||||
ctorName,
|
||||
kVoidFuncType
|
||||
@@ -2898,7 +2897,7 @@ internal class CodeGeneratorVisitor(
|
||||
LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMPrivateLinkage)
|
||||
|
||||
// Append initializers of global variables in "llvm.global_ctors" array.
|
||||
val globalCtors = llvm.staticData.placeGlobalArray("llvm.global_ctors", kCtorType,
|
||||
val globalCtors = codegen.staticData.placeGlobalArray("llvm.global_ctors", kCtorType,
|
||||
listOf(createGlobalCtor(globalCtorFunction)))
|
||||
LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
|
||||
if (context.config.produce == CompilerOutputKind.PROGRAM) {
|
||||
|
||||
+1
-3
@@ -7,9 +7,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
||||
|
||||
import kotlinx.cinterop.cValuesOf
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
|
||||
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
|
||||
@@ -17,7 +15,7 @@ private fun ConstPointer.add(index: LLVMValueRef): ConstPointer {
|
||||
return constPointer(LLVMConstGEP(llvm, cValuesOf(index), 1)!!)
|
||||
}
|
||||
|
||||
internal class KotlinStaticData(override val generationState: NativeGenerationState, override val llvm: Llvm, module: LLVMModuleRef) : ContextUtils, StaticData(module, llvm) {
|
||||
internal class KotlinStaticData(override val generationState: NativeGenerationState, override val llvm: CodegenLlvmHelpers, module: LLVMModuleRef) : ContextUtils, StaticData(module, llvm) {
|
||||
private val stringLiterals = mutableMapOf<String, ConstPointer>()
|
||||
|
||||
// Must match OBJECT_TAG_PERMANENT_CONTAINER in C++.
|
||||
|
||||
+4
-4
@@ -23,7 +23,7 @@ internal val ConstValue.llvmType: LLVMTypeRef
|
||||
get() = this.llvm.type
|
||||
|
||||
internal interface ConstPointer : ConstValue {
|
||||
fun getElementPtr(llvm: Llvm, index: Int): ConstPointer = ConstGetElementPtr(llvm, this, index)
|
||||
fun getElementPtr(llvm: CodegenLlvmHelpers, index: Int): ConstPointer = ConstGetElementPtr(llvm, this, index)
|
||||
}
|
||||
|
||||
internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
|
||||
@@ -34,7 +34,7 @@ internal fun constPointer(value: LLVMValueRef) = object : ConstPointer {
|
||||
override val llvm = value
|
||||
}
|
||||
|
||||
private class ConstGetElementPtr(llvm: Llvm, pointer: ConstPointer, index: Int) : ConstPointer {
|
||||
private class ConstGetElementPtr(llvm: CodegenLlvmHelpers, pointer: ConstPointer, index: Int) : ConstPointer {
|
||||
override val llvm = LLVMConstInBoundsGEP(pointer.llvm, cValuesOf(llvm.int32(0), llvm.int32(index)), 2)!!
|
||||
// TODO: squash multiple GEPs
|
||||
}
|
||||
@@ -182,12 +182,12 @@ private fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef): LLVMValu
|
||||
}
|
||||
|
||||
internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, declaration: IrDeclaration) =
|
||||
importGlobal(name, type).also { llvm.dependenciesTracker.add(declaration) }
|
||||
importGlobal(name, type).also { generationState.dependenciesTracker.add(declaration) }
|
||||
|
||||
internal fun ContextUtils.importObjCGlobal(name: String, type: LLVMTypeRef) = importGlobal(name, type)
|
||||
|
||||
internal fun ContextUtils.importNativeRuntimeGlobal(name: String, type: LLVMTypeRef) =
|
||||
importGlobal(name, type).also { llvm.dependenciesTracker.addNativeRuntime() }
|
||||
importGlobal(name, type).also { generationState.dependenciesTracker.addNativeRuntime() }
|
||||
|
||||
private fun CodeGenerator.replaceExternalWeakOrCommonGlobal(name: String, value: ConstValue) {
|
||||
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
||||
|
||||
+10
-1
@@ -10,7 +10,7 @@ import llvm.*
|
||||
/**
|
||||
* Provides utilities to create static data.
|
||||
*/
|
||||
internal open class StaticData(val module: LLVMModuleRef, private val llvm: Llvm) {
|
||||
internal open class StaticData(val module: LLVMModuleRef, private val llvm: CodegenLlvmHelpers) {
|
||||
|
||||
/**
|
||||
* Represents the LLVM global variable.
|
||||
@@ -52,6 +52,11 @@ internal open class StaticData(val module: LLVMModuleRef, private val llvm: Llvm
|
||||
val llvmGlobal = LLVMGetNamedGlobal(staticData.module, name) ?: return null
|
||||
return Global(llvmGlobal)
|
||||
}
|
||||
|
||||
fun get(module: LLVMModuleRef, name: String): Global? {
|
||||
val llvmGlobal = LLVMGetNamedGlobal(module, name) ?: return null
|
||||
return Global(llvmGlobal)
|
||||
}
|
||||
}
|
||||
|
||||
val type get() = getGlobalType(this.llvmGlobal)
|
||||
@@ -150,4 +155,8 @@ internal open class StaticData(val module: LLVMModuleRef, private val llvm: Llvm
|
||||
}
|
||||
|
||||
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 global = llvm.staticData.placeGlobal(globalName, methodList).also {
|
||||
val global = codegen.staticData.placeGlobal(globalName, methodList).also {
|
||||
it.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
|
||||
it.setAlignment(runtime.pointerAlignment)
|
||||
it.setSection("__DATA, __objc_const")
|
||||
@@ -165,7 +165,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
|
||||
"\u0001l_OBJC_CLASS_RO_\$_"
|
||||
} + name
|
||||
|
||||
val roGlobal = llvm.staticData.placeGlobal(roLabel, roValue).also {
|
||||
val roGlobal = codegen.staticData.placeGlobal(roLabel, roValue).also {
|
||||
it.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
|
||||
it.setAlignment(runtime.pointerAlignment)
|
||||
it.setSection("__DATA, __objc_const")
|
||||
@@ -223,7 +223,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
|
||||
private fun addModuleClassList(elements: List<ConstPointer>, name: String, section: String) {
|
||||
if (elements.isEmpty()) return
|
||||
|
||||
val global = llvm.staticData.placeGlobalArray(
|
||||
val global = codegen.staticData.placeGlobalArray(
|
||||
name,
|
||||
llvm.int8PtrType,
|
||||
elements.map { it.bitcast(llvm.int8PtrType) }
|
||||
@@ -270,7 +270,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
|
||||
}
|
||||
|
||||
class CStringLiteralsGenerator(val label: String, val section: String) {
|
||||
fun generate(module: LLVMModuleRef, llvm: Llvm, value: String): ConstPointer {
|
||||
fun generate(module: LLVMModuleRef, llvm: CodegenLlvmHelpers, value: String): ConstPointer {
|
||||
val bytes = value.toByteArray(Charsets.UTF_8).map { llvm.constInt8(it) } + llvm.constInt8(0)
|
||||
val initializer = ConstArray(llvm.int8Type, bytes)
|
||||
val llvmGlobal = LLVMAddGlobal(module, initializer.llvmType, label)!!
|
||||
|
||||
+6
-7
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.konan.llvm.objc
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
|
||||
import org.jetbrains.kotlin.backend.konan.isFinalBinary
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
@@ -127,7 +126,7 @@ private fun PatchBuilder.addObjCPatches() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun PatchBuilder.buildAndApply(llvmModule: LLVMModuleRef, llvm: Llvm) {
|
||||
private fun PatchBuilder.buildAndApply(llvmModule: LLVMModuleRef, llvm: CodegenLlvmHelpers) {
|
||||
val nameToGlobalPatch = globalPatches.associateNonRepeatingBy { it.globalName }
|
||||
|
||||
val sectionToValueToLiteralPatch = literalPatches.groupBy { it.generator.section }
|
||||
@@ -197,10 +196,10 @@ private fun <T, K> List<T>.associateNonRepeatingBy(keySelector: (T) -> K): Map<K
|
||||
}
|
||||
|
||||
private fun patchLiteral(
|
||||
global: LLVMValueRef,
|
||||
llvm: Llvm,
|
||||
generator: ObjCDataGenerator.CStringLiteralsGenerator,
|
||||
newValue: String
|
||||
global: LLVMValueRef,
|
||||
llvm: CodegenLlvmHelpers,
|
||||
generator: ObjCDataGenerator.CStringLiteralsGenerator,
|
||||
newValue: String
|
||||
) {
|
||||
val module = LLVMGetGlobalParent(global)!!
|
||||
|
||||
@@ -216,7 +215,7 @@ private fun patchLiteral(
|
||||
}
|
||||
}
|
||||
|
||||
private fun LLVMValueRef.isFirstCharPtr(llvm: Llvm, global: LLVMValueRef): Boolean =
|
||||
private fun LLVMValueRef.isFirstCharPtr(llvm: CodegenLlvmHelpers, global: LLVMValueRef): Boolean =
|
||||
this.type == llvm.int8PtrType &&
|
||||
LLVMIsConstant(this) != 0 && LLVMGetConstOpcode(this) == LLVMOpcode.LLVMGetElementPtr
|
||||
&& LLVMGetNumOperands(this) == 3
|
||||
|
||||
+1
-1
@@ -148,7 +148,7 @@ private val BlockPointerBridge.blockType: BlockType
|
||||
*/
|
||||
internal data class BlockType(val numberOfParameters: Int, val returnsVoid: Boolean)
|
||||
|
||||
private fun BlockType.toBlockInvokeLlvmType(llvm: Llvm): LlvmFunctionSignature =
|
||||
private fun BlockType.toBlockInvokeLlvmType(llvm: CodegenLlvmHelpers): LlvmFunctionSignature =
|
||||
LlvmFunctionSignature(
|
||||
LlvmRetType(if (returnsVoid) llvm.voidType else llvm.int8PtrType),
|
||||
(0..numberOfParameters).map { LlvmParamType(llvm.int8PtrType) }
|
||||
|
||||
+4
-4
@@ -43,7 +43,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
|
||||
internal fun TypeBridge.makeNothing(llvm: Llvm) = when (this) {
|
||||
internal fun TypeBridge.makeNothing(llvm: CodegenLlvmHelpers) = when (this) {
|
||||
is ReferenceBridge, is BlockPointerBridge -> llvm.kNullInt8Ptr
|
||||
is ValueTypeBridge -> LLVMConstNull(this.objCValueType.toLlvmType(llvm))!!
|
||||
}
|
||||
@@ -1929,7 +1929,7 @@ private fun objCFunctionType(generationState: NativeGenerationState, methodBridg
|
||||
return LlvmFunctionSignature(returnType, paramTypes, isVararg = false)
|
||||
}
|
||||
|
||||
private fun ObjCValueType.toLlvmType(llvm: Llvm): LLVMTypeRef = when (this) {
|
||||
private fun ObjCValueType.toLlvmType(llvm: CodegenLlvmHelpers): LLVMTypeRef = when (this) {
|
||||
ObjCValueType.BOOL -> llvm.int8Type
|
||||
ObjCValueType.UNICHAR -> llvm.int16Type
|
||||
ObjCValueType.CHAR -> llvm.int8Type
|
||||
@@ -1945,7 +1945,7 @@ private fun ObjCValueType.toLlvmType(llvm: Llvm): LLVMTypeRef = when (this) {
|
||||
ObjCValueType.POINTER -> llvm.int8PtrType
|
||||
}
|
||||
|
||||
private fun MethodBridgeParameter.toLlvmParamType(llvm: Llvm): LlvmParamType = when (this) {
|
||||
private fun MethodBridgeParameter.toLlvmParamType(llvm: CodegenLlvmHelpers): LlvmParamType = when (this) {
|
||||
is MethodBridgeValueParameter.Mapped -> this.bridge.toLlvmParamType(llvm)
|
||||
is MethodBridgeReceiver -> ReferenceBridge.toLlvmParamType(llvm)
|
||||
MethodBridgeSelector -> LlvmParamType(llvm.int8PtrType)
|
||||
@@ -1972,7 +1972,7 @@ private fun 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 ValueTypeBridge -> LlvmParamType(this.objCValueType.toLlvmType(llvm), this.objCValueType.defaultParameterAttributes)
|
||||
}
|
||||
|
||||
+4
-5
@@ -6,8 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.optimizations
|
||||
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
|
||||
import org.jetbrains.kotlin.backend.konan.BitcodePostProcessingContext
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.getBasicBlocks
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.getFunctions
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.getInstructions
|
||||
@@ -32,10 +31,10 @@ private fun process(function: LLVMValueRef, currentThreadTLV: LLVMValueRef) {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun removeMultipleThreadDataLoads(generationState: NativeGenerationState) {
|
||||
val currentThreadTLV = generationState.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return
|
||||
internal fun removeMultipleThreadDataLoads(context: BitcodePostProcessingContext) {
|
||||
val currentThreadTLV = context.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return
|
||||
|
||||
getFunctions(generationState.llvm.module)
|
||||
getFunctions(context.llvm.module)
|
||||
.filter { it.name?.startsWith("kfun:") == true }
|
||||
.filterNot { LLVMIsDeclaration(it) == 1 }
|
||||
.forEach { process(it, currentThreadTLV) }
|
||||
|
||||
@@ -5581,6 +5581,19 @@ standaloneTest("fake_override_0") {
|
||||
useGoldenData = true
|
||||
}
|
||||
|
||||
standaloneTest("split_compilation_pipeline") {
|
||||
def dir = buildDir.absolutePath
|
||||
source = "link/private_fake_overrides/override_main.kt"
|
||||
doBeforeBuild {
|
||||
konanc("$projectDir/link/private_fake_overrides/override_lib.kt -p library -target ${target.name} -o $dir/lib")
|
||||
konanc("$projectDir/$source -target ${target.name} -o $dir/out -r $dir -l lib " +
|
||||
"-Xtemporary-files-dir=$dir/tmp/split " +
|
||||
"-Xwrite-dependencies-to=${dir}/split_compilation_pipeline.deps")
|
||||
}
|
||||
flags = ["-Xread-dependencies-from=${dir}/split_compilation_pipeline.deps", "-Xcompile-from-bitcode=${dir}/tmp/split/out.bc"]
|
||||
useGoldenData = true
|
||||
}
|
||||
|
||||
linkTest("private_fake_overrides_0") {
|
||||
source = "link/private_fake_overrides/inherit_main.kt"
|
||||
lib = "link/private_fake_overrides/inherit_lib.kt"
|
||||
|
||||
Reference in New Issue
Block a user