Extract utility function to create temporary variables if necessary.

This commit is contained in:
Mark Punzalan
2019-06-18 23:39:09 -07:00
committed by max-kammerer
parent 9bb9ab67a7
commit 3c775c598c
2 changed files with 30 additions and 49 deletions
@@ -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.
@@ -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)
}