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.
|
// To reduce local variable usage, we create and use temporary variables only if necessary.
|
||||||
var stepArgVar: IrVariable? = null
|
val (stepArgVar, stepArgExpression) = createTemporaryVariableIfNecessary(stepArg, "stepArg")
|
||||||
val stepArgExpression = if (stepArg.canHaveSideEffects) {
|
|
||||||
stepArgVar = scope.createTemporaryVariable(stepArg, nameHint = "stepArg")
|
|
||||||
irGet(stepArgVar)
|
|
||||||
} else {
|
|
||||||
stepArg
|
|
||||||
}
|
|
||||||
|
|
||||||
// The `step` standard library function only accepts positive values, and performs the following check:
|
// 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`
|
// 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.
|
// A temporary variable is created only if necessary, so we can preserve the evaluation order.
|
||||||
val nestedStep = nestedInfo.step
|
val nestedStep = nestedInfo.step
|
||||||
val nestedStepExpression = if (nestedStep.canHaveSideEffects) {
|
val (tmpNestedStepVar, nestedStepExpression) = createTemporaryVariableIfNecessary(nestedStep, "nestedStep")
|
||||||
nestedStepVar = scope.createTemporaryVariable(nestedStep, nameHint = "nestedStep")
|
nestedStepVar = tmpNestedStepVar
|
||||||
irGet(nestedStepVar)
|
|
||||||
} else {
|
|
||||||
nestedStep
|
|
||||||
}
|
|
||||||
val nestedStepPositiveCheck = irCall(stepGreaterFun).apply {
|
val nestedStepPositiveCheck = irCall(stepGreaterFun).apply {
|
||||||
putValueArgument(0, nestedStepExpression)
|
putValueArgument(0, nestedStepExpression)
|
||||||
putValueArgument(1, zeroStep.deepCopyWithSymbols())
|
putValueArgument(1, zeroStep.deepCopyWithSymbols())
|
||||||
}
|
}
|
||||||
|
|
||||||
checkedStepVar = scope.createTemporaryVariable(checkedStepExpression, nameHint = "checkedStep")
|
val (tmpCheckedStepVar, checkedStepOrGet) = createTemporaryVariableIfNecessary(checkedStepExpression, "checkedStep")
|
||||||
irIfThenElse(stepType, nestedStepPositiveCheck, irGet(checkedStepVar), irGet(checkedStepVar).negate())
|
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.
|
// Store the nested "first" and "last" and final "step" in temporary variables only if necessary, so we can preserve the
|
||||||
var newStepVar: IrVariable? = null
|
// evaluation order.
|
||||||
val newStepExpression = if (checkedAndMaybeNegatedStep.canHaveSideEffects) {
|
val (nestedFirstVar, nestedFirstExpression) = createTemporaryVariableIfNecessary(nestedInfo.first, "nestedFirst")
|
||||||
newStepVar = scope.createTemporaryVariable(checkedAndMaybeNegatedStep, nameHint = "newStep")
|
val (nestedLastVar, nestedLastExpression) = createTemporaryVariableIfNecessary(nestedInfo.last, "nestedLast")
|
||||||
irGet(newStepVar)
|
val (newStepVar, newStepExpression) = createTemporaryVariableIfNecessary(checkedAndMaybeNegatedStep, "newStep")
|
||||||
} 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating a progression with a step value != 1 may result in a "last" value that is smaller than the given "last". The new
|
// 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.
|
// "last" value is such that iterating over the progression (by incrementing by "step") does not go over the "last" value.
|
||||||
|
|||||||
+18
-6
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.lower.loops
|
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.IrConst
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
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(). */
|
/** Return the negated value if the expression is const, otherwise call unaryMinus(). */
|
||||||
internal fun IrExpression.negate(): IrExpression {
|
internal fun IrExpression.negate(): IrExpression {
|
||||||
val value = (this as? IrConst<*>)?.value as? Number
|
return when (val value = (this as? IrConst<*>)?.value as? Number) {
|
||||||
return when (value) {
|
|
||||||
is Int -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Int, -value)
|
is Int -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Int, -value)
|
||||||
is Long -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Long, -value)
|
is Long -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Long, -value)
|
||||||
else -> {
|
else -> {
|
||||||
@@ -44,8 +45,7 @@ internal fun IrExpression.negate(): IrExpression {
|
|||||||
|
|
||||||
/** Return `this - 1` if the expression is const, otherwise call dec(). */
|
/** Return `this - 1` if the expression is const, otherwise call dec(). */
|
||||||
internal fun IrExpression.decrement(): IrExpression {
|
internal fun IrExpression.decrement(): IrExpression {
|
||||||
val thisValue = (this as? IrConst<*>)?.value
|
return when (val thisValue = (this as? IrConst<*>)?.value) {
|
||||||
return when (thisValue) {
|
|
||||||
is Int -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Int, thisValue - 1)
|
is Int -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Int, thisValue - 1)
|
||||||
is Long -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Long, thisValue - 1)
|
is Long -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Long, thisValue - 1)
|
||||||
is Char -> IrConstImpl(startOffset, endOffset, type, IrConstKind.Char, 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?
|
internal val IrExpression.constLongValue: Long?
|
||||||
get() = if (this is IrConst<*>) {
|
get() = if (this is IrConst<*>) {
|
||||||
val value = this.value
|
when (val value = this.value) {
|
||||||
when (value) {
|
|
||||||
is Number -> value.toLong()
|
is Number -> value.toLong()
|
||||||
is Char -> value.toLong()
|
is Char -> value.toLong()
|
||||||
else -> null
|
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