[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.
This commit is contained in:
+3
-6
@@ -310,8 +310,7 @@ internal class HeaderProcessor(
|
|||||||
progressionType.elementCastFunctionName
|
progressionType.elementCastFunctionName
|
||||||
),
|
),
|
||||||
nameHint = "inductionVariable",
|
nameHint = "inductionVariable",
|
||||||
isMutable = true,
|
isMutable = true
|
||||||
origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Due to features of PSI2IR we can obtain nullable arguments here while actually
|
// Due to features of PSI2IR we can obtain nullable arguments here while actually
|
||||||
@@ -325,8 +324,7 @@ internal class HeaderProcessor(
|
|||||||
progressionType.elementCastFunctionName
|
progressionType.elementCastFunctionName
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
nameHint = "last",
|
nameHint = "last"
|
||||||
origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val stepValue = scope.createTemporaryVariable(
|
val stepValue = scope.createTemporaryVariable(
|
||||||
@@ -336,8 +334,7 @@ internal class HeaderProcessor(
|
|||||||
progressionType.stepCastFunctionName
|
progressionType.stepCastFunctionName
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
nameHint = "step",
|
nameHint = "step"
|
||||||
origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return when (headerInfo) {
|
return when (headerInfo) {
|
||||||
|
|||||||
+1
-2
@@ -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
|
// 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.
|
// proposed in https://youtrack.jetbrains.com/issue/KT-21354.
|
||||||
val arrayReference = scope.createTemporaryVariable(
|
val arrayReference = scope.createTemporaryVariable(
|
||||||
expression, nameHint = "indexedObject",
|
expression, nameHint = "indexedObject"
|
||||||
origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val last = irCall(expression.type.sizePropertyGetter).apply {
|
val last = irCall(expression.type.sizePropertyGetter).apply {
|
||||||
|
|||||||
+1
-2
@@ -262,8 +262,7 @@ class ExpressionCodegen(
|
|||||||
info.variables.forEach {
|
info.variables.forEach {
|
||||||
when (it.declaration.origin) {
|
when (it.declaration.origin) {
|
||||||
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
|
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
|
||||||
IrDeclarationOrigin.FOR_LOOP_ITERATOR,
|
IrDeclarationOrigin.FOR_LOOP_ITERATOR -> {
|
||||||
IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE -> {
|
|
||||||
// Ignore implicitly created variables
|
// Ignore implicitly created variables
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
+20
-10
@@ -178,8 +178,7 @@ class JvmBuiltinOptimizationLowering(val context: JvmBackendContext) : FileLower
|
|||||||
statement.initializer is IrConst<*>
|
statement.initializer is IrConst<*>
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBlock(expression: IrBlock): IrExpression {
|
private fun removeUnnecessaryTemporaryVariables(statements: MutableList<IrStatement>) {
|
||||||
expression.transformChildrenVoid(this)
|
|
||||||
// Remove declarations of immutable temporary variables with constant values.
|
// Remove declarations of immutable temporary variables with constant values.
|
||||||
// IrGetValue operations for such temporary variables are replaced
|
// IrGetValue operations for such temporary variables are replaced
|
||||||
// by the initializer IrConst. This makes sure that we do not load and
|
// 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
|
// which allows the equality check to be simplified away and we end up with
|
||||||
// just a const string load.
|
// just a const string load.
|
||||||
expression.statements.removeIf {
|
statements.removeIf {
|
||||||
isImmutableTemporaryVariableWithConstantValue(it)
|
isImmutableTemporaryVariableWithConstantValue(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a block that contains only two statements: the declaration of a temporary
|
// 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
|
// 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
|
// for the temporary variable. We only perform this transformation for compiler generated
|
||||||
@@ -242,18 +242,28 @@ class JvmBuiltinOptimizationLowering(val context: JvmBackendContext) : FileLower
|
|||||||
// 42.toLong()
|
// 42.toLong()
|
||||||
//
|
//
|
||||||
// Doing so we avoid local loads and stores.
|
// Doing so we avoid local loads and stores.
|
||||||
if (expression.statements.size == 2) {
|
if (statements.size == 2) {
|
||||||
val first = expression.statements[0]
|
val first = statements[0]
|
||||||
val second = expression.statements[1]
|
val second = statements[1]
|
||||||
if (first is IrVariable
|
if (first is IrVariable
|
||||||
&& first.origin == IrDeclarationOrigin.IR_TEMPORARY_VARIABLE
|
&& first.origin == IrDeclarationOrigin.IR_TEMPORARY_VARIABLE
|
||||||
&& second is IrGetValue
|
&& second is IrGetValue
|
||||||
&& first.symbol == second.symbol
|
&& first.symbol == second.symbol) {
|
||||||
) {
|
statements.clear()
|
||||||
expression.statements.clear()
|
first.initializer?.let { statements.add(it) }
|
||||||
first.initializer?.let { expression.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
|
return expression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -197,7 +197,7 @@ class LoopExpressionGenerator(statementGenerator: StatementGenerator) : Statemen
|
|||||||
irNextCall
|
irNextCall
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
scope.createTemporaryVariable(irNextCall, "loop_parameter", origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE)
|
scope.createTemporaryVariable(irNextCall, "loop_parameter")
|
||||||
}
|
}
|
||||||
irInnerBody.statements.add(irLoopParameter)
|
irInnerBody.statements.add(irLoopParameter)
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ fun test() {
|
|||||||
// 0 hasNext
|
// 0 hasNext
|
||||||
// 0 nextChar
|
// 0 nextChar
|
||||||
// 0 INVOKEINTERFACE
|
// 0 INVOKEINTERFACE
|
||||||
// 1 ISTORE 4
|
// 1 charAt \(I\)C
|
||||||
// 1 ILOAD 4
|
// 1 length \(\)I
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ FILE fqName:<root> fileName:/for.kt
|
|||||||
condition: CALL 'public abstract fun hasNext (): kotlin.Boolean declared in kotlin.collections.Iterator' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT
|
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<kotlin.Pair<kotlin.Int, kotlin.String>> [val] declared in <root>.testDestructuring' type=kotlin.collections.Iterator<kotlin.Pair<kotlin.Int, kotlin.String>> origin=null
|
$this: GET_VAR 'val tmp0_iterator: kotlin.collections.Iterator<kotlin.Pair<kotlin.Int, kotlin.String>> [val] declared in <root>.testDestructuring' type=kotlin.collections.Iterator<kotlin.Pair<kotlin.Int, kotlin.String>> origin=null
|
||||||
body: BLOCK type=kotlin.Unit origin=FOR_LOOP_INNER_WHILE
|
body: BLOCK type=kotlin.Unit origin=FOR_LOOP_INNER_WHILE
|
||||||
VAR FOR_LOOP_IMPLICIT_VARIABLE name:tmp1_loop_parameter type:kotlin.Pair<kotlin.Int, kotlin.String> [val]
|
VAR IR_TEMPORARY_VARIABLE name:tmp1_loop_parameter type:kotlin.Pair<kotlin.Int, kotlin.String> [val]
|
||||||
CALL 'public abstract fun next (): T of kotlin.collections.Iterator declared in kotlin.collections.Iterator' type=kotlin.Pair<kotlin.Int, kotlin.String> origin=FOR_LOOP_NEXT
|
CALL 'public abstract fun next (): T of kotlin.collections.Iterator declared in kotlin.collections.Iterator' type=kotlin.Pair<kotlin.Int, kotlin.String> origin=FOR_LOOP_NEXT
|
||||||
$this: GET_VAR 'val tmp0_iterator: kotlin.collections.Iterator<kotlin.Pair<kotlin.Int, kotlin.String>> [val] declared in <root>.testDestructuring' type=kotlin.collections.Iterator<kotlin.Pair<kotlin.Int, kotlin.String>> origin=null
|
$this: GET_VAR 'val tmp0_iterator: kotlin.collections.Iterator<kotlin.Pair<kotlin.Int, kotlin.String>> [val] declared in <root>.testDestructuring' type=kotlin.collections.Iterator<kotlin.Pair<kotlin.Int, kotlin.String>> origin=null
|
||||||
VAR name:i type:kotlin.Int [val]
|
VAR name:i type:kotlin.Int [val]
|
||||||
|
|||||||
Reference in New Issue
Block a user