From 90a37617a42c09a9ca30e002941c1e868ed15cab Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Thu, 29 Aug 2019 12:52:03 +0200 Subject: [PATCH] [JVM_IR, IR] Remove more needless temporary variables. Avoid using a separate origin for temporary variables introduced for for loops. That doesn't add anything and gives one more case for optimizations to deal with. Extend the JVM specific optimizations to remove temporary variables to deal with more cases encountered in for loops lowering. --- .../common/lower/loops/HeaderProcessor.kt | 9 ++---- .../common/lower/loops/ProgressionHandlers.kt | 3 +- .../backend/jvm/codegen/ExpressionCodegen.kt | 3 +- .../lower/JvmBuiltinOptimizationLowering.kt | 30 ++++++++++++------- .../generators/LoopExpressionGenerator.kt | 2 +- .../forLoop/forInStringSpecialized.kt | 4 +-- .../testData/ir/irText/expressions/for.txt | 2 +- 7 files changed, 29 insertions(+), 24 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderProcessor.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderProcessor.kt index 59745b8c601..70ba88a8864 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderProcessor.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderProcessor.kt @@ -310,8 +310,7 @@ internal class HeaderProcessor( progressionType.elementCastFunctionName ), nameHint = "inductionVariable", - isMutable = true, - origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE + isMutable = true ) // Due to features of PSI2IR we can obtain nullable arguments here while actually @@ -325,8 +324,7 @@ internal class HeaderProcessor( progressionType.elementCastFunctionName ) ), - nameHint = "last", - origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE + nameHint = "last" ) val stepValue = scope.createTemporaryVariable( @@ -336,8 +334,7 @@ internal class HeaderProcessor( progressionType.stepCastFunctionName ) ), - nameHint = "step", - origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE + nameHint = "step" ) return when (headerInfo) { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt index 8985adfa6db..cea4d82992e 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt @@ -351,8 +351,7 @@ internal abstract class IndexedGetIterationHandler(protected val context: Common // This also ensures that the semantics of re-assignment of array variables used in the loop is consistent with the semantics // proposed in https://youtrack.jetbrains.com/issue/KT-21354. val arrayReference = scope.createTemporaryVariable( - expression, nameHint = "indexedObject", - origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE + expression, nameHint = "indexedObject" ) val last = irCall(expression.type.sizePropertyGetter).apply { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 8fd450be82c..faea2725cc2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -262,8 +262,7 @@ class ExpressionCodegen( info.variables.forEach { when (it.declaration.origin) { IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, - IrDeclarationOrigin.FOR_LOOP_ITERATOR, - IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE -> { + IrDeclarationOrigin.FOR_LOOP_ITERATOR -> { // Ignore implicitly created variables } else -> { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmBuiltinOptimizationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmBuiltinOptimizationLowering.kt index 3536ff743d9..0e0d74f0b0d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmBuiltinOptimizationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmBuiltinOptimizationLowering.kt @@ -178,8 +178,7 @@ class JvmBuiltinOptimizationLowering(val context: JvmBackendContext) : FileLower statement.initializer is IrConst<*> } - override fun visitBlock(expression: IrBlock): IrExpression { - expression.transformChildrenVoid(this) + private fun removeUnnecessaryTemporaryVariables(statements: MutableList) { // Remove declarations of immutable temporary variables with constant values. // IrGetValue operations for such temporary variables are replaced // by the initializer IrConst. This makes sure that we do not load and @@ -208,9 +207,10 @@ class JvmBuiltinOptimizationLowering(val context: JvmBackendContext) : FileLower // // which allows the equality check to be simplified away and we end up with // just a const string load. - expression.statements.removeIf { + statements.removeIf { isImmutableTemporaryVariableWithConstantValue(it) } + // Remove a block that contains only two statements: the declaration of a temporary // variable and a load of the value of that temporary variable with just the initializer // for the temporary variable. We only perform this transformation for compiler generated @@ -242,18 +242,28 @@ class JvmBuiltinOptimizationLowering(val context: JvmBackendContext) : FileLower // 42.toLong() // // Doing so we avoid local loads and stores. - if (expression.statements.size == 2) { - val first = expression.statements[0] - val second = expression.statements[1] + if (statements.size == 2) { + val first = statements[0] + val second = statements[1] if (first is IrVariable && first.origin == IrDeclarationOrigin.IR_TEMPORARY_VARIABLE && second is IrGetValue - && first.symbol == second.symbol - ) { - expression.statements.clear() - first.initializer?.let { expression.statements.add(it) } + && first.symbol == second.symbol) { + statements.clear() + first.initializer?.let { statements.add(it) } } } + } + + override fun visitBlockBody(body: IrBlockBody): IrBody { + body.transformChildrenVoid(this) + removeUnnecessaryTemporaryVariables(body.statements) + return body + } + + override fun visitContainerExpression(expression: IrContainerExpression): IrExpression { + expression.transformChildrenVoid(this) + removeUnnecessaryTemporaryVariables(expression.statements) return expression } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt index 7b0b40669d2..ad6b251682e 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt @@ -197,7 +197,7 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen irNextCall ) } else { - scope.createTemporaryVariable(irNextCall, "loop_parameter", origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE) + scope.createTemporaryVariable(irNextCall, "loop_parameter") } irInnerBody.statements.add(irLoopParameter) diff --git a/compiler/testData/codegen/bytecodeText/forLoop/forInStringSpecialized.kt b/compiler/testData/codegen/bytecodeText/forLoop/forInStringSpecialized.kt index c882c798ce9..d3eb41c5ee5 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/forInStringSpecialized.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/forInStringSpecialized.kt @@ -9,5 +9,5 @@ fun test() { // 0 hasNext // 0 nextChar // 0 INVOKEINTERFACE -// 1 ISTORE 4 -// 1 ILOAD 4 +// 1 charAt \(I\)C +// 1 length \(\)I diff --git a/compiler/testData/ir/irText/expressions/for.txt b/compiler/testData/ir/irText/expressions/for.txt index e6cf725a0f1..2af2f411122 100644 --- a/compiler/testData/ir/irText/expressions/for.txt +++ b/compiler/testData/ir/irText/expressions/for.txt @@ -41,7 +41,7 @@ FILE fqName: fileName:/for.kt condition: CALL 'public abstract fun hasNext (): kotlin.Boolean declared in kotlin.collections.Iterator' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT $this: GET_VAR 'val tmp0_iterator: kotlin.collections.Iterator> [val] declared in .testDestructuring' type=kotlin.collections.Iterator> origin=null body: BLOCK type=kotlin.Unit origin=FOR_LOOP_INNER_WHILE - VAR FOR_LOOP_IMPLICIT_VARIABLE name:tmp1_loop_parameter type:kotlin.Pair [val] + VAR IR_TEMPORARY_VARIABLE name:tmp1_loop_parameter type:kotlin.Pair [val] CALL 'public abstract fun next (): T of kotlin.collections.Iterator declared in kotlin.collections.Iterator' type=kotlin.Pair origin=FOR_LOOP_NEXT $this: GET_VAR 'val tmp0_iterator: kotlin.collections.Iterator> [val] declared in .testDestructuring' type=kotlin.collections.Iterator> origin=null VAR name:i type:kotlin.Int [val]