[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 ordinals = mutableMapOf<ClassDescriptor, Map<ClassDescriptor, Int>>()
val loweredInlineFunctions = mutableSetOf<IrFunction>()
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
@@ -131,7 +131,7 @@ internal val extractLocalClassesFromInlineBodies = namedIrModulePhase(
internal val inlinePhase = namedIrModulePhase(
lower = object : SameTypeCompilerPhase<Context, 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) }
}
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.IrModuleFragment
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
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.util.*
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
@@ -320,6 +316,7 @@ internal val linkerPhase = konanUnitPhase(
internal val allLoweringsPhase = namedIrModulePhase(
name = "IrLowering",
description = "IR Lowering",
// TODO: The lowerings before inlinePhase should be aligned with [NativeInlineFunctionResolver.kt]
lower = removeExpectDeclarationsPhase then
stripTypeAliasDeclarationsPhase then
lowerBeforeInlinePhase then
@@ -392,6 +389,7 @@ internal val dependenciesLowerPhase = SameTypeNamedPhaseWrapper(
?: return@forEach
input.files += libModule.files
}
input.files += files
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
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.konan.Context
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.IrExpression
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:
* - 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 asserts = symbols.asserts
private val enableAssertions = context.config.configuration.getBoolean(KonanConfigKeys.ENABLE_ASSERTIONS)
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object : IrBuildingTransformer(context) {
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transformChildrenVoid(object : IrBuildingTransformer(context) {
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
+12
View File
@@ -3302,6 +3302,18 @@ linkTest("inline_defaultArgs_linkTest") {
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 mapOption = "--Map \"${buildDir}/cutom map.map\""
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 })
}