From 287d80413193ab43c96c92c08a116fbe867c443c Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 17 Aug 2016 13:09:59 +0300 Subject: [PATCH] Rematerialize simple expressions (local variables, literals, $this, $receiver) when generating calls. --- .../psi2ir/generators/IrCallGenerator.kt | 37 ++++++++++---- .../IrOperatorExpressionGenerator.kt | 13 ++++- .../generators/values/IrIndexedLValue.kt | 9 ++-- .../values/IrRematerializableValue.kt | 51 +++++++++++++++++++ .../ir/expressions/IrBlockExpression.kt | 4 ++ .../testData/ir/irText/arrayAssignment.txt | 8 +-- .../ir/irText/arrayAugmentedAssignment1.txt | 24 ++++----- .../ir/irText/arrayAugmentedAssignment2.txt | 12 ++--- .../ir/irText/callWithReorderedArguments.kt | 1 + .../ir/irText/callWithReorderedArguments.txt | 5 ++ 10 files changed, 118 insertions(+), 46 deletions(-) create mode 100644 compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrRematerializableValue.kt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrCallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrCallGenerator.kt index f28d82a70fa..1eac2b64a33 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrCallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrCallGenerator.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi2ir.generators.values.IrTemporaryVariableValue import org.jetbrains.kotlin.psi2ir.generators.values.IrValue +import org.jetbrains.kotlin.psi2ir.generators.values.createRematerializableValue import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall import org.jetbrains.kotlin.resolve.calls.model.* @@ -42,12 +43,30 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera private val receiverValues = HashMap() private val valueArgumentValues = HashMap() - fun createTemporary(ktExpression: KtExpression, irExpression: IrExpression, nameHint: String? = null): IrVariable { + fun introduceTemporary(ktExpression: KtExpression, irExpression: IrExpression, nameHint: String? = null): IrVariable? { + val rematerializable = createRematerializableValue(irExpression) + if (rematerializable != null) { + putValue(ktExpression, rematerializable) + return null + } + val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, nameHint) putValue(ktExpression, IrTemporaryVariableValue(irTmpVar)) return irTmpVar } + fun introduceTemporary(valueParameterDescriptor: ValueParameterDescriptor, irExpression: IrExpression): IrVariable? { + val rematerializable = createRematerializableValue(irExpression) + if (rematerializable != null) { + putValue(valueParameterDescriptor, rematerializable) + return null + } + + val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, valueParameterDescriptor.name.asString()) + putValue(valueParameterDescriptor, IrTemporaryVariableValue(irTmpVar)) + return irTmpVar + } + fun putValue(ktExpression: KtExpression, irValue: IrValue) { expressionValues[ktExpression] = irValue } @@ -140,30 +159,30 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera // TODO use IrLetExpression? val valueArgumentsInEvaluationOrder = resolvedCall.valueArguments.values + val valueParameters = resolvedCall.resultingDescriptor.valueParameters val irBlock = IrBlockExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, resultType, hasResult = isUsedAsExpression(ktExpression), isDesugared = true) + + val valueArgumentsToValueParameters = HashMap() for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) { - val valueParameter = resolvedCall.resultingDescriptor.valueParameters[index] + val valueParameter = valueParameters[index] valueArgumentsToValueParameters[valueArgument] = valueParameter } - val temporariesForValueArguments = HashMap>() for (valueArgument in valueArgumentsInEvaluationOrder) { val valueParameter = valueArgumentsToValueParameters[valueArgument]!! val irArgument = generateValueArgument(valueArgument, valueParameter) ?: continue - val irTemporary = temporaryVariableFactory.createTemporaryVariable(irArgument, valueParameter.name.asString()) - temporariesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument) - irBlock.addStatement(irTemporary) + val irTmpArg = introduceTemporary(valueParameter, irArgument) + irBlock.addIfNotNull(irTmpArg) } for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) { - val (temporaryDescriptor, irArgument) = temporariesForValueArguments[valueArgument]!! - val valueParameter = resolvedCall.resultingDescriptor.valueParameters[index] - val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset, temporaryDescriptor) + val valueParameter = valueParameters[index] + val irGetTemporary = valueArgumentValues[valueParameter]!!.load() irCall.putArgument(index, irGetTemporary.toExpectedType(valueParameter.type)) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt index 3627f50900b..6bb8eca155d 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt @@ -28,15 +28,24 @@ import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi2ir.generators.values.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall +import org.jetbrains.kotlin.types.expressions.OperatorConventions val KT_OPERATOR_TO_IR_OPERATOR = hashMapOf( KtTokens.PLUSEQ to IrOperator.PLUSEQ, KtTokens.MINUSEQ to IrOperator.MINUSEQ, KtTokens.MULTEQ to IrOperator.MULTEQ, KtTokens.DIVEQ to IrOperator.DIVEQ, - KtTokens.PERCEQ to IrOperator.PERCEQ + KtTokens.PERCEQ to IrOperator.PERCEQ, + + KtTokens.PLUS to IrOperator.PLUS, + KtTokens.MINUS to IrOperator.MINUS, + KtTokens.MUL to IrOperator.MUL, + KtTokens.DIV to IrOperator.DIV ) +val AUGMENTED_ASSIGNMENTS = KtTokens.AUGMENTED_ASSIGNMENTS +val BINARY_OPERATORS_WITH_CALLS = OperatorConventions.BINARY_OPERATION_NAMES.keys + class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator { override val context: IrGeneratorContext get() = irStatementGenerator.context @@ -45,7 +54,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat return when (ktOperator) { KtTokens.EQ -> generateAssignment(expression) - in KtTokens.AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, ktOperator) + in AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, ktOperator) else -> createDummyExpression(expression, ktOperator.toString()) } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrIndexedLValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrIndexedLValue.kt index 959d6392259..b88c89b124e 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrIndexedLValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrIndexedLValue.kt @@ -16,10 +16,7 @@ package org.jetbrains.kotlin.psi2ir.generators.values -import org.jetbrains.kotlin.ir.expressions.IrBlockExpression -import org.jetbrains.kotlin.ir.expressions.IrBlockExpressionImpl -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrOperator +import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.psiUtil.endOffset @@ -98,11 +95,11 @@ class IrIndexedLValue( } private fun defineContextVariables(irBlock: IrBlockExpression, callGenerator: IrCallGenerator) { - irBlock.addStatement(callGenerator.createTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array")) + irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array")) var index = 0 for ((ktIndexExpression, irIndexValue) in indexValues) { - irBlock.addStatement(callGenerator.createTemporary(ktIndexExpression, irIndexValue, "index${index++}")) + irBlock.addIfNotNull(callGenerator.introduceTemporary(ktIndexExpression, irIndexValue, "index${index++}")) } } } \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrRematerializableValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrRematerializableValue.kt new file mode 100644 index 00000000000..a7a015df8c3 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrRematerializableValue.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.psi2ir.generators.values + +import org.jetbrains.kotlin.ir.expressions.* + +interface IrRematerializableValue : IrValue + +fun createRematerializableValue(irExpression: IrExpression): IrRematerializableValue? = + when (irExpression) { + is IrLiteralExpression<*> -> IrRematerializableLiteralValue(irExpression) + is IrGetVariableExpression -> IrRematerializableVariableValue(irExpression) + is IrGetExtensionReceiverExpression -> IrRematerializableExtensionReceiverValue(irExpression) + is IrThisExpression -> IrRematerializableThisValue(irExpression) + else -> null + } + +class IrRematerializableLiteralValue(val irExpression: IrLiteralExpression<*>): IrRematerializableValue { + override fun load(): IrExpression = + IrLiteralExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, + irExpression.kind, irExpression.kind.valueOf(irExpression)) +} + +class IrRematerializableVariableValue(val irExpression: IrGetVariableExpression) : IrRematerializableValue { + override fun load(): IrExpression = + IrGetVariableExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.descriptor) +} + +class IrRematerializableExtensionReceiverValue(val irExpression: IrGetExtensionReceiverExpression) : IrRematerializableValue { + override fun load(): IrExpression = + IrGetExtensionReceiverExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.descriptor) +} + +class IrRematerializableThisValue(val irExpression: IrThisExpression): IrRematerializableValue { + override fun load(): IrExpression = + IrThisExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.classDescriptor) +} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlockExpression.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlockExpression.kt index 5180aa236f3..654509c7587 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlockExpression.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlockExpression.kt @@ -33,6 +33,10 @@ interface IrBlockExpression : IrExpression { fun addStatement(statement: IrStatement) } +fun IrBlockExpression.addIfNotNull(statement: IrStatement?) { + if (statement != null) addStatement(statement) +} + class IrBlockExpressionImpl( startOffset: Int, endOffset: Int, diff --git a/compiler/testData/ir/irText/arrayAssignment.txt b/compiler/testData/ir/irText/arrayAssignment.txt index 3297db0929a..b2be3bf40bd 100644 --- a/compiler/testData/ir/irText/arrayAssignment.txt +++ b/compiler/testData/ir/irText/arrayAssignment.txt @@ -5,11 +5,7 @@ IrFile /arrayAssignment.kt VAR val x: kotlin.IntArray CALL .intArrayOf type=kotlin.IntArray operator= elements: DUMMY vararg type=kotlin.Int - VAR val tmp0_array: kotlin.IntArray - GET_VAR x type=kotlin.IntArray - VAR val tmp1_index0: kotlin.Int - LITERAL Int type=kotlin.Int value='1' CALL .set type=kotlin.Unit operator=EQ - $this: GET_VAR tmp0_array type=kotlin.IntArray - index: GET_VAR tmp1_index0 type=kotlin.Int + $this: GET_VAR x type=kotlin.IntArray + index: LITERAL Int type=kotlin.Int value='1' value: LITERAL Int type=kotlin.Int value='0' diff --git a/compiler/testData/ir/irText/arrayAugmentedAssignment1.txt b/compiler/testData/ir/irText/arrayAugmentedAssignment1.txt index 2b527404e71..9b719f6c33d 100644 --- a/compiler/testData/ir/irText/arrayAugmentedAssignment1.txt +++ b/compiler/testData/ir/irText/arrayAugmentedAssignment1.txt @@ -10,27 +10,21 @@ IrFile /arrayAugmentedAssignment1.kt BLOCK type= hasResult=false isDesugared=false VAR var x: kotlin.IntArray CALL .foo type=kotlin.IntArray operator= - VAR val tmp0_array: kotlin.IntArray - GET_VAR x type=kotlin.IntArray - VAR val tmp1_index0: kotlin.Int - LITERAL Int type=kotlin.Int value='0' CALL .set type=kotlin.Unit operator=PLUSEQ - $this: GET_VAR tmp0_array type=kotlin.IntArray - index: GET_VAR tmp1_index0 type=kotlin.Int + $this: GET_VAR x type=kotlin.IntArray + index: LITERAL Int type=kotlin.Int value='0' value: CALL .plus type=kotlin.Int operator=PLUSEQ $this: CALL .get type=kotlin.Int operator=PLUSEQ - $this: GET_VAR tmp0_array type=kotlin.IntArray - index: GET_VAR tmp1_index0 type=kotlin.Int + $this: GET_VAR x type=kotlin.IntArray + index: LITERAL Int type=kotlin.Int value='0' other: LITERAL Int type=kotlin.Int value='1' - VAR val tmp2_array: kotlin.IntArray + VAR val tmp0_array: kotlin.IntArray CALL .foo type=kotlin.IntArray operator= - VAR val tmp3_index0: kotlin.Int - LITERAL Int type=kotlin.Int value='0' CALL .set type=kotlin.Unit operator=MULTEQ - $this: GET_VAR tmp2_array type=kotlin.IntArray - index: GET_VAR tmp3_index0 type=kotlin.Int + $this: GET_VAR tmp0_array type=kotlin.IntArray + index: LITERAL Int type=kotlin.Int value='0' value: CALL .times type=kotlin.Int operator=MULTEQ $this: CALL .get type=kotlin.Int operator=MULTEQ - $this: GET_VAR tmp2_array type=kotlin.IntArray - index: GET_VAR tmp3_index0 type=kotlin.Int + $this: GET_VAR tmp0_array type=kotlin.IntArray + index: LITERAL Int type=kotlin.Int value='0' other: LITERAL Int type=kotlin.Int value='2' diff --git a/compiler/testData/ir/irText/arrayAugmentedAssignment2.txt b/compiler/testData/ir/irText/arrayAugmentedAssignment2.txt index 22cc081e7cd..e4d4f2805a0 100644 --- a/compiler/testData/ir/irText/arrayAugmentedAssignment2.txt +++ b/compiler/testData/ir/irText/arrayAugmentedAssignment2.txt @@ -4,16 +4,12 @@ IrFile /arrayAugmentedAssignment2.kt IrFunction public fun IB.test(/*0*/ a: IA): kotlin.Unit IrExpressionBody BLOCK type= hasResult=false isDesugared=false - VAR val tmp0_array: IA - GET_VAR a type=IA - VAR val tmp1_index0: kotlin.String - LITERAL String type=kotlin.String value='' CALL .set type=kotlin.Unit operator=PLUSEQ $this: $RECEIVER of: test type=IB - $receiver: GET_VAR tmp0_array type=IA - index: GET_VAR tmp1_index0 type=kotlin.String + $receiver: GET_VAR a type=IA + index: LITERAL String type=kotlin.String value='' value: CALL .plus type=kotlin.Int operator=PLUSEQ $this: CALL .get type=kotlin.Int operator=PLUSEQ - $this: GET_VAR tmp0_array type=IA - index: GET_VAR tmp1_index0 type=kotlin.String + $this: GET_VAR a type=IA + index: LITERAL String type=kotlin.String value='' other: LITERAL Int type=kotlin.Int value='42' diff --git a/compiler/testData/ir/irText/callWithReorderedArguments.kt b/compiler/testData/ir/irText/callWithReorderedArguments.kt index d4563c0da4f..6ffebfe3a5b 100644 --- a/compiler/testData/ir/irText/callWithReorderedArguments.kt +++ b/compiler/testData/ir/irText/callWithReorderedArguments.kt @@ -9,4 +9,5 @@ fun reordered2() = 2 fun test() { foo(a = noReorder1(), b = noReorder2()) foo(b = reordered1(), a = reordered2()) + foo(b = 1, a = reordered2()) } \ No newline at end of file diff --git a/compiler/testData/ir/irText/callWithReorderedArguments.txt b/compiler/testData/ir/irText/callWithReorderedArguments.txt index 948db638cbb..e5b0a6fd0fc 100644 --- a/compiler/testData/ir/irText/callWithReorderedArguments.txt +++ b/compiler/testData/ir/irText/callWithReorderedArguments.txt @@ -35,3 +35,8 @@ IrFile /callWithReorderedArguments.kt CALL .foo type=kotlin.Unit operator= a: GET_VAR tmp1_a type=kotlin.Int b: GET_VAR tmp0_b type=kotlin.Int + VAR val tmp2_a: kotlin.Int + CALL .reordered2 type=kotlin.Int operator= + CALL .foo type=kotlin.Unit operator= + a: GET_VAR tmp2_a type=kotlin.Int + b: LITERAL Int type=kotlin.Int value='1'