Combine parameter evaluation with parameter transformer

This commit is contained in:
Konstantin Anisimov
2017-03-14 17:18:01 +07:00
committed by KonstantinAnisimov
parent 3ebcf92f8b
commit 39f002db81
@@ -3,7 +3,9 @@ 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.descriptors.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.Scope
@@ -11,7 +13,10 @@ 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.*
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrMemberAccessExpressionBase
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -31,6 +36,10 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
//-------------------------------------------------------------------------//
override fun visitElement(element: IrElement) = element.accept(this, null)
//-------------------------------------------------------------------------//
override fun visitFile(declaration: IrFile): IrFile {
currentFile = declaration
return super.visitFile(declaration)
@@ -41,37 +50,31 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
override fun visitFunction(declaration: IrFunction): IrStatement {
currentFunction = declaration
functionScope = Scope(declaration.descriptor)
// println("visitFunction ${declaration.descriptor.name}")
return super.visitFunction(declaration)
}
//-------------------------------------------------------------------------//
fun isLambdaExpression(expression: IrExpression) : Boolean {
if (expression !is IrContainerExpressionBase) return false
if (expression.origin != IrStatementOrigin.LAMBDA) return false
return true
}
override fun visitCall(expression: IrCall): IrExpression {
//-------------------------------------------------------------------------//
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
val fileName = currentFile!!.fileEntry.name
if (fileName.contains("cinterop")) return super.visitCall(expression)
fun evaluateParameters(irCall: IrCall,
statements: MutableList<IrStatement>): MutableList<Pair<ValueDescriptor, IrExpression>> {
if (currentFunction == null) return super.visitCall(expression)
if (currentFunction!!.descriptor.isInline) return super.visitCall(expression) // TODO workaround
val parametersOld = irCall.getArguments() // Create map call_site_argument -> inline_function_parameter.
val parametersNew = parametersOld.map {
val argument = it.first.original
val parameter = it.second
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 = 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.
// println("visitCall ${expression.descriptor.name}")
val functionDescriptor = expression.descriptor as FunctionDescriptor
if (functionDescriptor.isInline) {
val inlineFunctionBody = inlineFunction(expression)
// inlineFunctionBody.accept(this, null) //
return inlineFunctionBody // Return newly created IrInlineBody instead of IrCall.
}
return parametersNew.toMutableList()
return super.visitCall(expression)
}
//-------------------------------------------------------------------------//
@@ -83,7 +86,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
.functions[functionDescriptor.original] // Get FunctionDeclaration by FunctionDescriptor.
if (functionDeclaration == null) return irCall // Function is declared in another module.
print("file: ${currentFile!!.fileEntry.name} ") // TODO debug output
print(" inline file: ${currentFile!!.fileEntry.name} ") // TODO debug output
print("function: ${currentFunction!!.descriptor.name} ") // TODO debug output
println("call: ${functionDescriptor.name} ${irCall.startOffset}") // TODO debug output
@@ -99,71 +102,154 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
val statements = blockBody.statements
val inlineBody = IrInlineFunctionBody(startOffset, endOffset, returnType, null, statements)
val newBody = super.visitBlock(inlineBody) as IrBlock
val parameters = evaluateParameters(irCall, newBody.statements) // Evaluate parameters representing expression.
val lambdaInliner = LambdaInliner(parameters, functionScope!!)
newBody.accept(lambdaInliner, null) // TODO
val transformer = ParametersTransformer(parameters, irCall, functionScope!!)
newBody.accept(transformer, null) // TODO // Replace parameters with expression.
val parameterToArgument: MutableList <Pair <ValueDescriptor, IrExpression>> = irCall.getArguments().toMutableList()
val typeArgsMap = (irCall as IrMemberAccessExpressionBase).typeArguments // If there are no type args - do nothing.
val statementsBuf = mutableListOf<IrStatement>()
val transformer = ParametersTransformer(parameterToArgument, typeArgsMap, statementsBuf)
inlineBody.accept(transformer, null) // Replace parameters with expression.
inlineBody.statements.addAll(0, statementsBuf)
return newBody
val lambdaInliner = LambdaInliner(parameterToArgument)
inlineBody.accept(lambdaInliner, null)
return inlineBody
}
//-------------------------------------------------------------------------//
override fun visitCall(expression: IrCall): IrExpression {
inner class ParametersTransformer(val substituteMap: MutableList <Pair <ValueDescriptor, IrExpression>>,
val typeArgsMap: Map <TypeParameterDescriptor, KotlinType>?,
val statements: MutableList<IrStatement>): IrElementTransformerVoid() {
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
val fileName = currentFile!!.fileEntry.name
if (fileName.contains("cinterop")) return super.visitCall(expression)
if (currentFunction!!.descriptor.isInline) return super.visitCall(expression) // TODO workaround
override fun visitElement(element: IrElement) = element.accept(this, null)
val functionDescriptor = expression.descriptor as FunctionDescriptor
if (functionDescriptor.isInline) return inlineFunction(expression) // Return newly created IrInlineBody instead of IrCall.
//---------------------------------------------------------------------//
return super.visitCall(expression)
override fun visitTypeOperator(oldExpression: IrTypeOperatorCall): IrExpression {
val expression = super.visitTypeOperator(oldExpression) as IrTypeOperatorCall
if (expression.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT) { // Nothing to do for IMPLICIT_COERCION_TO_UNIT
return expression
}
if (typeArgsMap == null) return expression
val operandTypeDescriptor = expression.typeOperand.constructor.declarationDescriptor
if (operandTypeDescriptor !is TypeParameterDescriptor) return expression // It is not TypeParameter - do nothing
val typeNew = typeArgsMap[operandTypeDescriptor]!!
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val type = expression.type // TODO
val operator = expression.operator
val argument = expression.argument
return IrTypeOperatorCallImpl(startOffset, endOffset, type, operator, typeNew, argument)
}
//---------------------------------------------------------------------//
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
}
return argument
}
//---------------------------------------------------------------------//
fun newVariable(oldVariable: IrVariable): IrVariable {
val initializer = oldVariable.initializer!!
return functionScope!!.createTemporaryVariable(initializer, "inline", false) // Create new variable and init it with the parameter expression.
}
//---------------------------------------------------------------------//
override fun visitVariable(declaration: IrVariable): IrStatement {
// println(" visitVariable ${declaration.descriptor.name}")
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)
return newVariable
}
}
//-------------------------------------------------------------------------//
override fun visitElement(element: IrElement) = element.accept(this, null)
}
inner class LambdaInliner(val substituteMap: MutableList <Pair <ValueDescriptor, IrExpression>>): IrElementTransformerVoid() {
//-----------------------------------------------------------------------------//
override fun visitElement(element: IrElement) = element.accept(this, null)
internal class LambdaInliner(val parameterToArgument:
MutableList<Pair<ValueDescriptor, IrExpression>>, val scope: Scope): IrElementTransformerVoid() {
//---------------------------------------------------------------------//
override fun visitElement(element: IrElement) = element.accept(this, null)
fun isLambdaCall(irCall: IrCall) : Boolean {
if (!(irCall.descriptor as FunctionDescriptor).isFunctionInvoke) return false // If it is lambda call.
if (irCall.dispatchReceiver !is IrGetValue) return false // Do not process such dispatch receiver.
return true
}
//-------------------------------------------------------------------------//
//---------------------------------------------------------------------//
fun isLambdaCall(irCall: IrCall) : Boolean {
if (!(irCall.descriptor as FunctionDescriptor).isFunctionInvoke) return false // If it is lambda call.
if (irCall.dispatchReceiver !is IrGetValue) return false // Do not process such dispatch receiver.
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 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 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
@@ -193,136 +279,46 @@ internal class LambdaInliner(val parameterToArgument:
return irFunction
}
//-------------------------------------------------------------------------//
//---------------------------------------------------------------------//
fun inlineLambda(irCall: IrCall): IrExpression {
fun inlineLambda(irCall: IrCall): IrExpression {
val dispatchReceiver = irCall.dispatchReceiver as IrGetValue //
val parameterArgument = parameterToArgument.find { // Find expression to replace this parameter.
it.first == dispatchReceiver.descriptor
}
if (parameterArgument == null) return super.visitCall(irCall) // It is not function parameter.
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 = parameterArgument.second
val lambdaArgument = substitute.second
val lambdaFunction = getLambdaFunction(lambdaArgument)
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 as ValueDescriptor
parameter to argument!!
}.toMutableList()
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 lambdaStatements = getLambdaStatements(lambdaArgument)
val lambdaReturnType = getLambdaReturnType(lambdaArgument)
val inlineBody = IrInlineFunctionBody(0, 0, lambdaReturnType, null, lambdaStatements)
val lambdaStatements = getLambdaStatements(lambdaArgument)
val lambdaReturnType = getLambdaReturnType(lambdaArgument)
val inlineBody = IrInlineFunctionBody(0, 0, lambdaReturnType, null, lambdaStatements)
val transformer = ParametersTransformer(res, irCall, scope)
val aa = inlineBody.accept(transformer, null) // TODO // Replace parameters with expression.
val transformer = ParametersTransformer(substituteMap, null, lambdaStatements)
inlineBody.accept(transformer, null) // Replace parameters with expression.
return inlineBody // Replace call site with InlineFunctionBody.
}
return inlineBody // Replace call site with InlineFunctionBody.
}
//-------------------------------------------------------------------------//
//---------------------------------------------------------------------//
override fun visitCall(expression: IrCall): IrExpression {
if (!isLambdaCall(expression)) return super.visitCall(expression) // If call it is not lambda call - do nothing
return inlineLambda(expression)
override fun visitCall(expression: IrCall): IrExpression {
if (!isLambdaCall(expression)) return super.visitCall(expression) // If call it is not lambda call - do nothing.
return inlineLambda(expression)
}
}
}
//-----------------------------------------------------------------------------//
internal class ParametersTransformer(val parameterToArgument: MutableList<Pair<ValueDescriptor, IrExpression>>,
val callSite: IrCall, val scope: Scope): IrElementTransformerVoid() {
override fun visitElement(element: IrElement) = element.accept(this, null)
//-------------------------------------------------------------------------//
override fun visitTypeOperator(oldExpression: IrTypeOperatorCall): IrExpression {
val expression = super.visitTypeOperator(oldExpression) as IrTypeOperatorCall
if (expression.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT) { // Nothing to do for IMPLICIT_COERCION_TO_UNIT
return expression
}
val typeArgsMap = (callSite as IrMemberAccessExpressionBase).typeArguments // If there are no type args - do nothing.
if (typeArgsMap == null) return expression
val operandTypeDescriptor = expression.typeOperand.constructor.declarationDescriptor
if (operandTypeDescriptor !is TypeParameterDescriptor) return expression // It is not TypeParameter - do nothing
println("typeArgsMap: $typeArgsMap")
println("operandTypeDescriptor: $operandTypeDescriptor")
val typeNew = typeArgsMap[operandTypeDescriptor]!!
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val type = expression.type // TODO
val operator = expression.operator
val argument = expression.argument
return IrTypeOperatorCallImpl(startOffset, endOffset, type, operator, typeNew, argument)
}
//-------------------------------------------------------------------------//
override fun visitGetValue(expression: IrGetValue): IrExpression {
val descriptor = expression.descriptor
val result = super.visitGetValue(expression)
val parameterArgument = parameterToArgument.find { it.first == descriptor } // Find expression to replace this parameter.
if (parameterArgument == null) {
return result
}
return parameterArgument.second // TODO should we proceed with IR iteration here?
}
//-------------------------------------------------------------------------//
fun newVariable(oldVariable: IrVariable, newType: KotlinType): IrVariable {
val initializer = oldVariable.initializer!!
val newVariable = scope.createTemporaryVariable(initializer, "inline", false) // Create new variable and init it with the parameter expression.
return newVariable
}
//-------------------------------------------------------------------------//
fun substituteType(variable: IrVariable): KotlinType? {
val typeArgsMap = (callSite as IrMemberAccessExpressionBase).typeArguments
if (typeArgsMap == null) return variable.descriptor.type
val oldType = variable.descriptor.type
val typeDescriptor = oldType.constructor.declarationDescriptor
val newType = typeArgsMap[typeDescriptor]
if (newType == null) return variable.descriptor.type
return newType
}
//-------------------------------------------------------------------------//
override fun visitVariable(declaration: IrVariable): IrStatement {
// println("visitVariableAkm ${declaration.descriptor.name}")
val replacement = parameterToArgument.find {
if (it.second !is IrGetValue) return super.visitVariable(declaration)
val aa = it.second as IrGetValue
aa.descriptor == declaration.descriptor
} // Try to find
if (replacement != null) return super.visitVariable(declaration)
val nn = super.visitVariable(declaration) as IrVariable
val newType = substituteType(nn)!! // If variable type should be replaced with type arg.
val newVariable = newVariable(nn, newType) // Create new local variable.
val getVal = IrGetValueImpl(0, 0, newVariable.descriptor) // Create new IR element representing access the new variable.
parameterToArgument.add(nn.descriptor to getVal)
return newVariable
}
}