Merge pull request #216 from JetBrains/inline

Inline
This commit is contained in:
KonstantinAnisimov
2017-02-06 17:39:11 +07:00
committed by GitHub
14 changed files with 246 additions and 43 deletions
@@ -17,6 +17,9 @@ internal class KonanLower(val context: Context) {
fun lower(irFile: IrFile) { fun lower(irFile: IrFile) {
val phaser = PhaseManager(context) val phaser = PhaseManager(context)
phaser.phase(KonanPhase.LOWER_INLINE) {
FunctionInlining(context).inline(irFile)
}
phaser.phase(KonanPhase.LOWER_ENUMS) { phaser.phase(KonanPhase.LOWER_ENUMS) {
EnumClassLowering(context).run(irFile) EnumClassLowering(context).run(irFile)
} }
@@ -48,12 +51,5 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.AUTOBOX) { phaser.phase(KonanPhase.AUTOBOX) {
Autoboxing(context).lower(irFile) Autoboxing(context).lower(irFile)
} }
phaser.phase(KonanPhase.LOWER_INLINE) {
//FunctionInlining(context).inline(irFile)
}
phaser.phase(KonanPhase.LOWER_INTEROP) {
InteropLowering(context).runOnFilePostfix(irFile)
}
} }
} }
@@ -17,6 +17,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
// TODO: remove, to make CodeGenerator descriptor-agnostic. // TODO: remove, to make CodeGenerator descriptor-agnostic.
var constructedClass: ClassDescriptor? = null var constructedClass: ClassDescriptor? = null
val vars = VariableManager(this) val vars = VariableManager(this)
var functionDescriptor: FunctionDescriptor? = null
private var returnSlot: LLVMValueRef? = null private var returnSlot: LLVMValueRef? = null
private var slotsPhi: LLVMValueRef? = null private var slotsPhi: LLVMValueRef? = null
private var slotCount = 0 private var slotCount = 0
@@ -40,6 +41,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
if (descriptor is ConstructorDescriptor) { if (descriptor is ConstructorDescriptor) {
constructedClass = descriptor.constructedClass constructedClass = descriptor.constructedClass
} }
functionDescriptor = descriptor
} }
fun prologue(function:LLVMValueRef, returnType:LLVMTypeRef) { fun prologue(function:LLVMValueRef, returnType:LLVMTypeRef) {
@@ -1511,10 +1511,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
} }
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) { override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
if (KotlinBuiltIns.isUnit(inlineBody.type) == false) { if (target == codegen.functionDescriptor) { // It is "non local return".
codegen.assignPhis(getResult()!! to value!!) super.genReturn(target, value) // Generate real "return".
return
} }
codegen.br(getExit()!!) // It is local return.
if (KotlinBuiltIns.isUnit(inlineBody.type) == false) { // If function returns more then "unit"
codegen.assignPhis(getResult()!! to value!!) // Assign return value to result PHI node.
}
codegen.br(getExit()!!) // Generate branch on exit block.
} }
} }
@@ -1,16 +1,22 @@
package org.jetbrains.kotlin.backend.konan.lower package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.konan.Context 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.IrInlineFunctionBody
import org.jetbrains.kotlin.backend.konan.ir.getArguments import org.jetbrains.kotlin.backend.konan.ir.getArguments
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement 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.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.* 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.util.DeepCopyIrTree
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.types.KotlinType
//-----------------------------------------------------------------------------// //-----------------------------------------------------------------------------//
@@ -20,27 +26,96 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
override fun visitCall(expression: IrCall): IrExpression { fun isLambda(value: IrExpression) : Boolean {
val functionDescriptor = expression.descriptor as FunctionDescriptor if (value !is IrContainerExpressionBase) return false
if (!functionDescriptor.isInline) return super.visitCall(expression) // Function is not to be inlined - do nothing. 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.originalModuleIndex val functionDeclaration = context.ir.originalModuleIndex
.functions[functionDescriptor] // Get FunctionDeclaration by FunctionDescriptor. .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 copyFuncDeclaration = functionDeclaration.accept(DeepCopyIrTree(), null) as IrFunction // Create copy of the function.
val body = copyFuncDeclaration.body!! as IrBlockBody
val startOffset = copyFuncDeclaration.startOffset val startOffset = copyFuncDeclaration.startOffset
val endOffset = copyFuncDeclaration.endOffset val endOffset = copyFuncDeclaration.endOffset
val returnType = copyFuncDeclaration.descriptor.returnType!! val returnType = copyFuncDeclaration.descriptor.returnType!!
val statements = body.statements 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 irBlock = IrInlineFunctionBody(startOffset, endOffset, returnType, null, statements)
val parameterToExpression = expression.getArguments() // Build map parameter -> expression. val transformer = ParametersTransformer(parameters)
val parametersTransformer = ParametersTransformer(parameterToExpression) irBlock.accept(transformer, null) // Replace parameters with expression.
irBlock.accept(parametersTransformer, null) // Replace parameters with expression. return irBlock
}
return irBlock // Return newly created IrBlock instead of IrCall. //-------------------------------------------------------------------------//
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.originalModuleIndex.functions[functionDescriptor] // Get FunctionDeclaration by FunctionDescriptor.
if (functionDeclaration == null) return super.visitCall(expression) // Function is declared in another module.
return inlineFunction(expression) // Return newly created IrBlock instead of IrCall.
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -56,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 parameterExpression = parameterToExpression.find { it.first == getValue.descriptor } // Find expression to replace this parameter.
if (parameterExpression == null) super.visitCall(expression) // It is not function parameter.
return parameterExpression!!.second // Replace call site with InlineFunctionBody.
}
return super.visitCall(expression) // Function is declared in another module.
}
//-------------------------------------------------------------------------//
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
val descriptor = expression.descriptor val descriptor = expression.descriptor
if (descriptor !is ParameterDescriptor) { // TODO do we need this check? if (descriptor !is ParameterDescriptor) { // TODO do we need this check?
return super.visitGetValue(expression) return super.visitGetValue(expression)
} }
val parExp = parameterToExpression.find { it.first == descriptor } // Find expression to replace this parameter. val parameterExpression = 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 (parameterExpression == null) return super.visitGetValue(expression)
return parameterExpression.second // TODO should we proceed with IR iteration here?
} }
} }
+30 -5
View File
@@ -1001,11 +1001,6 @@ task memory_throw_cleanup(type: RunKonanTest) {
source = "runtime/memory/throw_cleanup.kt" source = "runtime/memory/throw_cleanup.kt"
} }
task memory_collect_cycles(type: RunKonanTest) {
goldValue = "42\n"
source = "runtime/memory/cycles0.kt"
}
task unit1(type: RunKonanTest) { task unit1(type: RunKonanTest) {
goldValue = "First\nkotlin.Unit\n" goldValue = "First\nkotlin.Unit\n"
source = "codegen/basics/unit1.kt" source = "codegen/basics/unit1.kt"
@@ -1050,6 +1045,36 @@ task vararg0(type: RunKonanTest) {
source = "lower/vararg.kt" source = "lower/vararg.kt"
} }
task inline4(type: RunKonanTest) {
goldValue = "3\n"
source = "codegen/inline/inline4.kt"
}
task inline5(type: RunKonanTest) {
goldValue = "33\n"
source = "codegen/inline/inline5.kt"
}
task inline9(type: RunKonanTest) {
goldValue = "hello\n6\n"
source = "codegen/inline/inline9.kt"
}
task inline6(type: RunKonanTest) {
goldValue = "hello1\nhello2\nhello3\nhello4\n"
source = "codegen/inline/inline6.kt"
}
task inline7(type: RunKonanTest) {
goldValue = "1\n2\n3\n"
source = "codegen/inline/inline7.kt"
}
task inline8(type: RunKonanTest) {
goldValue = "8\n"
source = "codegen/inline/inline8.kt"
}
kotlinNativeInterop { kotlinNativeInterop {
sysstat { sysstat {
pkg 'sysstat' pkg 'sysstat'
@@ -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>) { fun main(args: Array<String>) {
println(bar(1, 8).toString()) println(bar(3, 8).toString())
} }
@@ -0,0 +1,13 @@
@Suppress("NOTHING_TO_INLINE")
inline fun foo(i2: Int, body: () -> Int): Int {
return i2 + body()
}
fun bar(i1: Int): Int {
return foo(i1) { return 33 }
}
fun main(args: Array<String>) {
println(bar(1).toString())
}
@@ -0,0 +1,17 @@
@Suppress("NOTHING_TO_INLINE")
inline fun foo(body: () -> Unit) {
println("hello1")
body()
println("hello4")
}
fun bar() {
foo {
println("hello2")
println("hello3")
}
}
fun main(args: Array<String>) {
bar()
}
@@ -0,0 +1,14 @@
@Suppress("NOTHING_TO_INLINE")
inline fun foo(vararg args: Int) {
for (a in args) {
println(a.toString())
}
}
fun bar() {
foo(1, 2, 3)
}
fun main(args: Array<String>) {
bar()
}
@@ -0,0 +1,12 @@
@Suppress("NOTHING_TO_INLINE")
inline fun foo(i3: Int, i4: Int) : Int {
return i3 + i3 + i4
}
fun bar(i1: Int, i2: Int) : Int {
return foo(i1 + i2, 2)
}
fun main(args: Array<String>) {
println(bar(1, 2).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())
}