[K/N][IR] Made the compiler pipeline to do per file lowerings

This commit is contained in:
Igor Chevdar
2021-09-23 12:04:33 +05:00
parent d3a7aefe36
commit af09fb51ac
5 changed files with 138 additions and 126 deletions
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.konan
import llvm.*
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.KonanIr
import org.jetbrains.kotlin.library.SerializedMetadata
@@ -47,6 +48,7 @@ import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker
import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.name.FqName
@@ -57,7 +59,7 @@ import org.jetbrains.kotlin.konan.util.disposeNativeMemoryAllocator
import org.jetbrains.kotlin.library.SerializedIrModule
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
internal class InlineFunctionOriginInfo(val irFile: IrFile, val startOffset: Int, val endOffset: Int)
internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
/**
* Offset for synthetic elements created by lowerings and not attributable to other places in the source code.
@@ -73,7 +75,13 @@ internal class SpecialDeclarationsFactory(val context: Context) {
private val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>()
private val notLoweredInlineFunctions = mutableMapOf<IrFunctionSymbol, IrFunction>()
val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
fun getNonLoweredInlineFunction(function: IrFunction): IrFunction {
return notLoweredInlineFunctions.getOrPut(function.symbol) {
function.deepCopyWithVariables().also { it.patchDeclarationParents(function.parent) }
}
}
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
@@ -22,8 +22,12 @@ import org.jetbrains.kotlin.backend.konan.lower.*
import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering
import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering
import org.jetbrains.kotlin.backend.konan.optimizations.KonanBCEForLoopBodyTransformer
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
private val validateAll = false
@@ -89,13 +93,21 @@ internal val specialBackendChecksPhase = konanUnitPhase(
description = "Special backend checks"
)
internal val removeExpectDeclarationsPhase = makeKonanModuleLoweringPhase(
internal val propertyAccessorInlinePhase = makeKonanModuleLoweringPhase(
::PropertyAccessorInlineLowering,
name = "PropertyAccessorInline",
description = "Property accessor inline lowering"
)
/* IrFile phases */
internal val removeExpectDeclarationsPhase = makeKonanFileLoweringPhase(
::ExpectDeclarationsRemoving,
name = "RemoveExpectDeclarations",
description = "Expect declarations removing"
)
internal val stripTypeAliasDeclarationsPhase = makeKonanModuleLoweringPhase(
internal val stripTypeAliasDeclarationsPhase = makeKonanFileLoweringPhase(
{ StripTypeAliasDeclarationsLowering() },
name = "StripTypeAliasDeclarations",
description = "Strip typealias declarations"
@@ -107,102 +119,90 @@ internal val annotationImplementationPhase = makeKonanFileLoweringPhase(
description = "Create synthetic annotations implementations and use them in annotations constructor calls"
)
internal val lowerBeforeInlinePhase = makeKonanModuleLoweringPhase(
internal val lowerBeforeInlinePhase = makeKonanFileLoweringPhase(
::PreInlineLowering,
name = "LowerBeforeInline",
description = "Special operations processing before inlining"
)
internal val arrayConstructorPhase = makeKonanModuleLoweringPhase(
internal val arrayConstructorPhase = makeKonanFileLoweringPhase(
::ArrayConstructorLowering,
name = "ArrayConstructor",
description = "Transform `Array(size) { index -> value }` into a loop"
)
internal val lateinitPhase = makeKonanModuleOpPhase(
{ context, irModule ->
NullableFieldsForLateinitCreationLowering(context).lower(irModule)
NullableFieldsDeclarationLowering(context).lower(irModule)
LateinitUsageLowering(context).lower(irModule)
internal val lateinitPhase = makeKonanFileOpPhase(
{ context, irFile ->
NullableFieldsForLateinitCreationLowering(context).lower(irFile)
NullableFieldsDeclarationLowering(context).lower(irFile)
LateinitUsageLowering(context).lower(irFile)
},
name = "Lateinit",
description = "Lateinit properties lowering"
)
internal val propertyAccessorInlinePhase = makeKonanModuleLoweringPhase(
::PropertyAccessorInlineLowering,
name = "PropertyAccessorInline",
description = "Property accessor inline lowering"
)
internal val sharedVariablesPhase = makeKonanModuleLoweringPhase(
internal val sharedVariablesPhase = makeKonanFileLoweringPhase(
::SharedVariablesLowering,
name = "SharedVariables",
description = "Shared variable lowering",
prerequisite = setOf(lateinitPhase)
)
internal val inventNamesForLocalClasses = makeKonanModuleLoweringPhase(
::NativeInventNamesForLocalClasses,
internal val inventNamesForLocalClasses = makeKonanFileLoweringPhase(
{ NativeInventNamesForLocalClasses(it) },
name = "InventNamesForLocalClasses",
description = "Invent names for local classes and anonymous objects"
)
internal val extractLocalClassesFromInlineBodies = NamedCompilerPhase(
lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment): IrModuleFragment {
LocalClassesInInlineLambdasLowering(context).run {
input.files.forEach { lower(it) }
}
LocalClassesInInlineFunctionsLowering(context).run {
input.files.forEach { lower(it) }
}
LocalClassesExtractionFromInlineFunctionsLowering(context).run {
input.files.forEach { lower(it) }
}
return input
}
internal val extractLocalClassesFromInlineBodies = makeKonanFileOpPhase(
{ context, irFile ->
LocalClassesInInlineLambdasLowering(context).lower(irFile)
LocalClassesInInlineFunctionsLowering(context).lower(irFile)
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(irFile)
},
name = "ExtractLocalClassesFromInlineBodies",
description = "Extraction of local classes from inline bodies",
prerequisite = setOf(sharedVariablesPhase), // TODO: add "soft" dependency on inventNamesForLocalClasses
nlevels = 0,
actions = modulePhaseActions
)
internal val inlinePhase = NamedCompilerPhase(
lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment): IrModuleFragment {
FunctionInlining(context, NativeInlineFunctionResolver(context)).run {
input.files.forEach { lower(it) }
internal val inlinePhase = makeKonanFileOpPhase(
{ context, irFile ->
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
return input
}
override fun visitFunction(declaration: IrFunction) {
if (declaration.isInline)
context.specialDeclarationsFactory.getNonLoweredInlineFunction(declaration)
declaration.acceptChildrenVoid(this)
}
})
FunctionInlining(context, NativeInlineFunctionResolver(context)).lower(irFile)
},
name = "Inline",
description = "Functions inlining",
prerequisite = setOf(lowerBeforeInlinePhase, arrayConstructorPhase, extractLocalClassesFromInlineBodies),
nlevels = 0,
actions = modulePhaseActions
prerequisite = setOf(lowerBeforeInlinePhase, arrayConstructorPhase, extractLocalClassesFromInlineBodies)
)
internal val lowerAfterInlinePhase = makeKonanModuleOpPhase(
{ context, irModule ->
irModule.files.forEach(PostInlineLowering(context)::lower)
// TODO: Seems like this should be deleted in PsiToIR.
irModule.files.forEach(ContractsDslRemover(context)::lower)
},
name = "LowerAfterInline",
description = "Special operations processing after inlining"
internal val postInlinePhase = makeKonanFileLoweringPhase(
{ PostInlineLowering(it) },
name = "PostInline",
description = "Post-processing after inlining"
)
/* IrFile phases */
internal val contractsDslRemovePhase = makeKonanFileLoweringPhase(
{ ContractsDslRemover(it) },
name = "RemoveContractsDsl",
description = "Contracts dsl removing"
)
// TODO make all lambda-related stuff work with IrFunctionExpression and drop this phase (see kotlin: dd3f8ecaacd)
internal val provisionalFunctionExpressionPhase = makeKonanModuleLoweringPhase(
{ ProvisionalFunctionExpressionLowering() },
name = "FunctionExpression-before-inliner",
description = "Transform IrFunctionExpression to a local function reference"
internal val provisionalFunctionExpressionPhase = makeKonanFileLoweringPhase(
{ ProvisionalFunctionExpressionLowering() },
name = "FunctionExpression",
description = "Transform IrFunctionExpression to a local function reference"
)
internal val flattenStringConcatenationPhase = makeKonanFileLoweringPhase(
@@ -256,56 +256,57 @@ internal val allLoweringsPhase = NamedCompilerPhase(
name = "IrLowering",
description = "IR Lowering",
// TODO: The lowerings before inlinePhase should be aligned with [NativeInlineFunctionResolver.kt]
lower = removeExpectDeclarationsPhase then
stripTypeAliasDeclarationsPhase then
lowerBeforeInlinePhase then
arrayConstructorPhase then
lateinitPhase then
sharedVariablesPhase then
inventNamesForLocalClasses then
extractLocalClassesFromInlineBodies then
inlinePhase then
provisionalFunctionExpressionPhase then
lowerAfterInlinePhase then
performByIrFile(
name = "IrLowerByFile",
description = "IR Lowering by file",
lower = listOf(
annotationImplementationPhase,
rangeContainsLoweringPhase,
forLoopsPhase,
flattenStringConcatenationPhase,
foldConstantLoweringPhase,
computeStringTrimPhase,
stringConcatenationPhase,
enumConstructorsPhase,
initializersPhase,
localFunctionsPhase,
tailrecPhase,
defaultParameterExtentPhase,
innerClassPhase,
dataClassesPhase,
ifNullExpressionsFusionPhase,
testProcessorPhase,
delegationPhase,
functionReferencePhase,
singleAbstractMethodPhase,
enumWhenPhase,
builtinOperatorPhase,
finallyBlocksPhase,
enumClassPhase,
enumUsagePhase,
interopPhase,
varargPhase,
kotlinNothingValueExceptionPhase,
coroutinesPhase,
typeOperatorPhase,
expressionBodyTransformPhase,
fileInitializersPhase,
bridgesPhase,
autoboxPhase,
)
),
lower = performByIrFile(
name = "IrLowerByFile",
description = "IR Lowering by file",
lower = listOf(
removeExpectDeclarationsPhase,
stripTypeAliasDeclarationsPhase,
lowerBeforeInlinePhase,
arrayConstructorPhase,
lateinitPhase,
sharedVariablesPhase,
inventNamesForLocalClasses,
extractLocalClassesFromInlineBodies,
inlinePhase,
provisionalFunctionExpressionPhase,
postInlinePhase,
contractsDslRemovePhase,
annotationImplementationPhase,
rangeContainsLoweringPhase,
forLoopsPhase,
flattenStringConcatenationPhase,
foldConstantLoweringPhase,
computeStringTrimPhase,
stringConcatenationPhase,
enumConstructorsPhase,
initializersPhase,
localFunctionsPhase,
tailrecPhase,
defaultParameterExtentPhase,
innerClassPhase,
dataClassesPhase,
ifNullExpressionsFusionPhase,
testProcessorPhase,
delegationPhase,
functionReferencePhase,
singleAbstractMethodPhase,
enumWhenPhase,
builtinOperatorPhase,
finallyBlocksPhase,
enumClassPhase,
enumUsagePhase,
interopPhase,
varargPhase,
kotlinNothingValueExceptionPhase,
coroutinesPhase,
typeOperatorPhase,
expressionBodyTransformPhase,
fileInitializersPhase,
bridgesPhase,
autoboxPhase,
)
),
actions = setOf(defaultDumper, ::moduleValidationCallback)
)
@@ -26,44 +26,46 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
val function = super.getFunctionDeclaration(symbol)
if (function in context.specialDeclarationsFactory.loweredInlineFunctions)
return function
context.specialDeclarationsFactory.loweredInlineFunctions[function]?.let { return it.irFunction }
val packageFragment = function.findPackage()
if (packageFragment !is IrExternalPackageFragment) {
context.specialDeclarationsFactory.loweredInlineFunctions[function] =
InlineFunctionOriginInfo(function.file, function.startOffset, function.endOffset)
val notLoweredFunction = if (packageFragment !is IrExternalPackageFragment) {
context.specialDeclarationsFactory.getNonLoweredInlineFunction(function).also {
context.specialDeclarationsFactory.loweredInlineFunctions[function] =
InlineFunctionOriginInfo(it, function.file, function.startOffset, function.endOffset)
}
} else {
// The function is from Lazy IR, get its body from the IR linker.
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
val moduleDeserializer = context.irLinker.cachedLibraryModuleDeserializers[moduleDescriptor]
?: error("No module deserializer for ${function.render()}")
context.specialDeclarationsFactory.loweredInlineFunctions[function] = moduleDeserializer.deserializeInlineFunction(function)
function
}
val body = function.body ?: return function
val body = notLoweredFunction.body ?: return notLoweredFunction
PreInlineLowering(context).lower(body, function, context.specialDeclarationsFactory.loweredInlineFunctions[function]!!.irFile)
PreInlineLowering(context).lower(body, notLoweredFunction, context.specialDeclarationsFactory.loweredInlineFunctions[function]!!.irFile)
ArrayConstructorLowering(context).lower(body, function)
ArrayConstructorLowering(context).lower(body, notLoweredFunction)
NullableFieldsForLateinitCreationLowering(context).lowerWithLocalDeclarations(function)
NullableFieldsDeclarationLowering(context).lowerWithLocalDeclarations(function)
LateinitUsageLowering(context).lower(body, function)
NullableFieldsForLateinitCreationLowering(context).lowerWithLocalDeclarations(notLoweredFunction)
NullableFieldsDeclarationLowering(context).lowerWithLocalDeclarations(notLoweredFunction)
LateinitUsageLowering(context).lower(body, notLoweredFunction)
SharedVariablesLowering(context).lower(body, function)
SharedVariablesLowering(context).lower(body, notLoweredFunction)
OuterThisLowering(context).lower(function)
OuterThisLowering(context).lower(notLoweredFunction)
LocalClassesInInlineLambdasLowering(context).lower(body, function)
LocalClassesInInlineLambdasLowering(context).lower(body, notLoweredFunction)
if (context.llvmModuleSpecification.containsPackageFragment(packageFragment)) {
// Do not extract local classes off of inline functions from cached libraries.
LocalClassesInInlineFunctionsLowering(context).lower(body, function)
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, function)
LocalClassesInInlineFunctionsLowering(context).lower(body, notLoweredFunction)
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, notLoweredFunction)
}
return function
return notLoweredFunction
}
private fun DeclarationTransformer.lowerWithLocalDeclarations(function: IrFunction) {
@@ -711,6 +711,7 @@ internal class KonanIrLinker(
if (function.parents.any { (it as? IrFunction)?.isInline == true}) {
// Already deserialized by the top-most inline function.
return InlineFunctionOriginInfo(
function,
inlineFunctionFiles[packageFragment]
?: error("${function.render()} should've been deserialized along with its parent"),
function.startOffset, function.endOffset
@@ -777,7 +778,7 @@ internal class KonanIrLinker(
}
inlineFunctionFiles[packageFragment] = fileDeserializationInfo.file
return InlineFunctionOriginInfo(fileDeserializationInfo.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset)
return InlineFunctionOriginInfo(function, fileDeserializationInfo.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset)
}
private val classesFields by lazy {