Improve IR inliner to be able to inline property references

This commit is contained in:
Ivan Kylchik
2022-02-09 18:54:51 +03:00
committed by Space Team
parent a09a48492b
commit 59522a6130
@@ -265,6 +265,8 @@ class FunctionInlining(
functionArgument is IrFunctionReference ->
inlineFunctionReference(expression, functionArgument, functionArgument.symbol.owner)
functionArgument is IrPropertyReference -> inlinePropertyReference(expression, functionArgument)
functionArgument.isAdaptedFunctionReference() ->
inlineAdaptedFunctionReference(expression, functionArgument as IrBlock)
@@ -287,6 +289,30 @@ class FunctionInlining(
return newExpression.transform(this, null)
}
private fun inlinePropertyReference(expression: IrCall, propertyReference: IrPropertyReference): IrExpression {
val getterCall = IrCallImpl.fromSymbolOwner(
expression.startOffset, expression.endOffset, expression.type, propertyReference.getter!!
)
fun tryToGetArg(i: Int): IrExpression? {
if (i >= expression.valueArgumentsCount) return null
return expression.getValueArgument(i)?.transform(this, null)
}
val receiverFromField = propertyReference.dispatchReceiver ?: propertyReference.extensionReceiver
getterCall.dispatchReceiver = getterCall.symbol.owner.dispatchReceiverParameter?.let {
receiverFromField ?: tryToGetArg(0)
}
getterCall.extensionReceiver = getterCall.symbol.owner.extensionReceiverParameter?.let {
when (getterCall.symbol.owner.dispatchReceiverParameter) {
null -> receiverFromField ?: tryToGetArg(0)
else -> tryToGetArg(if (receiverFromField != null) 0 else 1)
}
}
return getterCall
}
fun inlineAdaptedFunctionReference(irCall: IrCall, irBlock: IrBlock): IrExpression {
val irFunction = irBlock.statements[0].let {
it.transformChildrenVoid(this)
@@ -436,6 +462,9 @@ class FunctionInlining(
|| argumentExpression is IrFunctionExpression
|| argumentExpression.isAdaptedFunctionReference())
val isInlinablePropertyReference: Boolean
get() = parameter.isInlineParameter() && argumentExpression is IrPropertyReference
val isImmutableVariableLoad: Boolean
get() = argumentExpression.let { argument ->
argument is IrGetValue && !argument.symbol.owner.let { it is IrVariable && it.isVar }
@@ -552,11 +581,15 @@ class FunctionInlining(
//-------------------------------------------------------------------------//
private fun evaluateArguments(functionReference: IrFunctionReference): List<IrStatement> {
val arguments = functionReference.getArgumentsWithIr().map { ParameterToArgument(it.first, it.second) }
private fun evaluateArguments(reference: IrCallableReference<*>): List<IrStatement> {
val arguments = reference.getArgumentsWithIr().map { ParameterToArgument(it.first, it.second) }
val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor()
val referenced = functionReference.symbol.owner
val referenced = when (reference) {
is IrFunctionReference -> reference.symbol.owner
is IrPropertyReference -> reference.getter!!.owner
else -> error(this)
}
arguments.forEach {
val newArgument = if (it.isImmutableVariableLoad) {
it.argumentExpression.transform( // Arguments may reference the previous ones - substitute them.
@@ -579,9 +612,9 @@ class FunctionInlining(
IrGetValueWithoutLocation(newVariable.symbol)
}
when (it.parameter) {
referenced.dispatchReceiverParameter -> functionReference.dispatchReceiver = newArgument
referenced.extensionReceiverParameter -> functionReference.extensionReceiver = newArgument
else -> functionReference.putValueArgument(it.parameter.index, newArgument)
referenced.dispatchReceiverParameter -> reference.dispatchReceiver = newArgument
referenced.extensionReceiverParameter -> reference.extensionReceiver = newArgument
else -> reference.putValueArgument(it.parameter.index, newArgument)
}
}
return evaluationStatements
@@ -598,9 +631,9 @@ class FunctionInlining(
* For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
* not only for those referring to inlinable lambdas.
*/
if (argument.isInlinableLambdaArgument) {
if (argument.isInlinableLambdaArgument || argument.isInlinablePropertyReference) {
substituteMap[parameter] = argument.argumentExpression
(argument.argumentExpression as? IrFunctionReference)?.let { evaluationStatements += evaluateArguments(it) }
(argument.argumentExpression as? IrCallableReference<*>)?.let { evaluationStatements += evaluateArguments(it) }
return@forEach
}