From 98322d6f557a198542dabe089980d8bbd3312cc7 Mon Sep 17 00:00:00 2001 From: Konstantin Anisimov Date: Wed, 15 Mar 2017 17:00:26 +0700 Subject: [PATCH] All arguments evaluated before inlining procedure Type of "substituteMap" changed to "MutableMap" Code improved according with Slava's comments --- .../backend/konan/lower/FunctionInlining.kt | 155 +++++++++--------- 1 file changed, 73 insertions(+), 82 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 e54cf68d914..08c44f2abac 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 @@ -71,13 +71,55 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( val functionDescriptor = expression.descriptor as FunctionDescriptor if (functionDescriptor.isInline) { val inlineFunctionBody = inlineFunction(expression) -// inlineFunctionBody.transformChildrenVoid(this) // TODO + inlineFunctionBody.transformChildrenVoid(this) // TODO return inlineFunctionBody // Return newly created IrInlineBody instead of IrCall. } return super.visitCall(expression) } + //---------------------------------------------------------------------// + + fun isLambdaExpression(expression: IrExpression) : Boolean { + if (expression !is IrContainerExpressionBase) return false + if (expression.origin != IrStatementOrigin.LAMBDA) return false + return true + } + + //---------------------------------------------------------------------// + + fun needsEvaluation(expression: IrExpression): Boolean { + if (expression is IrGetValue) return false // Parameter is already GetValue - nothing to evaluate. + if (expression is IrConst<*>) return false // Parameter is constant - nothing to evaluate. + if (isLambdaExpression(expression)) return false // Parameter is lambda - will be inlined. + return true + } + + //-------------------------------------------------------------------------// + + fun evaluateParameters(irCall: IrCall, statements: MutableList): MutableMap { + + val parametersOld = irCall.getArguments() // Create map call_site_argument -> inline_function_parameter. + val parametersNew = mutableMapOf () + + parametersOld.forEach { + val parameter = it.first.original + val argument = it.second + + if (!needsEvaluation(argument)) { + parametersNew[parameter] = argument + return@forEach + } + + val newVar = functionScope!!.createTemporaryVariable(argument, "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. + parametersNew[parameter] = getVal // Parameter will be replaced with the new variable. + } + return parametersNew + } + //-------------------------------------------------------------------------// fun inlineFunction(irCall: IrCall): IrExpression { @@ -103,22 +145,22 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( val statements = blockBody.statements val inlineBody = IrInlineFunctionBody(startOffset, endOffset, returnType, null, statements) - val parameterToArgument: MutableList > = irCall.getArguments().toMutableList() + val evaluationStatements = mutableListOf() + val parameterToArgument = evaluateParameters(irCall, evaluationStatements) val lambdaInliner = LambdaInliner(parameterToArgument) inlineBody.transformChildrenVoid(lambdaInliner) val typeArgsMap = (irCall as IrMemberAccessExpressionBase).typeArguments - val statementsBuf = mutableListOf() - val transformer = ParametersTransformer(parameterToArgument, typeArgsMap, statementsBuf) - inlineBody.transformChildrenVoid(transformer) // Replace parameters with expression. - inlineBody.statements.addAll(0, statementsBuf) + val transformer = ParametersTransformer(parameterToArgument, typeArgsMap, evaluationStatements) + inlineBody.transformChildrenVoid(transformer) // Replace parameters with expression. + inlineBody.statements.addAll(0, evaluationStatements) return inlineBody } //-------------------------------------------------------------------------// - inner class ParametersTransformer(val substituteMap: MutableList >, + inner class ParametersTransformer(val substituteMap: MutableMap , val typeArgsMap: Map ?, val statements: MutableList): IrElementTransformerVoid() { @@ -141,7 +183,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( val typeNew = typeArgsMap[operandTypeDescriptor]!! val startOffset = expression.startOffset val endOffset = expression.endOffset - val type = expression.type // TODO + val type = expression.type // TODO val operator = expression.operator val argument = expression.argument @@ -150,50 +192,12 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( //---------------------------------------------------------------------// - fun isLambdaExpression(expression: IrExpression) : Boolean { - if (expression !is IrContainerExpressionBase) return false - if (expression.origin != IrStatementOrigin.LAMBDA) return false - return true - } - - //---------------------------------------------------------------------// - - fun needsEvaluation(expression: IrExpression): Boolean { - if (expression is IrGetValue) return false // Parameter is already GetValue - nothing to evaluate. - if (expression is IrConst<*>) return false // Parameter is constant - nothing to evaluate. - if (isLambdaExpression(expression)) return false // Parameter is lambda - will be inlined. - return true - } - - //---------------------------------------------------------------------// - - fun evaluateExpression(expression: IrExpression): IrGetValue { - // println(" evaluateExpression $expression") - val newVar = functionScope!!.createTemporaryVariable(expression, "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. - return getVal // Parameter will be replaced with the new variable. - } - - //---------------------------------------------------------------------// - override fun visitGetValue(expression: IrGetValue): IrExpression { // println(" visitGetValue ${expression.descriptor.name}") val newExpression = super.visitGetValue(expression) as IrGetValue val descriptor = newExpression.descriptor - val substitute = substituteMap.find { it.first.original == descriptor } // Find expression to replace this parameter. - if (substitute == null) return newExpression // If there is no such expression - do nothing - - val parameter = substitute.first - val argument = substitute.second - if (needsEvaluation(argument)) { - val newArgument = evaluateExpression(argument) - val index = substituteMap.indexOf(substitute) - val newSubstitute = parameter to newArgument - substituteMap[index] = newSubstitute - return newArgument - } + val argument = substituteMap[descriptor] // Find expression to replace this parameter. + if (argument == null) return newExpression // If there is no such expression - do nothing return argument } @@ -213,14 +217,14 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( val newDeclaration = super.visitVariable(declaration) as IrVariable // Process variable initializer. val newVariable = newVariable(newDeclaration) // Create new local variable. val getVal = IrGetValueImpl(0, 0, newVariable.descriptor) // Create new IR element representing access the new variable. - substituteMap.add(declaration.descriptor to getVal) + substituteMap[declaration.descriptor.original] to getVal return newVariable } } //-------------------------------------------------------------------------// - inner class LambdaInliner(val substituteMap: MutableList >): IrElementTransformerVoid() { + inner class LambdaInliner(val substituteMap: MutableMap ): IrElementTransformerVoid() { override fun visitElement(element: IrElement) = element.accept(this, null) @@ -234,23 +238,6 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( //---------------------------------------------------------------------// - fun getLambdaStatements(value: IrExpression) : MutableList { - 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 getLambdaFunction(lambdaArgument: IrExpression): IrFunction? { if (lambdaArgument !is IrBlock) return null @@ -281,31 +268,35 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid( //---------------------------------------------------------------------// + fun buildParameterToArgument(lambdaFunction: IrFunction, irCall: IrCall): MutableMap { + val parameters = lambdaFunction.descriptor.valueParameters // Get lambda function parameters. + val parameterToArgument = mutableMapOf() + parameters.forEach { // Iterate parameters. + val parameter = it + val argument = irCall.getValueArgument(it.index) // Get corresponding argument. + parameterToArgument[parameter] = argument!! // Create (parameter -> argument) pair. + } + return parameterToArgument + } + + //---------------------------------------------------------------------// + fun inlineLambda(irCall: IrCall): IrExpression { val dispatchReceiver = irCall.dispatchReceiver as IrGetValue // - val substitute = substituteMap.find { // Find expression to replace this parameter. - it.first == dispatchReceiver.descriptor - } - if (substitute == null) return super.visitCall(irCall) // It is not function parameter - nothing to substitute. + val lambdaArgument = substituteMap[dispatchReceiver.descriptor] // Find expression to replace this parameter. + if (lambdaArgument == null) return super.visitCall(irCall) // It is not function parameter - nothing to substitute. - val lambdaArgument = substitute.second val lambdaFunction = getLambdaFunction(lambdaArgument) - if (lambdaFunction == null) return super.visitCall(irCall) // TODO - val parameters = lambdaFunction.descriptor.valueParameters // Get lambda function parameters. - val substituteMap = parameters.map { // Iterate parameters. - val parameter = it as ValueDescriptor - val argument = irCall.getValueArgument(it.index) // Get corresponding argument. - parameter to argument!! // Create (parameter -> argument) pair. - }.toMutableList() + val parameterToArgument = buildParameterToArgument(lambdaFunction, irCall) - val lambdaStatements = getLambdaStatements(lambdaArgument) - val lambdaReturnType = getLambdaReturnType(lambdaArgument) + val lambdaStatements = (lambdaFunction.body as IrBlockBody).statements + val lambdaReturnType = lambdaFunction.descriptor.returnType!! val inlineBody = IrInlineFunctionBody(0, 0, lambdaReturnType, null, lambdaStatements) - val transformer = ParametersTransformer(substituteMap, null, lambdaStatements) + val transformer = ParametersTransformer(parameterToArgument, null, lambdaStatements) inlineBody.accept(transformer, null) // Replace parameters with expression. return inlineBody // Replace call site with InlineFunctionBody.