[K/N] Introduce RemoveRedundantSafepointsPass
Since we do not inline Kotlin_mm_* functions on watchos_arm32 and ios_arm32 targets, there are a lot of unnecessary subsequent safepoints. To reduce binary size and avoid unnecessary safepoints we apply a simple optimization: remove all calls to Kotlin_mm_safePointFunctionPrologue in a basic block except the first one. ^KT-51737 fixed.
This commit is contained in:
+3
@@ -545,6 +545,7 @@ private val bitcodePostprocessingPhase = NamedCompilerPhase(
|
|||||||
lower = checkExternalCallsPhase then
|
lower = checkExternalCallsPhase then
|
||||||
bitcodeOptimizationPhase then
|
bitcodeOptimizationPhase then
|
||||||
coveragePhase then
|
coveragePhase then
|
||||||
|
removeRedundantSafepointsPhase then
|
||||||
optimizeTLSDataLoadsPhase then
|
optimizeTLSDataLoadsPhase then
|
||||||
rewriteExternalCallsCheckerGlobals
|
rewriteExternalCallsCheckerGlobals
|
||||||
)
|
)
|
||||||
@@ -644,6 +645,8 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
|
|||||||
disableUnless(fileInitializersPhase, getBoolean(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION))
|
disableUnless(fileInitializersPhase, getBoolean(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION))
|
||||||
disableUnless(removeRedundantCallsToFileInitializersPhase, getBoolean(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION))
|
disableUnless(removeRedundantCallsToFileInitializersPhase, getBoolean(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION))
|
||||||
|
|
||||||
|
disableUnless(removeRedundantSafepointsPhase, config.configuration.get(BinaryOptions.memoryModel) == MemoryModel.EXPERIMENTAL)
|
||||||
|
|
||||||
val isDescriptorsOnlyLibrary = config.metadataKlib == true
|
val isDescriptorsOnlyLibrary = config.metadataKlib == true
|
||||||
disableIf(psiToIrPhase, isDescriptorsOnlyLibrary)
|
disableIf(psiToIrPhase, isDescriptorsOnlyLibrary)
|
||||||
disableIf(destroySymbolTablePhase, isDescriptorsOnlyLibrary)
|
disableIf(destroySymbolTablePhase, isDescriptorsOnlyLibrary)
|
||||||
|
|||||||
+12
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.llvm
|
package org.jetbrains.kotlin.backend.konan.llvm
|
||||||
|
|
||||||
import llvm.*
|
import llvm.*
|
||||||
|
import org.jetbrains.kotlin.backend.common.LoggingContext
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase
|
import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.PhaserState
|
import org.jetbrains.kotlin.backend.common.phaser.PhaserState
|
||||||
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.ir.util.isFunction
|
|||||||
import org.jetbrains.kotlin.ir.util.isReal
|
import org.jetbrains.kotlin.ir.util.isReal
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.ir.visitors.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
|
import org.jetbrains.kotlin.konan.target.Architecture
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
|
|
||||||
@@ -386,6 +388,16 @@ internal val produceOutputPhase = namedUnitPhase(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal val removeRedundantSafepointsPhase = makeKonanModuleOpPhase(
|
||||||
|
name = "RemoveRedundantSafepoints",
|
||||||
|
description = "Leave only one safepoint in a basic block",
|
||||||
|
op = { context, _ ->
|
||||||
|
if (context.config.target.architecture == Architecture.ARM32 && context.config.target.family.isAppleFamily) {
|
||||||
|
RemoveRedundantSafepointsPass(context as LoggingContext).runOnModule(context.llvmModule!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
internal val verifyBitcodePhase = makeKonanModuleOpPhase(
|
internal val verifyBitcodePhase = makeKonanModuleOpPhase(
|
||||||
name = "VerifyBitcode",
|
name = "VerifyBitcode",
|
||||||
description = "Verify bitcode",
|
description = "Verify bitcode",
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.backend.konan.optimizations
|
||||||
|
|
||||||
|
import llvm.*
|
||||||
|
import org.jetbrains.kotlin.backend.common.LoggingContext
|
||||||
|
import org.jetbrains.kotlin.backend.konan.llvm.getBasicBlocks
|
||||||
|
import org.jetbrains.kotlin.backend.konan.llvm.getFunctions
|
||||||
|
import org.jetbrains.kotlin.backend.konan.llvm.getInstructions
|
||||||
|
import org.jetbrains.kotlin.backend.konan.llvm.name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all Kotlin_mm_safePointFunctionPrologue from basic block except the first one.
|
||||||
|
*
|
||||||
|
* Currently, this pass is useful only for watchos_arm32, ios_arm32 targets because Kotlin_mm_* functions are marked
|
||||||
|
* as noinline there.
|
||||||
|
*/
|
||||||
|
class RemoveRedundantSafepointsPass(
|
||||||
|
private val loggingContext: LoggingContext
|
||||||
|
) {
|
||||||
|
var totalPrologueSafepointsCount = 0
|
||||||
|
var removedPrologueSafepointsCount = 0
|
||||||
|
|
||||||
|
fun runOnFunction(function: LLVMValueRef) {
|
||||||
|
getBasicBlocks(function).forEach { bb ->
|
||||||
|
val unnecessaryPrologueSafepointCallsites = getInstructions(bb)
|
||||||
|
.filter { isPrologueSafepointCallsite(it) }
|
||||||
|
.onEach { totalPrologueSafepointsCount += 1 }
|
||||||
|
.drop(1)
|
||||||
|
.toList()
|
||||||
|
unnecessaryPrologueSafepointCallsites.forEach {
|
||||||
|
LLVMInstructionEraseFromParent(it)
|
||||||
|
removedPrologueSafepointsCount += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isPrologueSafepointCallsite(insn: LLVMValueRef): Boolean =
|
||||||
|
(LLVMIsACallInst(insn) != null || LLVMIsAInvokeInst(insn) != null)
|
||||||
|
&& LLVMGetCalledValue(insn)?.name == prologueSafepointFunctionName
|
||||||
|
|
||||||
|
fun runOnModule(module: LLVMModuleRef) {
|
||||||
|
totalPrologueSafepointsCount = 0
|
||||||
|
removedPrologueSafepointsCount = 0
|
||||||
|
getFunctions(module)
|
||||||
|
.filter { it.name?.startsWith("kfun:") == true }
|
||||||
|
.filterNot { LLVMIsDeclaration(it) == 1 }
|
||||||
|
.forEach(this::runOnFunction)
|
||||||
|
loggingContext.log {
|
||||||
|
"""
|
||||||
|
Total prologue safepoints: $totalPrologueSafepointsCount
|
||||||
|
Removed prologue safepoints: $removedPrologueSafepointsCount
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val prologueSafepointFunctionName = "Kotlin_mm_safePointFunctionPrologue"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user