Merge branch 'proper-inline' into inline
# Conflicts: # backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt # backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt # backend.native/tests/build.gradle # backend.native/tests/codegen/inline/inline5.kt # gradle.properties
This commit is contained in:
+3
-3
@@ -17,6 +17,9 @@ internal class KonanLower(val context: Context) {
|
||||
fun lower(irFile: IrFile) {
|
||||
val phaser = PhaseManager(context)
|
||||
|
||||
phaser.phase(KonanPhase.LOWER_INLINE) {
|
||||
FunctionInlining(context).inline(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_DEFAULT_PARAMETER_EXTENT) {
|
||||
DefaultParameterStubGenerator(context).runOnFilePostfix(irFile)
|
||||
DefaultParameterInjector(context).runOnFilePostfix(irFile)
|
||||
@@ -39,8 +42,5 @@ internal class KonanLower(val context: Context) {
|
||||
phaser.phase(KonanPhase.AUTOBOX) {
|
||||
Autoboxing(context).lower(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_INLINE) {
|
||||
FunctionInlining(context).inline(irFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -20,6 +20,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
var returnSlot: LLVMValueRef? = null
|
||||
var slotsPhi: LLVMValueRef? = null
|
||||
var slotCount = 0
|
||||
var functionDescriptor: FunctionDescriptor? = null
|
||||
|
||||
fun prologue(descriptor: FunctionDescriptor) {
|
||||
prologue(llvmFunction(descriptor),
|
||||
@@ -27,6 +28,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
if (descriptor is ConstructorDescriptor) {
|
||||
constructedClass = descriptor.constructedClass
|
||||
}
|
||||
functionDescriptor = descriptor
|
||||
}
|
||||
|
||||
fun prologue(function:LLVMValueRef, returnType:LLVMTypeRef) {
|
||||
|
||||
+5
@@ -1491,6 +1491,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
|
||||
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
|
||||
if (target == codegen.functionDescriptor) {
|
||||
super.genReturn(target, value)
|
||||
return
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isUnit(inlineBody.type) == false) {
|
||||
codegen.assignPhis(getResult()!! to value!!)
|
||||
}
|
||||
|
||||
+106
-15
@@ -1,16 +1,22 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
|
||||
import org.jetbrains.kotlin.backend.konan.ir.IrInlineFunctionBody
|
||||
import org.jetbrains.kotlin.backend.konan.ir.getArguments
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.Scope
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
//-----------------------------------------------------------------------------//
|
||||
|
||||
@@ -20,26 +26,96 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun isLambda(value: IrExpression) : Boolean {
|
||||
if (value !is IrContainerExpressionBase) return false
|
||||
if (value.origin != IrStatementOrigin.LAMBDA) return false
|
||||
return true
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun getLambdaStatements(value: IrExpression) : MutableList<IrStatement> {
|
||||
val statements = (value as IrContainerExpressionBase).statements
|
||||
val lambdaFunction = statements[0] as IrFunction
|
||||
val lambdaBody = lambdaFunction.body as IrBlockBody
|
||||
return lambdaBody.statements
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun getLambdaReturnType(value: IrExpression) : KotlinType {
|
||||
val statements = (value as IrContainerExpressionBase).statements
|
||||
val lambdaFunction = statements[0] as IrFunction
|
||||
return lambdaFunction.descriptor.returnType!!
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun evaluateParameters(irCall: IrCall,
|
||||
statements: MutableList<IrStatement>): List<Pair<ParameterDescriptor, IrExpression>> {
|
||||
|
||||
val scope = Scope(irCall.descriptor as FunctionDescriptor)
|
||||
val parametersOld = irCall.getArguments() // Create map inline_function_parameter -> containing_function_expression.
|
||||
val parametersNew = parametersOld.map {
|
||||
val parameter = it.first
|
||||
val expression = it.second
|
||||
if (expression is IrGetValue) return@map it // There is nothing to evaluate.
|
||||
if (isLambda(expression)) { // The expression is lambda.
|
||||
val inlineFunctionBody = inlineLambda(expression) // Create IrInlineFunctionBody to replace this parameter.
|
||||
return@map parameter to inlineFunctionBody
|
||||
}
|
||||
|
||||
val newVar = scope.createTemporaryVariable(expression, "inline", false) // Create new variable and init it with the expression.
|
||||
statements.add(0, newVar) // Add initialization of the new variable in statement list.
|
||||
|
||||
val getVal = IrGetValueImpl(0, 0, newVar.descriptor) // Create new IR element representing access the new variable.
|
||||
parameter to getVal // Parameter will be replaced with the new variable.
|
||||
}
|
||||
return parametersNew
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun inlineFunction(irCall: IrCall): IrBlock {
|
||||
|
||||
val functionDescriptor = irCall.descriptor as FunctionDescriptor
|
||||
val functionDeclaration = context.ir.moduleIndex.functions[functionDescriptor] // Get FunctionDeclaration by FunctionDescriptor.
|
||||
val copyFuncDeclaration = functionDeclaration!!.accept(DeepCopyIrTree(), null) as IrFunction // Create copy of the function.
|
||||
|
||||
val startOffset = copyFuncDeclaration.startOffset
|
||||
val endOffset = copyFuncDeclaration.endOffset
|
||||
val returnType = copyFuncDeclaration.descriptor.returnType!!
|
||||
val inlineBody = copyFuncDeclaration.body!! as IrBlockBody
|
||||
val statements = inlineBody.statements
|
||||
val parameters = evaluateParameters(irCall, statements) // Evaluate parameters representing expression.
|
||||
val irBlock = IrInlineFunctionBody(startOffset, endOffset, returnType, null, statements)
|
||||
|
||||
val transformer = ParametersTransformer(parameters)
|
||||
irBlock.accept(transformer, null) // Replace parameters with expression.
|
||||
return irBlock
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun inlineLambda(value: IrExpression): IrBlock {
|
||||
|
||||
val lambdaStatements = getLambdaStatements(value)
|
||||
val lambdaReturnType = getLambdaReturnType(value)
|
||||
val irBlock = IrInlineFunctionBody(0, 0, lambdaReturnType, null, lambdaStatements)
|
||||
|
||||
return irBlock
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val functionDescriptor = expression.descriptor as FunctionDescriptor
|
||||
if (!functionDescriptor.isInline) return super.visitCall(expression) // Function is not to be inlined - do nothing.
|
||||
|
||||
val functionDeclaration = context.ir.moduleIndex.functions[functionDescriptor] // Get FunctionDeclaration by FunctionDescriptor.
|
||||
if (functionDeclaration == null) return super.visitCall(expression) // Function is declared in another module.
|
||||
val copyFuncDeclaration = functionDeclaration.accept(DeepCopyIrTree(), null) as IrFunction // Create copy of the function.
|
||||
|
||||
val body = copyFuncDeclaration.body!! as IrBlockBody
|
||||
val startOffset = copyFuncDeclaration.startOffset
|
||||
val endOffset = copyFuncDeclaration.endOffset
|
||||
val returnType = copyFuncDeclaration.descriptor.returnType!!
|
||||
val statements = body.statements
|
||||
val irBlock = IrInlineFunctionBody(startOffset, endOffset, returnType, null, statements)
|
||||
|
||||
val parameterToExpression = expression.getArguments() // Build map parameter -> expression.
|
||||
val parametersTransformer = ParametersTransformer(parameterToExpression)
|
||||
irBlock.accept(parametersTransformer, null) // Replace parameters with expression.
|
||||
|
||||
return irBlock // Return newly created IrBlock instead of IrCall.
|
||||
return inlineFunction(expression) // Return newly created IrBlock instead of IrCall.
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
@@ -55,12 +131,27 @@ internal class ParametersTransformer(val parameterToExpression: List <Pair<Param
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
if ((expression.descriptor as FunctionDescriptor).isFunctionInvoke) { // If it is lambda call.
|
||||
if (expression.dispatchReceiver !is IrGetValue) super.visitCall(expression) // Do not process such dispatch receiver.
|
||||
val getValue = expression.dispatchReceiver as IrGetValue //
|
||||
val parExpr = parameterToExpression.find { it.first == getValue.descriptor } // Find expression to replace this parameter.
|
||||
if (parExpr == null) super.visitCall(expression) // It is not function parameter.
|
||||
return parExpr!!.second // Replace call site with InlineFunctionBody.
|
||||
}
|
||||
return super.visitCall(expression) // Function is declared in another module.
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val descriptor = expression.descriptor
|
||||
if (descriptor !is ParameterDescriptor) { // TODO do we need this check?
|
||||
return super.visitGetValue(expression)
|
||||
}
|
||||
val parExp = parameterToExpression.find { it.first == descriptor } // Find expression to replace this parameter.
|
||||
return parExp?.let { parExp.second } ?: super.visitGetValue(expression) // TODO should we proceed with IR iteration here?
|
||||
if (parExp == null) return super.visitGetValue(expression)
|
||||
|
||||
return parExp.second // TODO should we proceed with IR iteration here?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -860,11 +860,6 @@ task memory_throw_cleanup(type: RunKonanTest) {
|
||||
source = "runtime/memory/throw_cleanup.kt"
|
||||
}
|
||||
|
||||
task memory_collect_cycles(type: RunKonanTest) {
|
||||
goldValue = "42\n"
|
||||
source = "runtime/memory/cycles0.kt"
|
||||
}
|
||||
|
||||
task unit1(type: RunKonanTest) {
|
||||
goldValue = "First\nkotlin.Unit\n"
|
||||
source = "codegen/basics/unit1.kt"
|
||||
@@ -906,26 +901,16 @@ task inline3(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task inline4(type: RunKonanTest) {
|
||||
goldValue = "1\n"
|
||||
goldValue = "3\n"
|
||||
source = "codegen/inline/inline4.kt"
|
||||
}
|
||||
|
||||
//task inline5(type: RunKonanTest) {
|
||||
// goldValue = "1\n"
|
||||
// source = "codegen/inline/inline5.kt"
|
||||
//}
|
||||
|
||||
task inline6(type: RunKonanTest) {
|
||||
goldValue = "hello1\nhello2\nhello3\nhello4\n"
|
||||
source = "codegen/inline/inline6.kt"
|
||||
task inline5(type: RunKonanTest) {
|
||||
goldValue = "33\n"
|
||||
source = "codegen/inline/inline5.kt"
|
||||
}
|
||||
|
||||
task inline7(type: RunKonanTest) {
|
||||
goldValue = "1\n2\n3\n"
|
||||
source = "codegen/inline/inline7.kt"
|
||||
}
|
||||
|
||||
task inline8(type: RunKonanTest) {
|
||||
goldValue = "5\n"
|
||||
source = "codegen/inline/inline8.kt"
|
||||
task inline9(type: RunKonanTest) {
|
||||
goldValue = "hello\n6\n"
|
||||
source = "codegen/inline/inline9.kt"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun foo(i2: Int, body: () -> Int): Int {
|
||||
return i2 + body()
|
||||
}
|
||||
|
||||
fun bar(i1: Int): Int {
|
||||
return foo(i1) { 1 }
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(bar(1).toString())
|
||||
}
|
||||
@@ -9,5 +9,5 @@ fun bar(i1: Int, i2: Int): Int {
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(bar(1, 8).toString())
|
||||
println(bar(3, 8).toString())
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
// @Suppress("NOTHING_TO_INLINE")
|
||||
fun foo(i4: Int, i5: Int): Int {
|
||||
try {
|
||||
return i4 / i5
|
||||
} catch (e: Exception) {
|
||||
return i4
|
||||
}
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun foo(i2: Int, body: () -> Int): Int {
|
||||
return i2 + body()
|
||||
}
|
||||
|
||||
fun bar(i1: Int, i2: Int, i3: Int): Int {
|
||||
return i1 + foo(i2, i3)
|
||||
fun bar(i1: Int): Int {
|
||||
return foo(i1) { return 33 }
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(bar(1, 8, 0).toString())
|
||||
println(bar(1).toString())
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun foo(i3: Int, i4: Int): Int {
|
||||
return i3 + i3 + i4
|
||||
}
|
||||
|
||||
fun quiz(i: Int) : Int {
|
||||
println("hello")
|
||||
return i + 1
|
||||
}
|
||||
|
||||
fun bar(i1: Int, i2: Int): Int {
|
||||
return foo(quiz(i1), i2)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(bar(1, 2).toString())
|
||||
}
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
kotlin_version=1.1-M03
|
||||
#kotlinCompilerModule=org.jetbrains.kotlin:kotlin-compiler:1.1-SNAPSHOT
|
||||
kotlinCompilerModule=org.jetbrains.kotlin:kotlin-compiler:1.1-20170116.100209-359
|
||||
kotlinCompilerModule=org.jetbrains.kotlin:kotlin-compiler:1.1-20170126.112137-382
|
||||
Reference in New Issue
Block a user