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 e146b0b7cc0..20bb5fae1d8 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 @@ -250,13 +250,7 @@ internal class StepHandler( } // To reduce local variable usage, we create and use temporary variables only if necessary. - var stepArgVar: IrVariable? = null - val stepArgExpression = if (stepArg.canHaveSideEffects) { - stepArgVar = scope.createTemporaryVariable(stepArg, nameHint = "stepArg") - irGet(stepArgVar) - } else { - stepArg - } + val (stepArgVar, stepArgExpression) = createTemporaryVariableIfNecessary(stepArg, "stepArg") // The `step` standard library function only accepts positive values, and performs the following check: // @@ -313,49 +307,24 @@ internal class StepHandler( // Check value of nested step and negate step arg if needed: `if (nestedStep > 0) nestedStep else -nestedStep` // A temporary variable is created only if necessary, so we can preserve the evaluation order. val nestedStep = nestedInfo.step - val nestedStepExpression = if (nestedStep.canHaveSideEffects) { - nestedStepVar = scope.createTemporaryVariable(nestedStep, nameHint = "nestedStep") - irGet(nestedStepVar) - } else { - nestedStep - } + val (tmpNestedStepVar, nestedStepExpression) = createTemporaryVariableIfNecessary(nestedStep, "nestedStep") + nestedStepVar = tmpNestedStepVar val nestedStepPositiveCheck = irCall(stepGreaterFun).apply { putValueArgument(0, nestedStepExpression) putValueArgument(1, zeroStep.deepCopyWithSymbols()) } - checkedStepVar = scope.createTemporaryVariable(checkedStepExpression, nameHint = "checkedStep") - irIfThenElse(stepType, nestedStepPositiveCheck, irGet(checkedStepVar), irGet(checkedStepVar).negate()) + val (tmpCheckedStepVar, checkedStepOrGet) = createTemporaryVariableIfNecessary(checkedStepExpression, "checkedStep") + checkedStepVar = tmpCheckedStepVar + irIfThenElse(stepType, nestedStepPositiveCheck, checkedStepOrGet, checkedStepOrGet.deepCopyWithSymbols().negate()) } } - // Store the final "step" a temporary variable only if necessary, so we can preserve the evaluation order. - var newStepVar: IrVariable? = null - val newStepExpression = if (checkedAndMaybeNegatedStep.canHaveSideEffects) { - newStepVar = scope.createTemporaryVariable(checkedAndMaybeNegatedStep, nameHint = "newStep") - irGet(newStepVar) - } else { - checkedAndMaybeNegatedStep - } - - // Store the nested "first" and "last" in temporary variables only if necessary, so we can preserve the evaluation order. - var nestedFirstVar: IrVariable? = null - val nestedFirst = nestedInfo.first - val nestedFirstExpression = if (nestedFirst.canHaveSideEffects) { - nestedFirstVar = scope.createTemporaryVariable(nestedFirst, nameHint = "nestedFirst") - irGet(nestedFirstVar) - } else { - nestedFirst - } - - var nestedLastVar: IrVariable? = null - val nestedLast = nestedInfo.last - val nestedLastExpression = if (nestedLast.canHaveSideEffects) { - nestedLastVar = scope.createTemporaryVariable(nestedLast, nameHint = "nestedLast") - irGet(nestedLastVar) - } else { - nestedLast - } + // Store the nested "first" and "last" and final "step" in temporary variables only if necessary, so we can preserve the + // evaluation order. + val (nestedFirstVar, nestedFirstExpression) = createTemporaryVariableIfNecessary(nestedInfo.first, "nestedFirst") + val (nestedLastVar, nestedLastExpression) = createTemporaryVariableIfNecessary(nestedInfo.last, "nestedLast") + val (newStepVar, newStepExpression) = createTemporaryVariableIfNecessary(checkedAndMaybeNegatedStep, "newStep") // Creating a progression with a step value != 1 may result in a "last" value that is smaller than the given "last". The new // "last" value is such that iterating over the progression (by incrementing by "step") does not go over the "last" value. diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt index 108102e6b3b..1f56dd0a257 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.backend.common.lower.loops +import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder +import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrConstKind import org.jetbrains.kotlin.ir.expressions.IrExpression @@ -29,8 +31,7 @@ internal fun IrExpression.castIfNecessary(targetType: IrType, numberCastFunction /** Return the negated value if the expression is const, otherwise call unaryMinus(). */ internal fun IrExpression.negate(): IrExpression { - val value = (this as? IrConst<*>)?.value as? Number - return when (value) { + return when (val value = (this as? IrConst<*>)?.value as? Number) { is Int -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Int, -value) is Long -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Long, -value) else -> { @@ -44,8 +45,7 @@ internal fun IrExpression.negate(): IrExpression { /** Return `this - 1` if the expression is const, otherwise call dec(). */ internal fun IrExpression.decrement(): IrExpression { - val thisValue = (this as? IrConst<*>)?.value - return when (thisValue) { + return when (val thisValue = (this as? IrConst<*>)?.value) { is Int -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Int, thisValue - 1) is Long -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Long, thisValue - 1) is Char -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Char, thisValue - 1) @@ -63,10 +63,22 @@ internal val IrExpression.canHaveSideEffects: Boolean internal val IrExpression.constLongValue: Long? get() = if (this is IrConst<*>) { - val value = this.value - when (value) { + when (val value = this.value) { is Number -> value.toLong() is Char -> value.toLong() else -> null } - } else null \ No newline at end of file + } else null + +/** + * If [expression] can have side effects ([IrExpression.canHaveSideEffects]), this function creates a temporary local variable for that + * expression and returns that variable and an [IrGetValue] for it. Otherwise, it returns no variable and [expression]. + * + * This helps reduce local variable usage. + */ +internal fun DeclarationIrBuilder.createTemporaryVariableIfNecessary(expression: IrExpression, nameHint: String? = null) = + if (expression.canHaveSideEffects) { + scope.createTemporaryVariable(expression, nameHint = nameHint).let { Pair(it, irGet(it)) } + } else { + Pair(null, expression) + } \ No newline at end of file