From b9235ca8b196c52648fb976575aa27c4494f4a21 Mon Sep 17 00:00:00 2001 From: Konstantin Anisimov Date: Fri, 3 Mar 2017 17:45:00 +0700 Subject: [PATCH] Type propagation support, stdlib compilation bug fixes, workarounds --- .../backend/konan/lower/FunctionInlining.kt | 134 ++++++++++++++---- 1 file changed, 106 insertions(+), 28 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt index eb28182e540..81985fc4458 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt @@ -4,14 +4,13 @@ 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.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.* 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.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl @@ -25,18 +24,31 @@ import org.jetbrains.kotlin.types.KotlinType internal class FunctionInlining(val context: Context): IrElementTransformerVoid() { + var currentFile : IrFile? = null + var currentFunction : IrFunction? = null + var functionScope : Scope? = null + + //-------------------------------------------------------------------------// + fun inline(irFile: IrFile) = irFile.accept(this, null) //-------------------------------------------------------------------------// - var fqName: String? = null override fun visitFile(declaration: IrFile): IrFile { - fqName = declaration.packageFragmentDescriptor.fqName.asString() + currentFile = declaration return super.visitFile(declaration) } //-------------------------------------------------------------------------// + override fun visitFunction(declaration: IrFunction): IrStatement { + currentFunction = declaration + functionScope = Scope(declaration.descriptor) + return super.visitFunction(declaration) + } + + //-------------------------------------------------------------------------// + fun isLambdaExpression(expression: IrExpression) : Boolean { if (expression !is IrContainerExpressionBase) return false if (expression.origin != IrStatementOrigin.LAMBDA) return false @@ -46,24 +58,23 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( //-------------------------------------------------------------------------// fun evaluateParameters(irCall: IrCall, - statements: MutableList): List> { + statements: MutableList): MutableList> { - val scope = Scope(irCall.descriptor as FunctionDescriptor) val parametersOld = irCall.getArguments() // Create map call_site_argument -> inline_function_parameter. val parametersNew = parametersOld.map { - val argument = it.first + val argument = it.first.original val parameter = it.second - if (parameter is IrGetValue) return@map it // Parameter is already GetValue - nothing to evaluate. - if (parameter is IrConst<*>) return@map it // Parameter is constant - nothing to evaluate. - if (isLambdaExpression(parameter)) return@map it // Parameter is lambda - will be inlined. + if (parameter is IrGetValue) return@map argument to it.second // Parameter is already GetValue - nothing to evaluate. + if (parameter is IrConst<*>) return@map argument to it.second // Parameter is constant - nothing to evaluate. + if (isLambdaExpression(parameter)) return@map argument to it.second // Parameter is lambda - will be inlined. - val newVar = scope.createTemporaryVariable(parameter, "inline", false) // Create new variable and init it with the parameter expression. + val newVar = functionScope!!.createTemporaryVariable(parameter, "inline", false) // Create new variable and init it with the parameter 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. argument to getVal // Parameter will be replaced with the new variable. } - return parametersNew + return parametersNew.toMutableList() } //-------------------------------------------------------------------------// @@ -74,13 +85,20 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( val functionDeclaration = context.ir.originalModuleIndex .functions[functionDescriptor.original] // Get FunctionDeclaration by FunctionDescriptor. - if (functionDeclaration == null) return super.visitCall(irCall) // Function is declared in another module. + val result = super.visitCall(irCall) + if (functionDeclaration == null) return result // Function is declared in another module. +// print("inline function ${currentFile!!.name} ") // TODO debug output +// print("function: ${currentFunction!!.descriptor.name} ") // TODO debug output +// println("call: ${functionDescriptor.name} ${irCall.startOffset}") // TODO debug output + val copyFuncDeclaration = functionDeclaration.accept(DeepCopyIrTree(), // Create copy of the function. null) as IrFunction val startOffset = copyFuncDeclaration.startOffset val endOffset = copyFuncDeclaration.endOffset val returnType = copyFuncDeclaration.descriptor.returnType!! + + if (copyFuncDeclaration.body == null) return result // TODO workaround val blockBody = copyFuncDeclaration.body!! as IrBlockBody val statements = blockBody.statements val parameters = evaluateParameters(irCall, statements) // Evaluate parameters representing expression. @@ -90,6 +108,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( inlineBody.accept(lambdaInliner, null) val transformer = ParametersTransformer(parameters, irCall) inlineBody.accept(transformer, null) // Replace parameters with expression. + return super.visitBlock(inlineBody) } @@ -97,7 +116,9 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( override fun visitCall(expression: IrCall): IrExpression { - if(fqName!!.contains("kotlin")) return super.visitCall(expression) + val fqName = currentFile!!.packageFragmentDescriptor.fqName.asString() // TODO to be removed after stdlib compilation + if(fqName.contains("kotlin")) return super.visitCall(expression) // TODO to be removed after stdlib compilation + // if (currentFunction!!.descriptor.isInline) return super.visitCall(expression) // TODO workaround val functionDescriptor = expression.descriptor as FunctionDescriptor if (functionDescriptor.isInline) return inlineFunction(expression) // Return newly created IrInlineBody instead of IrCall. @@ -113,7 +134,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( //-----------------------------------------------------------------------------// internal class LambdaInliner(val parameterToArgument: - List>): IrElementTransformerVoid() { + MutableList>): IrElementTransformerVoid() { override fun visitElement(element: IrElement) = element.accept(this, null) @@ -144,9 +165,11 @@ internal class LambdaInliner(val parameterToArgument: //-------------------------------------------------------------------------// - fun getLambdaFunction(lambdaArgument: IrBlock): IrFunction { + fun getLambdaFunction(lambdaArgument: IrBlock): IrFunction? { val statements = (lambdaArgument as IrContainerExpressionBase).statements - val lambdaFunction = statements[0] as IrFunction + val irFunction = statements[0] + if (irFunction !is IrFunction) return null // TODO + val lambdaFunction = irFunction as IrFunction return lambdaFunction } @@ -163,12 +186,14 @@ internal class LambdaInliner(val parameterToArgument: val lambdaArgument = parameterArgument.second val lambdaFunction = getLambdaFunction(lambdaArgument as IrBlock) + if (lambdaFunction == null) return super.visitCall(irCall) // TODO + val parameters = lambdaFunction.descriptor.valueParameters // Lambda function parameters val res = parameters.map { val argument = irCall.getValueArgument(it.index) - val parameter = it + val parameter = it as DeclarationDescriptor parameter to argument!! - } + }.toMutableList() val lambdaStatements = getLambdaStatements(lambdaArgument) val lambdaReturnType = getLambdaReturnType(lambdaArgument) @@ -190,10 +215,11 @@ internal class LambdaInliner(val parameterToArgument: //-----------------------------------------------------------------------------// -internal class ParametersTransformer(val parameterToArgument: List>, +internal class ParametersTransformer(val parameterToArgument: MutableList>, val callSite: IrCall): IrElementTransformerVoid() { override fun visitElement(element: IrElement) = element.accept(this, null) + val scope = Scope(callSite.descriptor as FunctionDescriptor) //-------------------------------------------------------------------------// @@ -201,10 +227,17 @@ internal class ParametersTransformer(val parameterToArgument: List