diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 9b8c301f9f3..13fd08daf7a 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -171,7 +171,6 @@ class K2Native : CLICompiler() { put(VERBOSE_PHASES, arguments.verbosePhases.toNonNullList()) put(LIST_PHASES, arguments.listPhases) - put(TIME_PHASES, arguments.timePhases) put(COMPATIBLE_COMPILER_VERSIONS, arguments.compatibleCompilerVersions.toNonNullList()) diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index ebfe3cbf172..03231e4783c 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -153,9 +153,6 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { @Argument(value = "-Xtemporary-files-dir", deprecatedName = "--temporary_files_dir", valueDescription = "", description = "Save temporary files to the given directory") var temporaryFilesDir: String? = null - @Argument(value = "-Xtime", deprecatedName = "--time", description = "Report execution time for compiler phases") - var timePhases: Boolean = false - @Argument(value = "-Xverify-bitcode", deprecatedName = "--verify_bitcode", description = "Verify llvm bitcode after each method") var verifyBitCode: Boolean = false diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeCompiler.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeCompiler.kt new file mode 100644 index 00000000000..7eaaf2f34f6 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeCompiler.kt @@ -0,0 +1,179 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package org.jetbrains.kotlin.backend.konan + +import llvm.* +import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile +import org.jetbrains.kotlin.konan.exec.Command +import org.jetbrains.kotlin.konan.target.* + +typealias BitcodeFile = String +typealias ObjectFile = String +typealias ExecutableFile = String + +private fun mangleSymbol(target: KonanTarget,symbol: String) = + if (target.family == Family.IOS || target.family == Family.OSX) { + "_$symbol" + } else { + symbol + } + +internal class BitcodeCompiler(val context: Context) { + + private val target = context.config.target + private val platform = context.config.platform + private val optimize = context.shouldOptimize() + private val debug = context.config.debug + + private fun MutableList.addNonEmpty(elements: List) { + addAll(elements.filter { !it.isEmpty() }) + } + + private val exportedSymbols = context.coverage.addExportedSymbols() + + private fun runTool(vararg command: String) = + Command(*command) + .logWith(context::log) + .execute() + + private fun temporary(name: String, suffix: String): String = + context.config.tempFiles.create(name, suffix).absolutePath + + private fun targetTool(tool: String, vararg arg: String) { + val absoluteToolName = if (platform.configurables is AppleConfigurables) { + "${platform.absoluteTargetToolchain}/usr/bin/$tool" + } else { + "${platform.absoluteTargetToolchain}/bin/$tool" + } + runTool(absoluteToolName, *arg) + } + + private fun hostLlvmTool(tool: String, vararg arg: String) { + val absoluteToolName = "${platform.absoluteLlvmHome}/bin/$tool" + runTool(absoluteToolName, *arg) + } + + private fun llvmLto(configurables: LlvmLtoFlags, file: BitcodeFile): ObjectFile { + val combined = temporary("combined", ".o") + val arguments = mutableListOf().apply { + addNonEmpty(configurables.llvmLtoFlags) + addNonEmpty(llvmProfilingFlags()) + when { + optimize -> addNonEmpty(configurables.llvmLtoOptFlags) + debug -> addNonEmpty(platform.llvmDebugOptFlags) + else -> addNonEmpty(configurables.llvmLtoNooptFlags) + } + addNonEmpty(configurables.llvmLtoDynamicFlags) + add(file) + // Prevent symbols from being deleted by DCE. + addNonEmpty(exportedSymbols.map { "-exported-symbol=${mangleSymbol(target, it)}"} ) + } + hostLlvmTool("llvm-lto", "-o", combined, *arguments.toTypedArray()) + return combined + } + + private fun opt(optFlags: OptFlags, bitcodeFile: BitcodeFile): BitcodeFile { + val flags = (optFlags.optFlags + when { + optimize -> optFlags.optOptFlags + debug -> optFlags.optDebugFlags + else -> optFlags.optNooptFlags + } + llvmProfilingFlags()).toTypedArray() + val optimizedBc = temporary("opt_output", ".bc") + hostLlvmTool("opt", bitcodeFile, "-o", optimizedBc, *flags) + + if (shouldRunLateBitcodePasses(context)) { + val module = parseBitcodeFile(optimizedBc) + runLateBitcodePasses(context, module) + LLVMWriteBitcodeToFile(module, optimizedBc) + } + + return optimizedBc + } + + private fun llc(llcFlags: LlcFlags, bitcodeFile: BitcodeFile): ObjectFile { + val flags = (llcFlags.llcFlags + when { + optimize -> llcFlags.llcOptFlags + debug -> llcFlags.llcDebugFlags + else -> llcFlags.llcNooptFlags + } + llvmProfilingFlags()).toTypedArray() + val combinedO = temporary("llc_output", ".o") + hostLlvmTool("llc", bitcodeFile, "-o", combinedO, *flags, "-filetype=obj") + return combinedO + } + + private fun bitcodeToWasm(configurables: WasmConfigurables, file: BitcodeFile): String { + val optimizedBc = opt(configurables, file) + val compiled = llc(configurables, optimizedBc) + + // TODO: should be moved to linker. + val linkedWasm = temporary("linked", ".wasm") + hostLlvmTool("wasm-ld", compiled, "-o", linkedWasm, *configurables.lldFlags.toTypedArray()) + + return linkedWasm + } + + private fun optAndLlc(configurables: ZephyrConfigurables, file: BitcodeFile): String { + val optimizedBc = temporary("optimized", ".bc") + val optFlags = llvmProfilingFlags() + listOf("-O3", "-internalize", "-globaldce") + hostLlvmTool("opt", file, "-o=$optimizedBc", *optFlags.toTypedArray()) + + val combinedO = temporary("combined", ".o") + val llcFlags = llvmProfilingFlags() + listOf("-function-sections", "-data-sections") + hostLlvmTool("llc", optimizedBc, "-filetype=obj", "-o", combinedO, *llcFlags.toTypedArray()) + + return combinedO + } + + private fun clang(configurables: AppleConfigurables, file: BitcodeFile): ObjectFile { + val objectFile = temporary("result", ".o") + + val profilingFlags = llvmProfilingFlags().map { listOf("-mllvm", it) }.flatten() + + val flags = mutableListOf().apply { + addNonEmpty(configurables.clangFlags) + addNonEmpty(listOf("-triple", context.llvm.targetTriple)) + addNonEmpty(when { + optimize -> configurables.clangOptFlags + debug -> configurables.clangDebugFlags + else -> configurables.clangNooptFlags + }) + addNonEmpty(BitcodeEmbedding.getClangOptions(context.config)) + if (determineLinkerOutput(context) == LinkerOutputKind.DYNAMIC_LIBRARY) { + addNonEmpty(configurables.clangDynamicFlags) + } + addNonEmpty(profilingFlags) + } + targetTool("clang++", *flags.toTypedArray(), file, "-o", objectFile) + return objectFile + } + + // llvm-lto, opt and llc share same profiling flags, so we can + // reuse this function. + private fun llvmProfilingFlags(): List { + val flags = mutableListOf() + if (context.shouldProfilePhases()) { + flags += "-time-passes" + } + if (context.inVerbosePhase) { + flags += "-debug-pass=Structure" + } + return flags + } + + fun makeObjectFiles(bitcodeFile: BitcodeFile): List = + listOf(when (val configurables = platform.configurables) { + is AppleConfigurables -> + clang(configurables, bitcodeFile) + is WasmConfigurables -> + bitcodeToWasm(configurables, bitcodeFile) + is ZephyrConfigurables -> + optAndLlc(configurables, bitcodeFile) + is LlvmLtoFlags -> + llvmLto(configurables, bitcodeFile) + else -> + error("Unsupported configurables kind: ${configurables::class.simpleName}!") + }) +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeEmbedding.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeEmbedding.kt index 87e37addc89..2c027216f10 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeEmbedding.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeEmbedding.kt @@ -16,6 +16,12 @@ object BitcodeEmbedding { Mode.FULL -> listOf("-bitcode_bundle") } + internal fun getClangOptions(config: KonanConfig): List = when (config.bitcodeEmbeddingMode) { + BitcodeEmbedding.Mode.NONE -> listOf("-fembed-bitcode=off") + BitcodeEmbedding.Mode.MARKER -> listOf("-fembed-bitcode=marker") + BitcodeEmbedding.Mode.FULL -> listOf("-fembed-bitcode=all") + } + private val KonanConfig.bitcodeEmbeddingMode get() = configuration.get(KonanConfigKeys.BITCODE_EMBEDDING_MODE)!!.also { require(it == Mode.NONE || this.produce == CompilerOutputKind.FRAMEWORK) { "${it.name.toLowerCase()} bitcode embedding mode is not supported when producing ${this.produce.name.toLowerCase()}" diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt index 8730b7e7fe6..5dcad370474 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt @@ -4,16 +4,19 @@ */ package org.jetbrains.kotlin.backend.konan -import llvm.* +import llvm.LLVMLinkModules2 +import llvm.LLVMModuleRef +import llvm.LLVMWriteBitcodeToFile import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary +import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.Llvm -import org.jetbrains.kotlin.backend.konan.llvm.embedLlvmLinkOptions -import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile import org.jetbrains.kotlin.konan.CURRENT import org.jetbrains.kotlin.konan.KonanAbiVersion import org.jetbrains.kotlin.konan.KonanVersion +import org.jetbrains.kotlin.konan.file.isBitcode import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning import org.jetbrains.kotlin.konan.target.CompilerOutputKind +import org.jetbrains.kotlin.konan.target.Family val CompilerOutputKind.isNativeBinary: Boolean get() = when (this) { CompilerOutputKind.PROGRAM, CompilerOutputKind.DYNAMIC, @@ -28,20 +31,30 @@ internal fun produceCStubs(context: Context) { } } -private fun shouldRunBitcodePasses(context: Context): Boolean = - context.coverage.enabled +private fun linkAllDependecies(context: Context, generatedBitcodeFiles: List) { + + val nativeLibraries = context.config.nativeLibraries + context.config.defaultNativeLibraries + val bitcodeLibraries = context.llvm.bitcodeToLink.map { it.bitcodePaths }.flatten().filter { it.isBitcode } + val additionalBitcodeFilesToLink = context.llvm.additionalProducedBitcodeFiles + val bitcodeFiles = (nativeLibraries + generatedBitcodeFiles + additionalBitcodeFilesToLink + bitcodeLibraries).toSet() -internal fun runBitcodePasses(context: Context) { - if (!shouldRunBitcodePasses(context)) { - return - } val llvmModule = context.llvmModule!! - val passManager = LLVMCreatePassManager()!! - val targetLibraryInfo = LLVMGetTargetLibraryInfo(llvmModule) - LLVMAddTargetLibraryInfo(targetLibraryInfo, passManager) - context.coverage.addLlvmPasses(passManager) - LLVMRunPassManager(passManager, llvmModule) - LLVMDisposePassManager(passManager) + bitcodeFiles.forEach { + parseAndLinkBitcodeFile(llvmModule, it) + } +} + +private fun shouldOptimizeWithLlvmApi(context: Context) = + (context.config.target.family == Family.IOS || context.config.target.family == Family.OSX) + +private fun shoudRunClosedWorldCleanUp(context: Context) = + // GlobalDCE will kill coverage-related globals. + !context.coverage.enabled + +private fun runLlvmPipeline(context: Context) = when { + shouldOptimizeWithLlvmApi(context) -> runLlvmOptimizationPipeline(context) + shoudRunClosedWorldCleanUp(context) -> runClosedWorldCleanup(context) + else -> {} } internal fun produceOutput(context: Context) { @@ -57,7 +70,6 @@ internal fun produceOutput(context: Context) { CompilerOutputKind.PROGRAM -> { val output = tempFiles.nativeBinaryFileName context.bitcodeFileName = output - val generatedBitcodeFiles = if (produce == CompilerOutputKind.DYNAMIC || produce == CompilerOutputKind.STATIC) { produceCAdapterBitcode( @@ -66,20 +78,11 @@ internal fun produceOutput(context: Context) { tempFiles.cAdapterBitcodeName) listOf(tempFiles.cAdapterBitcodeName) } else emptyList() - - val nativeLibraries = - context.config.nativeLibraries + - context.config.defaultNativeLibraries + - generatedBitcodeFiles - - for (library in nativeLibraries) { - parseAndLinkBitcodeFile(context.llvmModule!!, library) - } - if (produce == CompilerOutputKind.FRAMEWORK && context.config.produceStaticFramework) { embedAppleLinkerOptionsToBitcode(context.llvm, context.config) } - + linkAllDependecies(context, generatedBitcodeFiles) + runLlvmPipeline(context) LLVMWriteBitcodeToFile(context.llvmModule!!, output) } CompilerOutputKind.LIBRARY -> { @@ -94,7 +97,6 @@ internal fun produceOutput(context: Context) { val nopack = config.getBoolean(KonanConfigKeys.NOPACK) val manifestProperties = context.config.manifestProperties - val library = buildLibrary( context.config.nativeLibraries, context.config.includeBinaries, @@ -109,7 +111,6 @@ internal fun produceOutput(context: Context) { manifestProperties, context.dataFlowGraph) - context.library = library context.bitcodeFileName = library.mainBitcodeFileName } CompilerOutputKind.BITCODE -> { @@ -147,4 +148,4 @@ private fun embedAppleLinkerOptionsToBitcode(llvm: Llvm, config: KonanConfig) { llvm.nativeDependenciesToLink.flatMap { findEmbeddableOptions(it.linkerOpts) } embedLlvmLinkOptions(llvm.llvmModule, optionsToEmbed) -} +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 7f20f896b28..11b6b8afdea 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescr import org.jetbrains.kotlin.backend.common.validateIrModule import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.ir.KonanIr -import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter import org.jetbrains.kotlin.backend.konan.library.LinkData import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD @@ -40,7 +39,6 @@ import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.konan.target.CompilerOutputKind -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.module @@ -54,6 +52,7 @@ import org.jetbrains.kotlin.backend.common.serialization.KotlinMangler import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl +import org.jetbrains.kotlin.name.FqName /** * Offset for synthetic elements created by lowerings and not attributable to other places in the source code. @@ -322,7 +321,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { val llvmImports: LlvmImports = Llvm.ImportsImpl(this) lateinit var llvmDeclarations: LlvmDeclarations lateinit var bitcodeFileName: String - lateinit var library: KonanLibraryWriter val cStubsManager = CStubsManager(config.target) @@ -441,7 +439,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { fun shouldPrintLocations() = config.configuration.getBoolean(KonanConfigKeys.PRINT_LOCATIONS) - fun shouldProfilePhases() = config.configuration.getBoolean(KonanConfigKeys.TIME_PHASES) + fun shouldProfilePhases() = config.phaseConfig.needProfiling fun shouldContainDebugInfo() = config.debug @@ -469,7 +467,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { internal val stdlibModule get() = this.builtIns.any.module - lateinit var linkStage: LinkStage + lateinit var compilerOutput: List } private fun MemberScope.getContributedClassifier(name: String) = diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index f8bec4933df..f00f8c372a2 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -96,8 +96,6 @@ class KonanConfigKeys { = CompilerConfigurationKey.create("target we compile for") val TEMPORARY_FILES_DIR: CompilerConfigurationKey = CompilerConfigurationKey.create("directory for temporary files") - val TIME_PHASES: CompilerConfigurationKey - = CompilerConfigurationKey.create("time backend phases") val VERIFY_BITCODE: CompilerConfigurationKey = CompilerConfigurationKey.create("verify bitcode") val VERIFY_DESCRIPTORS: CompilerConfigurationKey diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt deleted file mode 100644 index cb0f31e6493..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the LICENSE file. - */ - -package org.jetbrains.kotlin.backend.konan - -import org.jetbrains.kotlin.konan.KonanExternalToolFailure -import org.jetbrains.kotlin.konan.exec.Command -import org.jetbrains.kotlin.konan.file.File -import org.jetbrains.kotlin.konan.file.isBitcode -import org.jetbrains.kotlin.konan.target.* - -typealias BitcodeFile = String -typealias ObjectFile = String -typealias ExecutableFile = String - -private fun determineLinkerOutput(context: Context): LinkerOutputKind = - when (context.config.produce) { - CompilerOutputKind.FRAMEWORK -> { - val staticFramework = context.config.produceStaticFramework - if (staticFramework) LinkerOutputKind.STATIC_LIBRARY else LinkerOutputKind.DYNAMIC_LIBRARY - } - CompilerOutputKind.DYNAMIC -> LinkerOutputKind.DYNAMIC_LIBRARY - CompilerOutputKind.STATIC -> LinkerOutputKind.STATIC_LIBRARY - CompilerOutputKind.PROGRAM -> LinkerOutputKind.EXECUTABLE - else -> TODO("${context.config.produce} should not reach native linker stage") - } - -internal class LinkStage(val context: Context) { - - private val config = context.config.configuration - private val target = context.config.target - private val platform = context.config.platform - private val linker = platform.linker - - private val optimize = context.shouldOptimize() - private val debug = context.config.debug - private val linkerOutput = determineLinkerOutput(context) - - private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false - private val emitted = context.bitcodeFileName - - private val bitcodeLibraries = context.llvm.bitcodeToLink - private val nativeDependencies = context.llvm.nativeDependenciesToLink - - private val additionalBitcodeFilesToLink = context.llvm.additionalProducedBitcodeFiles - - private fun MutableList.addNonEmpty(elements: List) { - addAll(elements.filter { !it.isEmpty() }) - } - - private val exportedSymbols = context.coverage.addExportedSymbols() - - private fun mangleSymbol(symbol: String) = - if (target.family == Family.IOS || target.family == Family.OSX) { - "_$symbol" - } else { - symbol - } - - private fun runTool(command: List) = runTool(*command.toTypedArray()) - private fun runTool(vararg command: String) = - Command(*command) - .logWith(context::log) - .execute() - - private fun llvmLto(files: List): ObjectFile { - val combined = temporary("combined", ".o") - - val tool = "${platform.absoluteLlvmHome}/bin/llvm-lto" - val command = mutableListOf(tool, "-o", combined) - command.addNonEmpty(platform.llvmLtoFlags) - command.addNonEmpty(llvmProfilingFlags()) - when { - optimize -> command.addNonEmpty(platform.llvmLtoOptFlags) - debug -> command.addNonEmpty(platform.llvmDebugOptFlags) - else -> command.addNonEmpty(platform.llvmLtoNooptFlags) - } - command.addNonEmpty(platform.llvmLtoDynamicFlags) - command.addNonEmpty(files) - // Prevent symbols from being deleted by DCE. - command.addNonEmpty(exportedSymbols.map { "-exported-symbol=${mangleSymbol(it)}"} ) - runTool(command) - - return combined - } - - private fun temporary(name: String, suffix: String): String = - context.config.tempFiles.create(name, suffix).absolutePath - - private fun targetTool(tool: String, vararg arg: String) { - val absoluteToolName = "${platform.absoluteTargetToolchain}/bin/$tool" - runTool(absoluteToolName, *arg) - } - - private fun hostLlvmTool(tool: String, vararg arg: String) { - val absoluteToolName = "${platform.absoluteLlvmHome}/bin/$tool" - runTool(absoluteToolName, *arg) - } - - private fun bitcodeToWasm(bitcodeFiles: List): String { - val configurables = platform.configurables as WasmConfigurables - - val combinedBc = temporary("combined", ".bc") - // TODO: use -only-needed for the stdlib - hostLlvmTool("llvm-link", *bitcodeFiles.toTypedArray(), "-o", combinedBc) - val optFlags = (configurables.optFlags + when { - optimize -> configurables.optOptFlags - debug -> configurables.optDebugFlags - else -> configurables.optNooptFlags - } + llvmProfilingFlags()).toTypedArray() - val optimizedBc = temporary("optimized", ".bc") - hostLlvmTool("opt", combinedBc, "-o", optimizedBc, *optFlags) - val llcFlags = (configurables.llcFlags + when { - optimize -> configurables.llcOptFlags - debug -> configurables.llcDebugFlags - else -> configurables.llcNooptFlags - } + llvmProfilingFlags()).toTypedArray() - val combinedO = temporary("combined", ".o") - hostLlvmTool("llc", optimizedBc, "-o", combinedO, *llcFlags, "-filetype=obj") - val linkedWasm = temporary("linked", ".wasm") - hostLlvmTool("wasm-ld", combinedO, "-o", linkedWasm, *configurables.lldFlags.toTypedArray()) - return linkedWasm - } - - private fun llvmLinkAndLlc(bitcodeFiles: List): String { - val combinedBc = temporary("combined", ".bc") - hostLlvmTool("llvm-link", "-o", combinedBc, *bitcodeFiles.toTypedArray()) - - val optimizedBc = temporary("optimized", ".bc") - val optFlags = llvmProfilingFlags() + listOf("-O3", "-internalize", "-globaldce") - hostLlvmTool("opt", combinedBc, "-o=$optimizedBc", *optFlags.toTypedArray()) - - val combinedO = temporary("combined", ".o") - val llcFlags = llvmProfilingFlags() + listOf("-function-sections", "-data-sections") - hostLlvmTool("llc", optimizedBc, "-filetype=obj", "-o", combinedO, *llcFlags.toTypedArray()) - - return combinedO - } - - // llvm-lto, opt and llc share same profiling flags, so we can - // reuse this function. - private fun llvmProfilingFlags(): List { - val flags = mutableListOf() - if (context.shouldProfilePhases()) { - flags += "-time-passes" - } - if (context.inVerbosePhase) { - flags += "-debug-pass=Structure" - } - return flags - } - - private fun asLinkerArgs(args: List): List { - if (linker.useCompilerDriverAsLinker) { - return args - } - - val result = mutableListOf() - for (arg in args) { - // If user passes compiler arguments to us - transform them to linker ones. - if (arg.startsWith("-Wl,")) { - result.addAll(arg.substring(4).split(',')) - } else { - result.add(arg) - } - } - return result - } - - // Ideally we'd want to have - // #pragma weak main = Konan_main - // in the launcher.cpp. - // Unfortunately, anything related to weak linking on MacOS - // only seems to be working with dynamic libraries. - // So we stick to "-alias _main _konan_main" on Mac. - // And just do the same on Linux. - private val entryPointSelector: List - get() = if (nomain || linkerOutput != LinkerOutputKind.EXECUTABLE) emptyList() else platform.entrySelector - - private fun link(objectFiles: List, - includedBinaries: List, - libraryProvidedLinkerFlags: List): ExecutableFile? { - val frameworkLinkerArgs: List - val executable: String - - if (context.config.produce != CompilerOutputKind.FRAMEWORK) { - frameworkLinkerArgs = emptyList() - executable = context.config.outputFile - } else { - val framework = File(context.config.outputFile) - val dylibName = framework.name.removeSuffix(".framework") - val dylibRelativePath = when (target.family) { - Family.IOS -> dylibName - Family.OSX -> "Versions/A/$dylibName" - else -> error(target) - } - frameworkLinkerArgs = listOf("-install_name", "@rpath/${framework.name}/$dylibRelativePath") - val dylibPath = framework.child(dylibRelativePath) - dylibPath.parentFile.mkdirs() - executable = dylibPath.absolutePath - } - - try { - File(executable).delete() - linker.linkCommands(objectFiles = objectFiles, executable = executable, - libraries = linker.linkStaticLibraries(includedBinaries) + context.config.defaultSystemLibraries, - linkerArgs = entryPointSelector + - asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) + - BitcodeEmbedding.getLinkerOptions(context.config) + - libraryProvidedLinkerFlags + frameworkLinkerArgs, - optimize = optimize, debug = debug, kind = linkerOutput, - outputDsymBundle = context.config.outputFile + ".dSYM").forEach { - it.logWith(context::log) - it.execute() - } - } catch (e: KonanExternalToolFailure) { - context.reportCompilationError("${e.toolName} invocation reported errors") - } - return executable - } - - val objectFiles = mutableListOf() - - fun makeObjectFiles() { - - val bitcodeFiles = listOf(emitted) + additionalBitcodeFilesToLink + - bitcodeLibraries.map { it.bitcodePaths }.flatten().filter { it.isBitcode } - - objectFiles.add(when (platform.configurables) { - is WasmConfigurables - -> bitcodeToWasm(bitcodeFiles) - is ZephyrConfigurables - -> llvmLinkAndLlc(bitcodeFiles) - else - -> llvmLto(bitcodeFiles) - }) - } - - fun linkStage() { - val includedBinaries = - nativeDependencies.map { it.includedPaths }.flatten() - - val libraryProvidedLinkerFlags = - nativeDependencies.map { it.linkerOpts }.flatten() - - link(objectFiles, includedBinaries, libraryProvidedLinkerFlags) - } -} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt new file mode 100644 index 00000000000..eac86ab7605 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt @@ -0,0 +1,109 @@ +package org.jetbrains.kotlin.backend.konan + +import org.jetbrains.kotlin.konan.KonanExternalToolFailure +import org.jetbrains.kotlin.konan.file.File +import org.jetbrains.kotlin.konan.target.CompilerOutputKind +import org.jetbrains.kotlin.konan.target.Family +import org.jetbrains.kotlin.konan.target.LinkerOutputKind + +internal fun determineLinkerOutput(context: Context): LinkerOutputKind = + when (context.config.produce) { + CompilerOutputKind.FRAMEWORK -> { + val staticFramework = context.config.produceStaticFramework + if (staticFramework) LinkerOutputKind.STATIC_LIBRARY else LinkerOutputKind.DYNAMIC_LIBRARY + } + CompilerOutputKind.DYNAMIC -> LinkerOutputKind.DYNAMIC_LIBRARY + CompilerOutputKind.STATIC -> LinkerOutputKind.STATIC_LIBRARY + CompilerOutputKind.PROGRAM -> LinkerOutputKind.EXECUTABLE + else -> TODO("${context.config.produce} should not reach native linker stage") + } + +// TODO: We have a Linker.kt file in the shared module. +internal class Linker(val context: Context) { + + private val platform = context.config.platform + private val config = context.config.configuration + private val linkerOutput = determineLinkerOutput(context) + private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false + private val linker = platform.linker + private val target = context.config.target + private val optimize = context.shouldOptimize() + private val debug = context.config.debug + + // Ideally we'd want to have + // #pragma weak main = Konan_main + // in the launcher.cpp. + // Unfortunately, anything related to weak linking on MacOS + // only seems to be working with dynamic libraries. + // So we stick to "-alias _main _konan_main" on Mac. + // And just do the same on Linux. + private val entryPointSelector: List + get() = if (nomain || linkerOutput != LinkerOutputKind.EXECUTABLE) emptyList() else platform.entrySelector + + fun link(objectFiles: List) { + val nativeDependencies = context.llvm.nativeDependenciesToLink + val includedBinaries = nativeDependencies.map { it.includedPaths }.flatten() + val libraryProvidedLinkerFlags = nativeDependencies.map { it.linkerOpts }.flatten() + runLinker(objectFiles, includedBinaries, libraryProvidedLinkerFlags) + } + + private fun asLinkerArgs(args: List): List { + if (linker.useCompilerDriverAsLinker) { + return args + } + + val result = mutableListOf() + for (arg in args) { + // If user passes compiler arguments to us - transform them to linker ones. + if (arg.startsWith("-Wl,")) { + result.addAll(arg.substring(4).split(',')) + } else { + result.add(arg) + } + } + return result + } + + private fun runLinker(objectFiles: List, + includedBinaries: List, + libraryProvidedLinkerFlags: List): ExecutableFile? { + val frameworkLinkerArgs: List + val executable: String + + if (context.config.produce != CompilerOutputKind.FRAMEWORK) { + frameworkLinkerArgs = emptyList() + executable = context.config.outputFile + } else { + val framework = File(context.config.outputFile) + val dylibName = framework.name.removeSuffix(".framework") + val dylibRelativePath = when (target.family) { + Family.IOS -> dylibName + Family.OSX -> "Versions/A/$dylibName" + else -> error(target) + } + frameworkLinkerArgs = listOf("-install_name", "@rpath/${framework.name}/$dylibRelativePath") + val dylibPath = framework.child(dylibRelativePath) + dylibPath.parentFile.mkdirs() + executable = dylibPath.absolutePath + } + + try { + File(executable).delete() + linker.linkCommands(objectFiles = objectFiles, executable = executable, + libraries = linker.linkStaticLibraries(includedBinaries) + context.config.defaultSystemLibraries, + linkerArgs = entryPointSelector + + asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) + + BitcodeEmbedding.getLinkerOptions(context.config) + + libraryProvidedLinkerFlags + frameworkLinkerArgs, + optimize = optimize, debug = debug, kind = linkerOutput, + outputDsymBundle = context.config.outputFile + ".dSYM").forEach { + it.logWith(context::log) + it.execute() + } + } catch (e: KonanExternalToolFailure) { + context.reportCompilationError("${e.toolName} invocation reported errors") + } + return executable + } + +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OptimizationPipeline.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OptimizationPipeline.kt new file mode 100644 index 00000000000..cd16c634d6c --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OptimizationPipeline.kt @@ -0,0 +1,146 @@ +package org.jetbrains.kotlin.backend.konan + +import kotlinx.cinterop.alloc +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.ptr +import kotlinx.cinterop.value +import llvm.* +import org.jetbrains.kotlin.konan.target.KonanTarget + +private fun initializeLlvmGlobalPassRegistry() { + val passRegistry = LLVMGetGlobalPassRegistry() + + LLVMInitializeCore(passRegistry) + LLVMInitializeTransformUtils(passRegistry) + LLVMInitializeScalarOpts(passRegistry) + LLVMInitializeVectorization(passRegistry) + LLVMInitializeInstCombine(passRegistry) + LLVMInitializeIPO(passRegistry) + LLVMInitializeInstrumentation(passRegistry) + LLVMInitializeAnalysis(passRegistry) + LLVMInitializeIPA(passRegistry) + LLVMInitializeCodeGen(passRegistry) + LLVMInitializeTarget(passRegistry) +} + +internal fun shouldRunLateBitcodePasses(context: Context): Boolean { + return context.coverage.enabled +} + +internal fun runLateBitcodePasses(context: Context, llvmModule: LLVMModuleRef) { + val passManager = LLVMCreatePassManager()!! + val targetLibraryInfo = LLVMGetTargetLibraryInfo(llvmModule) + LLVMAddTargetLibraryInfo(targetLibraryInfo, passManager) + context.coverage.addLateLlvmPasses(passManager) + LLVMRunPassManager(passManager, llvmModule) + LLVMDisposePassManager(passManager) +} + +private class LlvmPipelineConfiguration(context: Context) { + + private val target = context.config.target + + val targetTriple: String = context.llvm.targetTriple + + val cpuArchitecture: String = when (target) { + KonanTarget.IOS_ARM32 -> "armv7" + KonanTarget.IOS_ARM64 -> "arm64" + KonanTarget.MACOS_X64 -> "core2" + else -> error("There is no support for ${target.name} target yet.") + } + + val cpuFeatures: String = "" + + val customInlineThreshold: Int? = when { + context.shouldOptimize() -> 100 + context.shouldContainDebugInfo() -> null + else -> null + } + + val optimizationLevel: Int = when { + context.shouldOptimize() -> 3 + context.shouldContainDebugInfo() -> 0 + else -> 1 + } + + val sizeLevel: Int = when { + context.shouldOptimize() -> 0 + context.shouldContainDebugInfo() -> 0 + else -> 0 + } + + val codegenOptimizationLevel: LLVMCodeGenOptLevel = when { + context.shouldOptimize() -> LLVMCodeGenOptLevel.LLVMCodeGenLevelAggressive + context.shouldContainDebugInfo() -> LLVMCodeGenOptLevel.LLVMCodeGenLevelNone + else -> LLVMCodeGenOptLevel.LLVMCodeGenLevelDefault + } + + val relocMode: LLVMRelocMode = LLVMRelocMode.LLVMRelocDefault + + val codeModel: LLVMCodeModel = LLVMCodeModel.LLVMCodeModelDefault +} + +// Since we are in a "closed world" internalization and global dce +// can be safely used to reduce size of a bitcode. +internal fun runClosedWorldCleanup(context: Context) { + initializeLlvmGlobalPassRegistry() + val llvmModule = context.llvmModule!! + val modulePasses = LLVMCreatePassManager() + LLVMAddInternalizePass(modulePasses, 0) + LLVMAddGlobalDCEPass(modulePasses) + LLVMRunPassManager(modulePasses, llvmModule) + LLVMDisposePassManager(modulePasses) +} + +internal fun runLlvmOptimizationPipeline(context: Context) { + val llvmModule = context.llvmModule!! + val config = LlvmPipelineConfiguration(context) + + memScoped { + LLVMKotlinInitializeTargets() + + initializeLlvmGlobalPassRegistry() + val passBuilder = LLVMPassManagerBuilderCreate() + val modulePasses = LLVMCreatePassManager() + LLVMPassManagerBuilderSetOptLevel(passBuilder, config.optimizationLevel) + LLVMPassManagerBuilderSetSizeLevel(passBuilder, config.sizeLevel) + // TODO: use LLVMGetTargetFromName instead. + val target = alloc() + val foundLlvmTarget = LLVMGetTargetFromTriple(config.targetTriple, target.ptr, null) == 0 + check(foundLlvmTarget) { "Cannot get target from triple ${config.targetTriple}." } + + val targetMachine = LLVMCreateTargetMachine( + target.value, + config.targetTriple, + config.cpuArchitecture, + config.cpuFeatures, + config.codegenOptimizationLevel, + config.relocMode, + config.codeModel) + + val targetLibraryInfo = LLVMGetTargetLibraryInfo(llvmModule) + LLVMAddTargetLibraryInfo(targetLibraryInfo, modulePasses) + // TargetTransformInfo pass. + LLVMAddAnalysisPasses(targetMachine, modulePasses) + // Since we are in a "closed world" internalization and global dce + // can be safely used to reduce size of a bitcode. + LLVMAddInternalizePass(modulePasses, 0) + LLVMAddGlobalDCEPass(modulePasses) + + config.customInlineThreshold?.let { threshold -> + LLVMPassManagerBuilderUseInlinerWithThreshold(passBuilder, threshold) + } + // Pipeline that is similar to `llvm-lto`. + // TODO: Add ObjC optimization passes. + LLVMPassManagerBuilderPopulateLTOPassManager(passBuilder, modulePasses, Internalize = 0, RunInliner = 1) + LLVMPassManagerBuilderDispose(passBuilder) + + LLVMRunPassManager(modulePasses, llvmModule) + + LLVMDisposeTargetMachine(targetMachine) + LLVMDisposePassManager(modulePasses) + } + if (shouldRunLateBitcodePasses(context)) { + runLateBitcodePasses(context, llvmModule) + } +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index 22ca3b9935b..084e04a5300 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -1,9 +1,9 @@ package org.jetbrains.kotlin.backend.konan +import llvm.LLVMWriteBitcodeToFile import org.jetbrains.kotlin.backend.common.LoggingContext import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.phaser.* -import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols @@ -15,10 +15,15 @@ import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable +import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.patchDeclarationParents +import org.jetbrains.kotlin.konan.CURRENT +import org.jetbrains.kotlin.konan.KonanAbiVersion +import org.jetbrains.kotlin.konan.KonanVersion +import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator @@ -185,20 +190,14 @@ internal val serializerPhase = konanUnitPhase( description = "Serialize descriptor tree and inline IR bodies" ) -internal val setUpLinkStagePhase = konanUnitPhase( - op = { linkStage = LinkStage(this) }, - name = "SetUpLinkStage", - description = "Set up link stage" -) - internal val objectFilesPhase = konanUnitPhase( - op = { linkStage.makeObjectFiles() }, + op = { compilerOutput = BitcodeCompiler(this).makeObjectFiles(bitcodeFileName) }, name = "ObjectFiles", description = "Bitcode to object file" ) internal val linkerPhase = konanUnitPhase( - op = { linkStage.linkStage() }, + op = { Linker(this).link(compilerOutput) }, name = "Linker", description = "Linker" ) @@ -206,8 +205,7 @@ internal val linkerPhase = konanUnitPhase( internal val linkPhase = namedUnitPhase( name = "Link", description = "Link stage", - lower = setUpLinkStagePhase then - objectFilesPhase then + lower = objectFilesPhase then linkerPhase ) @@ -304,7 +302,6 @@ internal val bitcodePhase = namedIrModulePhase( escapeAnalysisPhase then codegenPhase then finalizeDebugInfoPhase then - bitcodePassesPhase then cStubsPhase ) @@ -330,9 +327,9 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase( dependenciesLowerPhase then // Then lower all libraries in topological order. // With that we guarantee that inline functions are unlowered while being inlined. bitcodePhase then - produceOutputPhase then verifyBitcodePhase then printBitcodePhase then + produceOutputPhase then unitSink() ) then linkPhase diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt index 0149adfc7f8..7f4e4ed601d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BitcodePhases.kt @@ -124,16 +124,6 @@ internal val cStubsPhase = makeKonanModuleOpPhase( op = { context, _ -> produceCStubs(context) } ) -/** - * Runs specific passes over context.llvmModule. The main compilation pipeline - * is performed by [linkPhase]. - */ -internal val bitcodePassesPhase = makeKonanModuleOpPhase( - name = "BitcodePasses", - description = "Run custom LLVM passes over bitcode", - op = { context, _ -> runBitcodePasses(context) } -) - internal val produceOutputPhase = makeKonanModuleOpPhase( name = "ProduceOutput", description = "Produce output", diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 925739e3905..a876a2e6406 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -409,9 +409,11 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { val runtimeFile = context.config.distribution.runtime(target) val runtime = Runtime(runtimeFile) // TODO: dispose + val targetTriple = runtime.target + init { LLVMSetDataLayout(llvmModule, runtime.dataLayout) - LLVMSetTarget(llvmModule, runtime.target) + LLVMSetTarget(llvmModule, targetTriple) } private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 375f37a5fbd..c4bf3bfb18c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -318,7 +318,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map Xcode.current.iphonesimulatorSdk + KonanTarget.IOS_ARM64, KonanTarget.IOS_ARM32 -> Xcode.current.iphoneosSdk + KonanTarget.MACOS_X64 -> Xcode.current.macosxSdk + else -> error("Cannot validate bitcode for test target $testTarget") + } + + val args = listOf("--sdk", sdk, "-v", "-t", ldPath, frameworkBinary) + val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor(project), executable = bitcodeBuildTool, args = args) + check(exitCode == 0) { + """ + |bitcode-build-tool failed: + |stdout: $stdOut + |stderr: $stdErr + """.trimMargin() + } + } +} diff --git a/gradle.properties b/gradle.properties index c36f75b4b8f..c39d73e6e81 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,8 +23,9 @@ kotlinVersion=1.3.40-dev-2423 testKotlinVersion=1.3.40-dev-2423 # See https://teamcity.jetbrains.com/project.html?projectId=Kotlin_KotlinNativeShared&tab=projectOverview sharedRepo=https://dl.bintray.com/jetbrains/kotlin-native-dependencies -sharedVersion=1.0-dev-50 +sharedVersion=1.0-dev-57 konanVersion=1.3.0 org.gradle.jvmargs='-Dfile.encoding=UTF-8' org.gradle.workers.max=4 -#kotlinProjectPath=/Users/jetbrains/kotlin-native/kotlin +#kotlinProjectPath=/Users/jetbrains/IdeaProjects/kotlin +#sharedProjectPath=/Users/jetbrains/IdeaProjects/kotlin-native-shared \ No newline at end of file diff --git a/konan/konan.properties b/konan/konan.properties index 735f5882423..5ded7f1a5b7 100644 --- a/konan/konan.properties +++ b/konan/konan.properties @@ -39,24 +39,30 @@ llvmVersion = 6.0.1 llvmHome.macos_x64 = clang-llvm-6.0.1-darwin-macos targetToolchain.macos_x64 = target-toolchain-9-macos_x64 libffiDir.macos_x64 = libffi-3.2.1-3-darwin-macos +additionalToolsDir.macos_x64 = xcode-addon-9-macos_x64 arch.macos_x64 = x86_64 targetSysRoot.macos_x64 = target-sysroot-9-macos_x64 -llvmLtoFlags.macos_x64 = -llvmLtoOptFlags.macos_x64 = -O3 -function-sections -llvmLtoNooptFlags.macos_x64 = -O1 -llvmLtoDynamicFlags.macos_x64 = -relocation-model=pic + +clangFlags.macos_x64 = -cc1 -emit-obj -disable-llvm-passes -x ir +clangNooptFlags.macos_x64 = -O1 +clangOptFlags.macos_x64 = -O3 +clangDebugFlags.macos_x64 = -O0 +clangDynamicFlags.macos_x64 = + linkerKonanFlags.macos_x64 = -lSystem -lc++ -lobjc -framework Foundation linkerOptimizationFlags.macos_x64 = -dead_strip linkerNoDebugFlags.macos_x64 = -S linkerDynamicFlags.macos_x64 = -dylib + osVersionMinFlagLd.macos_x64 = -macosx_version_min osVersionMinFlagClang.macos_x64 = -mmacosx-version-min osVersionMin.macos_x64 = 10.11 entrySelector.macos_x64 = -alias _Konan_main _main dependencies.macos_x64 = \ libffi-3.2.1-3-darwin-macos \ - clang-llvm-6.0.1-darwin-macos + clang-llvm-6.0.1-darwin-macos \ + xcode-addon-9-macos_x64 target-sysroot-9-macos_x64.default = \ remote:internal @@ -64,6 +70,10 @@ target-sysroot-9-macos_x64.default = \ target-toolchain-9-macos_x64.default = \ remote:internal +xcode-addon-9-macos_x64.default = \ + remote:internal + + # Apple's 32-bit iOS. targetToolchain.macos_x64-ios_arm32 = target-toolchain-9-macos_x64 dependencies.macos_x64-ios_arm32 = \ @@ -77,13 +87,15 @@ arch.ios_arm32 = armv7 entrySelector.ios_arm32 = -alias _Konan_main _main # Shared with 64-bit version. targetSysRoot.ios_arm32 = target-sysroot-9-ios_arm64 -llvmLtoFlags.ios_arm32 = -llvmLtoOptFlags.ios_arm32 = -O3 -function-sections + +clangFlags.ios_arm32 = -cc1 -emit-obj -disable-llvm-optzns -x ir +clangNooptFlags.ios_arm32 = -O1 +clangOptFlags.ios_arm32 = -O3 +clangDebugFlags.ios_arm32 = -O0 +clangDynamicFlags.ios_arm32 = linkerNoDebugFlags.ios_arm32 = -S linkerDynamicFlags.ios_arm32 = -dylib -llvmLtoNooptFlags.ios_arm32 = -O1 -llvmLtoDynamicFlags.ios_arm32 = -relocation-model=pic -linkerKonanFlags.ios_arm32 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 12.2 +linkerKonanFlags.ios_arm32 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 11.2 linkerOptimizationFlags.ios_arm32 = -dead_strip osVersionMinFlagLd.ios_arm32 = -iphoneos_version_min osVersionMinFlagClang.ios_arm32 = -miphoneos-version-min @@ -101,13 +113,16 @@ target-sysroot-9-ios_arm64.default = \ arch.ios_arm64 = arm64 entrySelector.ios_arm64 = -alias _Konan_main _main targetSysRoot.ios_arm64 = target-sysroot-9-ios_arm64 -llvmLtoFlags.ios_arm64 = -llvmLtoOptFlags.ios_arm64 = -O3 -function-sections + +clangFlags.ios_arm64 = -cc1 -emit-obj -disable-llvm-passes -x ir +clangNooptFlags.ios_arm64 = -O1 +clangOptFlags.ios_arm64 = -O3 +clangDebugFlags.ios_arm64 = -O0 +clangDynamicFlags.ios_arm64 = + linkerNoDebugFlags.ios_arm64 = -S linkerDynamicFlags.ios_arm64 = -dylib -llvmLtoNooptFlags.ios_arm64 = -O1 -llvmLtoDynamicFlags.ios_arm64 = -relocation-model=pic -linkerKonanFlags.ios_arm64 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 12.2 +linkerKonanFlags.ios_arm64 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 11.2 linkerOptimizationFlags.ios_arm64 = -dead_strip osVersionMinFlagLd.ios_arm64 = -iphoneos_version_min osVersionMinFlagClang.ios_arm64 = -miphoneos-version-min @@ -125,11 +140,14 @@ target-sysroot-9-ios_x64.default = \ arch.ios_x64 = x86_64 entrySelector.ios_x64 = -alias _Konan_main _main targetSysRoot.ios_x64 = target-sysroot-9-ios_x64 -llvmLtoFlags.ios_x64 = -llvmLtoOptFlags.ios_x64 = -O3 -function-sections -llvmLtoNooptFlags.ios_x64 = -O1 -llvmLtoDynamicFlags.ios_x64 = -relocation-model=pic -linkerKonanFlags.ios_x64 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 12.2 + +clangFlags.ios_x64 = -cc1 -emit-obj -disable-llvm-passes -x ir +clangNooptFlags.ios_x64 = -O1 +clangOptFlags.ios_x64 = -O3 +clangDebugFlags.ios_x64 = -O0 +clangDynamicFlags.ios_x64 = + +linkerKonanFlags.ios_x64 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 11.2 linkerOptimizationFlags.ios_x64 = -dead_strip linkerNoDebugFlags.ios_x64 = -S linkerDynamicFlags.ios_x64 = -dylib diff --git a/llvmCoverageMappingC/build.gradle b/llvmCoverageMappingC/build.gradle index c513d8ba344..9870dbc0714 100644 --- a/llvmCoverageMappingC/build.gradle +++ b/llvmCoverageMappingC/build.gradle @@ -30,6 +30,15 @@ model { if (!project.parent.convention.plugins.platformInfo.isWindows()) cppCompiler.args "-fPIC" cppCompiler.args "--std=c++11", "-I${llvmDir}/include", "-I${projectDir}/src/main/include" + if (isMac()) { + cppCompiler.args "-DKONAN_MACOS=1" + } else if (isWindows()) { + cppCompiler.args "-DKONAN_WINDOWS=1" + } else if (isLinux()) { + cppCompiler.args "-DKONAN_LINUX=1" + } else { + throw new Error("Unsupported host OS.") + } linker.args "-L${llvmDir}/lib", "-lLLVMCore", "-lLLVMSupport" } binaries.withType(SharedLibraryBinarySpec) { binary -> diff --git a/llvmCoverageMappingC/src/main/cpp/CoverageMappingC.cpp b/llvmCoverageMappingC/src/main/cpp/CoverageMappingC.cpp index d6ce53c3c7b..97add2c525e 100644 --- a/llvmCoverageMappingC/src/main/cpp/CoverageMappingC.cpp +++ b/llvmCoverageMappingC/src/main/cpp/CoverageMappingC.cpp @@ -227,4 +227,22 @@ void LLVMAddInstrProfPass(LLVMPassManagerRef passManagerRef, const char* outputF LLVMTargetLibraryInfoRef LLVMGetTargetLibraryInfo(LLVMModuleRef moduleRef) { auto* libraryInfo = new TargetLibraryInfoImpl(Triple(unwrap(moduleRef)->getTargetTriple())); return llvm::wrap(libraryInfo); +} + +void LLVMKotlinInitializeTargets() { +#define INIT_LLVM_TARGET(TargetName) \ + LLVMInitialize##TargetName##TargetInfo();\ + LLVMInitialize##TargetName##Target();\ + LLVMInitialize##TargetName##TargetMC(); +#if KONAN_MACOS + INIT_LLVM_TARGET(AArch64) + INIT_LLVM_TARGET(ARM) + INIT_LLVM_TARGET(Mips) + INIT_LLVM_TARGET(X86) + INIT_LLVM_TARGET(WebAssembly) +#elif KONAN_LINUX +#elif KONAN_WINDOWS +#endif + +#undef INIT_LLVM_TARGET } \ No newline at end of file diff --git a/llvmCoverageMappingC/src/main/include/CoverageMappingC.h b/llvmCoverageMappingC/src/main/include/CoverageMappingC.h index 5cfaf09032b..e2396e19676 100644 --- a/llvmCoverageMappingC/src/main/include/CoverageMappingC.h +++ b/llvmCoverageMappingC/src/main/include/CoverageMappingC.h @@ -74,8 +74,9 @@ void LLVMAddInstrProfPass(LLVMPassManagerRef passManagerRef, const char* outputF LLVMTargetLibraryInfoRef LLVMGetTargetLibraryInfo(LLVMModuleRef moduleRef); +void LLVMKotlinInitializeTargets(); + # ifdef __cplusplus } - # endif #endif diff --git a/tools/scripts/update_xcode.sh b/tools/scripts/update_xcode.sh index 886096badaf..00d58fae91c 100755 --- a/tools/scripts/update_xcode.sh +++ b/tools/scripts/update_xcode.sh @@ -9,6 +9,7 @@ TARBALL_iphonesimulator=target-sysroot-$KONAN_TOOLCHAIN_VERSION-ios_x64 TARBALL_watchos=target-sysroot-$KONAN_TOOLCHAIN_VERSION-watchos_arm32 TARBALL_watchsimulator=target-sysroot-$KONAN_TOOLCHAIN_VERSION-watchos_x64 TARBALL_xcode=target-toolchain-$KONAN_TOOLCHAIN_VERSION-macos_x64 +TARBALL_xcode_addon=xcode-addon-$KONAN_TOOLCHAIN_VERSION-macos_x64 OUT=`pwd` for s in $SDKS; do @@ -26,3 +27,10 @@ t=`grealpath $t/../..` tarball=$TARBALL_xcode echo "Packing toolchain $OUT/$tarball.tar.gz..." $SHELL -c "tar czf $OUT/$tarball.tar.gz -C $t -s '/^\./$tarball/' ." + +t=`xcrun -f bitcode-build-tool` +t=`dirname $t` +t=`grealpath $t/..` +tarball=$TARBALL_xcode_addon +echo "Packing additional tools $OUT/$tarball.tar.gz..." +$SHELL -c "tar czf $OUT/$tarball.tar.gz -C $t -s '/^\./$tarball/' ." \ No newline at end of file