[K/N] Run inline property accessors later to inline all cases including devirtualized

This commit is contained in:
Elena Lepilkina
2021-09-13 17:34:17 +03:00
committed by Space
parent b32ab48596
commit bdb61ec5d7
5 changed files with 75 additions and 33 deletions
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.backend.common.ir.isPure
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -127,8 +128,14 @@ class PropertyAccessorInlineLowering(private val context: CommonBackendContext)
private fun isSimpleSetter(callee: IrSimpleFunction, backingField: IrField): Boolean {
val body = callee.body?.let { it as IrBlockBody } ?: return false
val stmt = body.statements.singleOrNull() ?: return false
val statementsSizeCheck = when (body.statements.size) {
1 -> true
// In K/N backend this lowering should be called after devirtualization. At this point IrReturns are already added.
2 -> (body.statements[1] as? IrReturn)?.value?.type?.isUnit() == true
else -> false
}
if (!statementsSizeCheck) return false
val stmt = body.statements[0]
val setFieldStmt = stmt as? IrSetField ?: return false
if (setFieldStmt.symbol !== backingField.symbol) return false
@@ -394,14 +394,15 @@ internal val bitcodePhase = NamedCompilerPhase(
name = "Bitcode",
description = "LLVM Bitcode generation",
lower = contextLLVMSetupPhase then
propertyAccessorInlinePhase then // Have to run after link dependencies phase, because fields
// from dependencies can be changed during lowerings.
returnsInsertionPhase then
buildDFGPhase then
devirtualizationAnalysisPhase then
dcePhase then
removeRedundantCallsToFileInitializersPhase then
devirtualizationPhase then
propertyAccessorInlinePhase then // Have to run after link dependencies phase, because fields
// from dependencies can be changed during lowerings.
inlineClassPropertyAccessorsPhase then
redundantCoercionsCleaningPhase then
createLLVMDeclarationsPhase then
ghaPhase then
@@ -493,6 +494,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
// Inline accessors only in optimized builds due to separate compilation and possibility to get broken
// debug information.
disableUnless(propertyAccessorInlinePhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
disableUnless(inlineClassPropertyAccessorsPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
disableUnless(dcePhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
disableUnless(removeRedundantCallsToFileInitializersPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
disableUnless(ghaPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.common.phaser.namedUnitPhase
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.GlobalHierarchyAnalysis
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
import org.jetbrains.kotlin.backend.konan.lower.InlineClassPropertyAccessorsLowering
import org.jetbrains.kotlin.backend.konan.lower.RedundantCoercionsCleaner
import org.jetbrains.kotlin.backend.konan.lower.ReturnsInsertionLowering
import org.jetbrains.kotlin.backend.konan.optimizations.*
@@ -121,6 +122,12 @@ internal val returnsInsertionPhase = makeKonanModuleOpPhase(
op = { context, irModule -> irModule.files.forEach { ReturnsInsertionLowering(context).lower(it) } }
)
internal val inlineClassPropertyAccessorsPhase = makeKonanModuleOpPhase(
name = "InlineClassPropertyAccessorsLowering",
description = "Inline class property accessors",
op = { context, irModule -> irModule.files.forEach { InlineClassPropertyAccessorsLowering(context).lower(it) } }
)
internal val devirtualizationAnalysisPhase = makeKonanModuleOpPhase(
name = "DevirtualizationAnalysis",
description = "Devirtualization analysis",
@@ -201,11 +208,6 @@ internal val dcePhase = makeKonanModuleOpPhase(
}
})
// TODO: Bridge function normally calls it's target, but it could be optimized out by Autoboxing and InlinePropertyAccessor
// lowerings. But Devirtualization doesn't handle this correctly, and can replace bridge call with call of it's target.
// So it's safer not to remove target if bridge is preserved, even if target itself is not called directly
referencedFunctions.addAll(referencedFunctions.mapNotNull { it.origin.safeAs<DECLARATION_ORIGIN_BRIDGE_METHOD>()?.bridgeTarget })
context.irModule!!.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitFile(declaration: IrFile): IrFile {
declaration.declarations.removeAll {
@@ -311,30 +311,6 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
return declaration
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
// Make replacement only in optimized builds due to separate compilation and possibility to get broken
// debug information.
if (!context.shouldOptimize())
return expression
val property = expression.symbol.owner.correspondingPropertySymbol?.owner ?: return expression
property.parent.let {
if (it is IrClass && it.isInline && property.backingField != null) {
expression.dispatchReceiver?.let { receiver ->
return builder.at(expression)
.irCall(symbols.reinterpret, expression.type, listOf(receiver.type, expression.type))
.apply {
extensionReceiver = receiver
}
}
}
}
return expression
}
private fun IrBuilderWithScope.irIsNull(expression: IrExpression): IrExpression {
val binary = expression.type.computeBinaryType()
return when (binary) {
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2021 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.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.visitors.*
/**
* Boxes and unboxes values of value types when necessary.
*/
internal class InlineClassPropertyAccessorsLowering(val context: Context) : FileLoweringPass {
private val transformer = InlineClassAccessorsTransformer(context)
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(transformer)
}
}
private class InlineClassAccessorsTransformer(private val context: Context) : IrBuildingTransformer(context) {
private val symbols = context.ir.symbols
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
val property = expression.symbol.owner.correspondingPropertySymbol?.owner ?: return expression
property.parent.let {
if (it is IrClass && it.isInline && property.backingField != null) {
expression.dispatchReceiver?.let { receiver ->
return builder.at(expression)
.irCall(symbols.reinterpret, expression.type, listOf(receiver.type, expression.type))
.apply {
extensionReceiver = receiver
}
}
}
}
return expression
}
}