forked from JetBrains/kotlin-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use clang instead if llvm-lto for darwin-based targets (JetBrains#2974)
* Use LLVM C API for optimizations * Use Clang for bitcode compilation * Test bitcode embedding
- Loading branch information
1 parent
89c2fb2
commit 5306d7b
Showing
23 changed files
with
620 additions
and
367 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
179 changes: 179 additions & 0 deletions
179
...tive/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeCompiler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<String>.addNonEmpty(elements: List<String>) { | ||
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<String>().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<String>().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<String> { | ||
val flags = mutableListOf<String>() | ||
if (context.shouldProfilePhases()) { | ||
flags += "-time-passes" | ||
} | ||
if (context.inVerbosePhase) { | ||
flags += "-debug-pass=Structure" | ||
} | ||
return flags | ||
} | ||
|
||
fun makeObjectFiles(bitcodeFile: BitcodeFile): List<ObjectFile> = | ||
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}!") | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.