Introduce flag for bitcode to native compilation

This enables splitting the compilation pipeline into multiple
invocations of the compiler.
This commit is contained in:
Johan Bay
2023-02-18 08:22:26 +01:00
committed by Space Team
parent 7033d78641
commit 349a6b6e82
26 changed files with 302 additions and 122 deletions
@@ -421,6 +421,19 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xomit-framework-binary", description = "Omit binary when compiling framework")
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(
@@ -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()
@@ -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)
}
}
}
@@ -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.
*/
@@ -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")
}
}
@@ -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
@@ -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)
}
@@ -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
@@ -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,
@@ -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,
@@ -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)
}
}
}
@@ -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,
@@ -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)
}
@@ -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
}
}
@@ -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)
}
@@ -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) {
@@ -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++.
@@ -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,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)
}
}
@@ -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)!!
@@ -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
@@ -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) }
@@ -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)
}
@@ -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"