[K/N] Better removing of extra safepoints
This commit is contained in:
+7
-2
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
import llvm.*
|
import llvm.*
|
||||||
|
import org.jetbrains.kotlin.backend.common.LoggingContext
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.KonanIr
|
import org.jetbrains.kotlin.backend.konan.ir.KonanIr
|
||||||
import org.jetbrains.kotlin.library.SerializedMetadata
|
import org.jetbrains.kotlin.library.SerializedMetadata
|
||||||
@@ -457,6 +458,10 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
|||||||
fun shouldUseDebugInfoFromNativeLibs() = shouldContainAnyDebugInfo() && config.useDebugInfoInNativeLibs
|
fun shouldUseDebugInfoFromNativeLibs() = shouldContainAnyDebugInfo() && config.useDebugInfoInNativeLibs
|
||||||
|
|
||||||
fun shouldOptimize() = config.optimizationsEnabled
|
fun shouldOptimize() = config.optimizationsEnabled
|
||||||
|
fun shouldInlineSafepoints() = when {
|
||||||
|
config.target.family.isAppleFamily -> config.target.architecture != Architecture.ARM32 // disable for watchos_arm32 and similar
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
fun ghaEnabled() = ::globalHierarchyAnalysisResult.isInitialized
|
fun ghaEnabled() = ::globalHierarchyAnalysisResult.isInitialized
|
||||||
fun useLazyFileInitializers() = config.propertyLazyInitialization
|
fun useLazyFileInitializers() = config.propertyLazyInitialization
|
||||||
|
|
||||||
@@ -530,11 +535,11 @@ private fun MemberScope.getContributedClassifier(name: String) =
|
|||||||
private fun MemberScope.getContributedFunctions(name: String) =
|
private fun MemberScope.getContributedFunctions(name: String) =
|
||||||
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
|
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
|
||||||
|
|
||||||
internal class ContextLogger(val context: Context) {
|
internal class ContextLogger(val context: LoggingContext) {
|
||||||
operator fun String.unaryPlus() = context.log { this }
|
operator fun String.unaryPlus() = context.log { this }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Context.logMultiple(messageBuilder: ContextLogger.() -> Unit) {
|
internal fun LoggingContext.logMultiple(messageBuilder: ContextLogger.() -> Unit) {
|
||||||
if (!inVerbosePhase) return
|
if (!inVerbosePhase) return
|
||||||
with(ContextLogger(this)) { messageBuilder() }
|
with(ContextLogger(this)) { messageBuilder() }
|
||||||
}
|
}
|
||||||
+5
-4
@@ -390,11 +390,12 @@ internal val produceOutputPhase = namedUnitPhase(
|
|||||||
|
|
||||||
internal val removeRedundantSafepointsPhase = makeKonanModuleOpPhase(
|
internal val removeRedundantSafepointsPhase = makeKonanModuleOpPhase(
|
||||||
name = "RemoveRedundantSafepoints",
|
name = "RemoveRedundantSafepoints",
|
||||||
description = "Leave only one safepoint in a basic block",
|
description = "Remove function prologue safepoints inlined to another function",
|
||||||
op = { context, _ ->
|
op = { context, _ ->
|
||||||
if (context.config.target.architecture == Architecture.ARM32 && context.config.target.family.isAppleFamily) {
|
RemoveRedundantSafepointsPass(context).runOnModule(
|
||||||
RemoveRedundantSafepointsPass(context as LoggingContext).runOnModule(context.llvmModule!!)
|
module = context.llvmModule!!,
|
||||||
}
|
isSafepointInliningAllowed = context.shouldInlineSafepoints()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+31
-18
@@ -7,34 +7,50 @@ package org.jetbrains.kotlin.backend.konan.optimizations
|
|||||||
|
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.common.LoggingContext
|
import org.jetbrains.kotlin.backend.common.LoggingContext
|
||||||
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.getBasicBlocks
|
import org.jetbrains.kotlin.backend.konan.llvm.getBasicBlocks
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.getFunctions
|
import org.jetbrains.kotlin.backend.konan.llvm.getFunctions
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.getInstructions
|
import org.jetbrains.kotlin.backend.konan.llvm.getInstructions
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.name
|
import org.jetbrains.kotlin.backend.konan.logMultiple
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all Kotlin_mm_safePointFunctionPrologue from basic block except the first one.
|
* Removes all Kotlin_mm_safePointFunctionPrologue from basic block except the first one.
|
||||||
*
|
* Also, if first basic block in function contains call to Kotlin_mm_safePointFunctionPrologue, all other calls would be removed.
|
||||||
* Currently, this pass is useful only for watchos_arm32, ios_arm32 targets because Kotlin_mm_* functions are marked
|
* Also, calls, which are not removed are inlined (except arm32 apple targets)
|
||||||
* as noinline there.
|
|
||||||
*/
|
*/
|
||||||
class RemoveRedundantSafepointsPass(
|
internal class RemoveRedundantSafepointsPass(
|
||||||
private val loggingContext: LoggingContext
|
private val loggingContext: LoggingContext
|
||||||
) {
|
) {
|
||||||
var totalPrologueSafepointsCount = 0
|
var totalPrologueSafepointsCount = 0
|
||||||
var removedPrologueSafepointsCount = 0
|
var removedPrologueSafepointsCount = 0
|
||||||
|
|
||||||
fun runOnFunction(function: LLVMValueRef) {
|
fun runOnFunction(function: LLVMValueRef, isSafepointInliningAllowed: Boolean) {
|
||||||
|
val firstBlock = LLVMGetFirstBasicBlock(function) ?: return
|
||||||
|
val firstBlockHasSafepoint = getInstructions(firstBlock).any { isPrologueSafepointCallsite(it) }
|
||||||
getBasicBlocks(function).forEach { bb ->
|
getBasicBlocks(function).forEach { bb ->
|
||||||
val unnecessaryPrologueSafepointCallsites = getInstructions(bb)
|
val removeFirst = firstBlockHasSafepoint && bb != firstBlock
|
||||||
|
val prologueSafepointCallsites = getInstructions(bb)
|
||||||
.filter { isPrologueSafepointCallsite(it) }
|
.filter { isPrologueSafepointCallsite(it) }
|
||||||
.onEach { totalPrologueSafepointsCount += 1 }
|
|
||||||
.drop(1)
|
|
||||||
.toList()
|
.toList()
|
||||||
unnecessaryPrologueSafepointCallsites.forEach {
|
totalPrologueSafepointsCount += prologueSafepointCallsites.size
|
||||||
|
prologueSafepointCallsites.drop(if (removeFirst) 0 else 1).forEach {
|
||||||
LLVMInstructionEraseFromParent(it)
|
LLVMInstructionEraseFromParent(it)
|
||||||
removedPrologueSafepointsCount += 1
|
removedPrologueSafepointsCount += 1
|
||||||
}
|
}
|
||||||
|
if (!removeFirst && isSafepointInliningAllowed) {
|
||||||
|
prologueSafepointCallsites
|
||||||
|
.firstOrNull()
|
||||||
|
?.apply {
|
||||||
|
if (LLVMIsDeclaration(LLVMGetCalledValue(this)) == 0) {
|
||||||
|
if (LLVMInlineCall(this) == 0) {
|
||||||
|
loggingContext.logMultiple {
|
||||||
|
+"Failed to Inline safepoint to ${function.name}"
|
||||||
|
+llvm2string(function)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,18 +58,15 @@ class RemoveRedundantSafepointsPass(
|
|||||||
(LLVMIsACallInst(insn) != null || LLVMIsAInvokeInst(insn) != null)
|
(LLVMIsACallInst(insn) != null || LLVMIsAInvokeInst(insn) != null)
|
||||||
&& LLVMGetCalledValue(insn)?.name == prologueSafepointFunctionName
|
&& LLVMGetCalledValue(insn)?.name == prologueSafepointFunctionName
|
||||||
|
|
||||||
fun runOnModule(module: LLVMModuleRef) {
|
fun runOnModule(module: LLVMModuleRef, isSafepointInliningAllowed: Boolean) {
|
||||||
totalPrologueSafepointsCount = 0
|
totalPrologueSafepointsCount = 0
|
||||||
removedPrologueSafepointsCount = 0
|
removedPrologueSafepointsCount = 0
|
||||||
getFunctions(module)
|
getFunctions(module)
|
||||||
.filter { it.name?.startsWith("kfun:") == true }
|
|
||||||
.filterNot { LLVMIsDeclaration(it) == 1 }
|
.filterNot { LLVMIsDeclaration(it) == 1 }
|
||||||
.forEach(this::runOnFunction)
|
.forEach { runOnFunction(it, isSafepointInliningAllowed) }
|
||||||
loggingContext.log {
|
loggingContext.logMultiple {
|
||||||
"""
|
+"Total prologue safepoints: $totalPrologueSafepointsCount"
|
||||||
Total prologue safepoints: $totalPrologueSafepointsCount
|
+"Removed prologue safepoints: $removedPrologueSafepointsCount"
|
||||||
Removed prologue safepoints: $removedPrologueSafepointsCount
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <llvm/IR/Instructions.h>
|
#include <llvm/IR/Instructions.h>
|
||||||
#include <llvm/IR/LegacyPassManager.h>
|
#include <llvm/IR/LegacyPassManager.h>
|
||||||
#include <llvm/Transforms/ObjCARC.h>
|
#include <llvm/Transforms/ObjCARC.h>
|
||||||
|
#include <llvm/Transforms/Utils/Cloning.h>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
@@ -47,3 +48,8 @@ void LLVMKotlinInitializeTargets() {
|
|||||||
void LLVMSetNoTailCall(LLVMValueRef Call) {
|
void LLVMSetNoTailCall(LLVMValueRef Call) {
|
||||||
unwrap<CallInst>(Call)->setTailCallKind(CallInst::TCK_NoTail);
|
unwrap<CallInst>(Call)->setTailCallKind(CallInst::TCK_NoTail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LLVMInlineCall(LLVMValueRef call) {
|
||||||
|
InlineFunctionInfo IFI;
|
||||||
|
return InlineFunction(*unwrap<CallBase>(call), IFI).isSuccess();
|
||||||
|
}
|
||||||
@@ -23,6 +23,8 @@ void LLVMKotlinInitializeTargets();
|
|||||||
|
|
||||||
void LLVMSetNoTailCall(LLVMValueRef Call);
|
void LLVMSetNoTailCall(LLVMValueRef Call);
|
||||||
|
|
||||||
|
int LLVMInlineCall(LLVMValueRef call);
|
||||||
|
|
||||||
# ifdef __cplusplus
|
# ifdef __cplusplus
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
@@ -586,7 +586,8 @@ extern "C" void CheckGlobalsAccessible() {
|
|||||||
// Always accessible
|
// Always accessible
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" RUNTIME_NOTHROW CODEGEN_INLINE_POLICY void Kotlin_mm_safePointFunctionPrologue() {
|
// it would be inlined manually in RemoveRedundantSafepointsPass
|
||||||
|
extern "C" RUNTIME_NOTHROW NO_INLINE void Kotlin_mm_safePointFunctionPrologue() {
|
||||||
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
|
||||||
AssertThreadState(threadData, ThreadState::kRunnable);
|
AssertThreadState(threadData, ThreadState::kRunnable);
|
||||||
threadData->gc().SafePointFunctionPrologue();
|
threadData->gc().SafePointFunctionPrologue();
|
||||||
|
|||||||
Reference in New Issue
Block a user