Make static cache symbols hidden
Enables DCE for cached code when linking dynamic library too
This commit is contained in:
committed by
SvyatoslavScherbina
parent
f282ff0f55
commit
990c754f77
+8
@@ -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)
|
||||
|
||||
|
||||
+12
@@ -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
|
||||
|
||||
+59
@@ -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
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user