Make static cache symbols hidden

Enables DCE for cached code when linking dynamic library too
This commit is contained in:
Svyatoslav Scherbina
2020-04-10 19:19:59 +03:00
committed by SvyatoslavScherbina
parent f282ff0f55
commit 990c754f77
3 changed files with 79 additions and 0 deletions
@@ -5,6 +5,8 @@ import kotlinx.cinterop.memScoped
import kotlinx.cinterop.ptr
import kotlinx.cinterop.value
import llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.makeVisibilityHiddenLikeLlvmInternalizePass
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.Configurables
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.ZephyrConfigurables
@@ -175,6 +177,12 @@ internal fun runLlvmOptimizationPipeline(context: Context) {
// Since we are in a "closed world" internalization can be safely used
// to reduce size of a bitcode with global dce.
LLVMAddInternalizePass(modulePasses, 0)
} else if (context.config.produce == CompilerOutputKind.STATIC_CACHE) {
// Hidden visibility makes symbols internal when linking the binary.
// When producing dynamic library, this enables stripping unused symbols from binary with -dead_strip flag,
// similar to DCE enabled by internalize but later:
makeVisibilityHiddenLikeLlvmInternalizePass(llvmModule)
// Important for binary size, workarounds references to undefined symbols from interop libraries.
}
LLVMAddGlobalDCEPass(modulePasses)
@@ -419,6 +419,18 @@ internal fun node(vararg it:LLVMValueRef) = LLVMMDNodeInContext(llvmContext, it.
internal fun LLVMValueRef.setUnaligned() = apply { LLVMSetAlignment(this, 1) }
internal fun getOperands(value: LLVMValueRef) =
(0 until LLVMGetNumOperands(value)).map { LLVMGetOperand(value, it)!! }
internal fun getGlobalAliases(module: LLVMModuleRef) =
generateSequence(LLVMGetFirstGlobalAlias(module), { LLVMGetNextGlobalAlias(it) })
internal fun getFunctions(module: LLVMModuleRef) =
generateSequence(LLVMGetFirstFunction(module), { LLVMGetNextFunction(it) })
internal fun getGlobals(module: LLVMModuleRef) =
generateSequence(LLVMGetFirstGlobal(module), { LLVMGetNextGlobal(it) })
fun LLVMTypeRef.isFloatingPoint(): Boolean = when (llvm.LLVMGetTypeKind(this)) {
LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind -> true
else -> false
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2020 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.llvm
import llvm.*
import org.jetbrains.kotlin.utils.DFS
/**
* Applies hidden visibility to symbols similarly to LLVM's internalize pass:
* it makes hidden the symbols that are made internal by internalize.
*/
fun makeVisibilityHiddenLikeLlvmInternalizePass(module: LLVMModuleRef) {
// Note: the implementation below generally follows InternalizePass::internalizeModule,
// but omits some details for simplicity.
// TODO: LLVM handles some additional cases.
val alwaysPreserved = getLlvmUsed(module)
(getFunctions(module) + getGlobals(module) + getGlobalAliases(module))
.filter {
when (LLVMGetLinkage(it)) {
LLVMLinkage.LLVMInternalLinkage, LLVMLinkage.LLVMPrivateLinkage -> false
else -> true
}
}
.filter { LLVMIsDeclaration(it) == 0 }
.minus(alwaysPreserved)
.forEach {
LLVMSetVisibility(it, LLVMVisibility.LLVMHiddenVisibility)
}
}
private fun getLlvmUsed(module: LLVMModuleRef): Set<LLVMValueRef> {
val llvmUsed = LLVMGetNamedGlobal(module, "llvm.used") ?: return emptySet()
val llvmUsedValue = LLVMGetInitializer(llvmUsed) ?: return emptySet()
// Note: llvm.used value is an array of globals, wrapped into bitcasts, GEPs and other instructions;
// see llvm::collectUsedGlobalVariables.
// Conservatively extract all involved globals for simplicity:
return DFS.dfs(
/* nodes = */ listOf(llvmUsedValue),
/* neighbors = */ { value -> getOperands(value) },
object : DFS.CollectingNodeHandler<LLVMValueRef, LLVMValueRef, MutableSet<LLVMValueRef>>(mutableSetOf()) {
override fun beforeChildren(current: LLVMValueRef): Boolean = when (LLVMGetValueKind(current)) {
LLVMValueKind.LLVMGlobalAliasValueKind,
LLVMValueKind.LLVMGlobalVariableValueKind,
LLVMValueKind.LLVMFunctionValueKind -> {
result.add(current)
false // Skip children.
}
else -> true
}
}
)
}