[IR] Run lowerings before the inliner on all inline functions

Since inlining is a cross-module operation (we need to know the bodies of
inline functions), all lowerings that are supposed to run before the inliner,
need to be run on all inline functions.
This commit is contained in:
Igor Chevdar
2020-04-06 18:47:36 +03:00
parent c11bf26d97
commit 92cdf24d48
10 changed files with 140 additions and 11 deletions
@@ -66,6 +66,8 @@ internal class SpecialDeclarationsFactory(val context: Context) {
private val loweredEnums = mutableMapOf<IrClass, LoweredEnum>() private val loweredEnums = mutableMapOf<IrClass, LoweredEnum>()
private val ordinals = mutableMapOf<ClassDescriptor, Map<ClassDescriptor, Int>>() private val ordinals = mutableMapOf<ClassDescriptor, Map<ClassDescriptor, Int>>()
val loweredInlineFunctions = mutableSetOf<IrFunction>()
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS : object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS") IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
@@ -131,7 +131,7 @@ internal val extractLocalClassesFromInlineBodies = namedIrModulePhase(
internal val inlinePhase = namedIrModulePhase( internal val inlinePhase = namedIrModulePhase(
lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> { lower = object : SameTypeCompilerPhase<Context, IrModuleFragment> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment): IrModuleFragment { override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<IrModuleFragment>, context: Context, input: IrModuleFragment): IrModuleFragment {
FunctionInlining(context).run { FunctionInlining(context, NativeInlineFunctionResolver(context)).run {
input.files.forEach { lower(it) } input.files.forEach { lower(it) }
} }
return input return input
@@ -25,11 +25,7 @@ import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.addFile
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
@@ -320,6 +316,7 @@ internal val linkerPhase = konanUnitPhase(
internal val allLoweringsPhase = namedIrModulePhase( internal val allLoweringsPhase = namedIrModulePhase(
name = "IrLowering", name = "IrLowering",
description = "IR Lowering", description = "IR Lowering",
// TODO: The lowerings before inlinePhase should be aligned with [NativeInlineFunctionResolver.kt]
lower = removeExpectDeclarationsPhase then lower = removeExpectDeclarationsPhase then
stripTypeAliasDeclarationsPhase then stripTypeAliasDeclarationsPhase then
lowerBeforeInlinePhase then lowerBeforeInlinePhase then
@@ -392,6 +389,7 @@ internal val dependenciesLowerPhase = SameTypeNamedPhaseWrapper(
?: return@forEach ?: return@forEach
input.files += libModule.files input.files += libModule.files
} }
input.files += files input.files += files
return input return input
@@ -0,0 +1,56 @@
/*
* 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.lower
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.inline.DefaultInlineFunctionResolver
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesExtractionFromInlineFunctionsLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineFunctionsLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineLambdasLowering
import org.jetbrains.kotlin.backend.common.runPostfix
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.dump
// TODO: This is a bit hacky. Think about adopting persistent IR ideas.
internal class NativeInlineFunctionResolver(override val context: Context) : DefaultInlineFunctionResolver(context) {
override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
val function = super.getFunctionDeclaration(symbol)
val body = function.body ?: return function
if (function in context.specialDeclarationsFactory.loweredInlineFunctions)
return function
context.specialDeclarationsFactory.loweredInlineFunctions.add(function)
PreInlineLowering(context).lower(body, function)
ArrayConstructorLowering(context).lower(body, function)
NullableFieldsForLateinitCreationLowering(context).lowerWithLocalDeclarations(function)
NullableFieldsDeclarationLowering(context).lowerWithLocalDeclarations(function)
LateinitUsageLowering(context).lower(body, function)
SharedVariablesLowering(context).lower(body, function)
LocalClassesInInlineLambdasLowering(context).lower(body, function)
if (context.llvmModuleSpecification.containsDeclaration(function)) {
// Do not extract local classes off of inline functions from cached libraries.
LocalClassesInInlineFunctionsLowering(context).lower(body, function)
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, function)
}
return function
}
private fun DeclarationTransformer.lowerWithLocalDeclarations(function: IrFunction) {
if (runPostfix(true).transformFlat(function) != null)
error("Unexpected transformation of function ${function.dump()}")
}
}
@@ -5,11 +5,12 @@
package org.jetbrains.kotlin.backend.konan.lower package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
@@ -20,15 +21,15 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
* This pass runs before inlining and performs the following additional transformations over some operations: * This pass runs before inlining and performs the following additional transformations over some operations:
* - Assertion call removal. * - Assertion call removal.
*/ */
internal class PreInlineLowering(val context: Context) : FileLoweringPass { internal class PreInlineLowering(val context: Context) : BodyLoweringPass {
private val symbols get() = context.ir.symbols private val symbols get() = context.ir.symbols
private val asserts = symbols.asserts private val asserts = symbols.asserts
private val enableAssertions = context.config.configuration.getBoolean(KonanConfigKeys.ENABLE_ASSERTIONS) private val enableAssertions = context.config.configuration.getBoolean(KonanConfigKeys.ENABLE_ASSERTIONS)
override fun lower(irFile: IrFile) { override fun lower(irBody: IrBody, container: IrDeclaration) {
irFile.transformChildrenVoid(object : IrBuildingTransformer(context) { irBody.transformChildrenVoid(object : IrBuildingTransformer(context) {
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
+12
View File
@@ -3302,6 +3302,18 @@ linkTest("inline_defaultArgs_linkTest") {
lib = "codegen/inline/defaultArgs_linkTest_lib.kt" lib = "codegen/inline/defaultArgs_linkTest_lib.kt"
} }
linkTest("inline_sharedVar_linkTest") {
goldValue = "6\n"
source = "codegen/inline/sharedVar_linkTest_main.kt"
lib = "codegen/inline/sharedVar_linkTest_lib.kt"
}
linkTest("inline_lateinitProperty_linkTest") {
goldValue = "OK\n"
source = "codegen/inline/lateinitProperty_linkTest_main.kt"
lib = "codegen/inline/lateinitProperty_linkTest_lib.kt"
}
def generateWithSpaceDefFile() { def generateWithSpaceDefFile() {
def mapOption = "--Map \"${buildDir}/cutom map.map\"" def mapOption = "--Map \"${buildDir}/cutom map.map\""
if (isAppleTarget(project)) { if (isAppleTarget(project)) {
@@ -0,0 +1,19 @@
/*
* 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 a
fun IntArray.forEachNoInline(block: (Int) -> Unit) = this.forEach { block(it) }
inline fun foo(values: IntArray, crossinline block: (Int, Int, Int) -> Int): Int {
val o = object {
lateinit var s: String
var x: Int = 42
}
values.forEachNoInline {
o.x = block(o.x, o.s.length, it)
}
return o.x
}
@@ -0,0 +1,15 @@
/*
* 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.
*/
import a.*
fun main() {
try {
val res = foo(intArrayOf(1, 2, 3)) { x, y, z -> x + y - z }
println(res)
} catch (t: UninitializedPropertyAccessException) {
println("OK")
}
}
@@ -0,0 +1,16 @@
/*
* 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 a
fun IntArray.forEachNoInline(block: (Int) -> Unit) = this.forEach { block(it) }
inline fun fold(initial: Int, values: IntArray, crossinline block: (Int, Int) -> Int): Int {
var res = initial
values.forEachNoInline {
res = block(res, it)
}
return res
}
@@ -0,0 +1,10 @@
/*
* 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.
*/
import a.*
fun main() {
println(fold(0, intArrayOf(1, 2, 3)) { x, y -> x + y })
}