Extract utility function to create temporary variables if necessary.
This commit is contained in:
committed by
max-kammerer
parent
9bb9ab67a7
commit
3c775c598c
+11
-42
@@ -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.
|
||||
|
||||
+19
-7
@@ -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
|
||||
} 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)
|
||||
}
|
||||
Reference in New Issue
Block a user