ForLoopsLowering: Reduce unnecessary temporary variables for the

"checked step" (check for a positive step arg) and "negated step"
(negate the step arg when the nested step is negative).
This commit is contained in:
Mark Punzalan
2020-07-16 00:42:36 -07:00
committed by Alexander Udalov
parent 291d62f653
commit b1ce21bc55
29 changed files with 153 additions and 173 deletions
@@ -9,23 +9,10 @@ package org.jetbrains.kotlin.backend.common.lower.loops
import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.ir.Symbols import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.ArrayIndicesHandler import org.jetbrains.kotlin.backend.common.lower.loops.handlers.*
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.ArrayIterationHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.CharSequenceIndicesHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.CharSequenceIterationHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.CollectionIndicesHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.DefaultIterableHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.DefaultProgressionHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.DownToHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.IndexedGetIterationHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.RangeToHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.ReversedHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.StepHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.StringIterationHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.UntilHandler
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.WithIndexHandler
import org.jetbrains.kotlin.backend.common.lower.matchers.IrCallMatcher import org.jetbrains.kotlin.backend.common.lower.matchers.IrCallMatcher
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -79,7 +66,7 @@ internal class ProgressionHeaderInfo(
canOverflow: Boolean? = null, canOverflow: Boolean? = null,
direction: ProgressionDirection, direction: ProgressionDirection,
additionalNotEmptyCondition: IrExpression? = null, additionalNotEmptyCondition: IrExpression? = null,
val additionalVariables: List<IrVariable> = listOf() val additionalStatements: List<IrStatement> = listOf()
) : NumericHeaderInfo( ) : NumericHeaderInfo(
progressionType, first, last, step, progressionType, first, last, step,
canCacheLast = true, canCacheLast = true,
@@ -156,7 +143,7 @@ internal class ProgressionHeaderInfo(
isReversed = !isReversed, isReversed = !isReversed,
direction = direction.asReversed(), direction = direction.asReversed(),
additionalNotEmptyCondition = additionalNotEmptyCondition, additionalNotEmptyCondition = additionalNotEmptyCondition,
additionalVariables = additionalVariables additionalStatements = additionalStatements
) )
} }
@@ -260,7 +260,7 @@ internal class ProgressionLoopHeader(
// //
// In the case of a reversed range, the `inductionVariable` and `last` variables are swapped, therefore the declaration order must be // In the case of a reversed range, the `inductionVariable` and `last` variables are swapped, therefore the declaration order must be
// swapped to preserve the correct evaluation order. // swapped to preserve the correct evaluation order.
override val loopInitStatements = headerInfo.additionalVariables + ( override val loopInitStatements = headerInfo.additionalStatements + (
if (headerInfo.isReversed) if (headerInfo.isReversed)
listOfNotNull(lastVariableIfCanCacheLast, inductionVariable) listOfNotNull(lastVariableIfCanCacheLast, inductionVariable)
else else
@@ -89,10 +89,10 @@ internal val IrExpression.constLongValue: Long?
*/ */
internal fun DeclarationIrBuilder.createTemporaryVariableIfNecessary( internal fun DeclarationIrBuilder.createTemporaryVariableIfNecessary(
expression: IrExpression, nameHint: String? = null, expression: IrExpression, nameHint: String? = null,
irType: IrType? = null irType: IrType? = null, isMutable: Boolean = false
): Pair<IrVariable?, IrExpression> = ): Pair<IrVariable?, IrExpression> =
if (expression.canHaveSideEffects) { if (expression.canHaveSideEffects) {
scope.createTmpVariable(expression, nameHint = nameHint, irType = irType).let { Pair(it, irGet(it)) } scope.createTmpVariable(expression, nameHint = nameHint, irType = irType, isMutable = isMutable).let { Pair(it, irGet(it)) }
} else { } else {
Pair(null, expression) Pair(null, expression)
} }
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
import org.jetbrains.kotlin.ir.util.getSimpleFunction import org.jetbrains.kotlin.ir.util.getSimpleFunction
import org.jetbrains.kotlin.util.OperatorNameConventions
/** Builds a [HeaderInfo] for Iterables not handled by more specialized handlers. */ /** Builds a [HeaderInfo] for Iterables not handled by more specialized handlers. */
internal open class DefaultIterableHandler(private val context: CommonBackendContext) : internal open class DefaultIterableHandler(private val context: CommonBackendContext) :
@@ -28,7 +29,7 @@ internal open class DefaultIterableHandler(private val context: CommonBackendCon
override fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo? = override fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo? =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) { with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
val iteratorFun = val iteratorFun =
iterableClassSymbol.getSimpleFunction(org.jetbrains.kotlin.util.OperatorNameConventions.ITERATOR.asString())!!.owner iterableClassSymbol.getSimpleFunction(OperatorNameConventions.ITERATOR.asString())!!.owner
IterableHeaderInfo( IterableHeaderInfo(
scope.createTmpVariable(irCall(iteratorFun).apply { dispatchReceiver = expression }, nameHint = "iterator") scope.createTmpVariable(irCall(iteratorFun).apply { dispatchReceiver = expression }, nameHint = "iterator")
) )
@@ -46,7 +46,7 @@ internal class DefaultProgressionHandler(private val context: CommonBackendConte
first, first,
last, last,
step, step,
additionalVariables = listOfNotNull(progressionVar), additionalStatements = listOfNotNull(progressionVar),
direction = ProgressionDirection.UNKNOWN direction = ProgressionDirection.UNKNOWN
) )
} }
@@ -11,10 +11,8 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.loops.* import org.jetbrains.kotlin.backend.common.lower.loops.*
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
import org.jetbrains.kotlin.backend.common.lower.matchers.singleArgumentExtension import org.jetbrains.kotlin.backend.common.lower.matchers.singleArgumentExtension
import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.irConcat import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.irIfThenElse
import org.jetbrains.kotlin.ir.builders.irString
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -59,15 +57,16 @@ 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.
val (stepArgVar, stepArgExpression) = createTemporaryVariableIfNecessary(stepArg, "stepArg") // This temporary variable for step needs to be mutable for certain cases (see below).
val (stepArgVar, stepArgExpression) = createTemporaryVariableIfNecessary(stepArg, "stepArg", isMutable = true)
// 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:
// //
// if (step > 0) step else throw IllegalArgumentException("Step must be positive, was: $step.") // if (step > 0) step else throw IllegalArgumentException("Step must be positive, was: $step.")
// //
// We insert this check in the lowered form only if necessary. // We insert a similar check in the lowered form only if necessary.
val stepType = data.stepClass.defaultType val stepType = data.stepClass.defaultType
val stepGreaterFun = context.irBuiltIns.greaterFunByOperandType.getValue(data.stepClass.symbol) val stepCompFun = context.irBuiltIns.lessOrEqualFunByOperandType.getValue(data.stepClass.symbol)
val zeroStep = data.run { zeroStepExpression() } val zeroStep = data.run { zeroStepExpression() }
val throwIllegalStepExceptionCall = { val throwIllegalStepExceptionCall = {
irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply { irCall(context.irBuiltIns.illegalArgumentExceptionSymbol).apply {
@@ -79,26 +78,25 @@ internal class StepHandler(
} }
} }
val stepArgValueAsLong = stepArgExpression.constLongValue val stepArgValueAsLong = stepArgExpression.constLongValue
val checkedStepExpression = when { val stepCheck: IrStatement? = when {
stepArgValueAsLong == null -> { stepArgValueAsLong == null -> {
// Step argument is not a constant. // Step argument is not a constant. In this case, we check if step <= 0.
val stepPositiveCheck = irCall(stepGreaterFun).apply { val stepNonPositiveCheck = irCall(stepCompFun).apply {
putValueArgument(0, stepArgExpression.deepCopyWithSymbols()) putValueArgument(0, stepArgExpression.deepCopyWithSymbols())
putValueArgument(1, zeroStep.deepCopyWithSymbols()) putValueArgument(1, zeroStep.deepCopyWithSymbols())
} }
irIfThenElse( irIfThen(
stepType, context.irBuiltIns.unitType,
stepPositiveCheck, stepNonPositiveCheck,
stepArgExpression.deepCopyWithSymbols(),
throwIllegalStepExceptionCall() throwIllegalStepExceptionCall()
) )
} }
stepArgValueAsLong > 0L -> stepArgValueAsLong <= 0L ->
// Step argument is a positive constant and is valid.
stepArgExpression.deepCopyWithSymbols()
else ->
// Step argument is a non-positive constant and is invalid, directly throw the exception. // Step argument is a non-positive constant and is invalid, directly throw the exception.
throwIllegalStepExceptionCall() throwIllegalStepExceptionCall()
else ->
// Step argument is a positive constant and is valid. No check is needed.
null
} }
// While the `step` function accepts positive values, the "step" value in the progression depends on the direction of the // While the `step` function accepts positive values, the "step" value in the progression depends on the direction of the
@@ -108,24 +106,49 @@ internal class StepHandler(
// If we don't know the direction of the nested progression (e.g., `someProgression() step 2`) then we have to check its value // If we don't know the direction of the nested progression (e.g., `someProgression() step 2`) then we have to check its value
// first to determine whether to negate. // first to determine whether to negate.
var nestedStepVar: IrVariable? = null var nestedStepVar: IrVariable? = null
var checkedStepVar: IrVariable? = null var stepNegation: IrStatement? = null
val checkedAndMaybeNegatedStep = when (nestedInfo.direction) { val finalStepExpression = when (nestedInfo.direction) {
ProgressionDirection.INCREASING -> checkedStepExpression ProgressionDirection.INCREASING -> stepArgExpression
ProgressionDirection.DECREASING -> checkedStepExpression.negate() ProgressionDirection.DECREASING -> {
if (stepArgVar == null) {
stepArgExpression.negate()
} else {
// Step is already stored in a variable, just negate it.
stepNegation = irSetVar(stepArgVar.symbol, irGet(stepArgVar).negate())
irGet(stepArgVar)
}
}
ProgressionDirection.UNKNOWN -> { ProgressionDirection.UNKNOWN -> {
// Check value of nested step and negate step arg if needed: `if (nestedStep > 0) checkedStep else -checkedStep` // Check value of nested step and negate step arg if needed: `if (nestedStep <= 0) -step else step`
// 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 (tmpNestedStepVar, nestedStepExpression) = createTemporaryVariableIfNecessary(nestedStep, "nestedStep") val (tmpNestedStepVar, nestedStepExpression) = createTemporaryVariableIfNecessary(nestedStep, "nestedStep")
nestedStepVar = tmpNestedStepVar nestedStepVar = tmpNestedStepVar
val nestedStepPositiveCheck = irCall(stepGreaterFun).apply { val nestedStepNonPositiveCheck = irCall(stepCompFun).apply {
putValueArgument(0, nestedStepExpression) putValueArgument(0, nestedStepExpression)
putValueArgument(1, zeroStep.deepCopyWithSymbols()) putValueArgument(1, zeroStep.deepCopyWithSymbols())
} }
if (stepArgVar == null) {
val (tmpCheckedStepVar, checkedStepOrGet) = createTemporaryVariableIfNecessary(checkedStepExpression, "checkedStep") // Create a temporary variable for the possibly-negated step, so we don't have to re-check every time step is used.
checkedStepVar = tmpCheckedStepVar stepNegation = scope.createTmpVariable(
irIfThenElse(stepType, nestedStepPositiveCheck, checkedStepOrGet, checkedStepOrGet.deepCopyWithSymbols().negate()) irIfThenElse(
stepType,
nestedStepNonPositiveCheck,
stepArgExpression.deepCopyWithSymbols().negate(),
stepArgExpression.deepCopyWithSymbols()
),
nameHint = "maybeNegatedStep"
)
irGet(stepNegation)
} else {
// Step is already stored in a variable, just negate it.
stepNegation = irIfThen(
context.irBuiltIns.unitType,
nestedStepNonPositiveCheck,
irSetVar(stepArgVar.symbol, irGet(stepArgVar).negate())
)
irGet(stepArgVar)
}
} }
} }
@@ -133,7 +156,6 @@ internal class StepHandler(
// evaluation order. // evaluation order.
val (nestedFirstVar, nestedFirstExpression) = createTemporaryVariableIfNecessary(nestedInfo.first, "nestedFirst") val (nestedFirstVar, nestedFirstExpression) = createTemporaryVariableIfNecessary(nestedInfo.first, "nestedFirst")
val (nestedLastVar, nestedLastExpression) = createTemporaryVariableIfNecessary(nestedInfo.last, "nestedLast") 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 // 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.
@@ -161,7 +183,7 @@ internal class StepHandler(
// 3), // 3),
// 2) // 2)
val recalculatedLast = val recalculatedLast =
callGetProgressionLastElementIfNecessary(data, nestedFirstExpression, nestedLastExpression, newStepExpression) callGetProgressionLastElementIfNecessary(data, nestedFirstExpression, nestedLastExpression, finalStepExpression)
// Consider the following for-loop: // Consider the following for-loop:
// //
@@ -176,29 +198,26 @@ internal class StepHandler(
// val innerNestedLast = B // val innerNestedLast = B
// // No nested step var because step for `A..B` is a constant 1 // // No nested step var because step for `A..B` is a constant 1
// val innerStepArg = C // val innerStepArg = C
// val innerNewStep = if (innerStepArg > 0) innerStepArg // if (innerStepArg <= 0) throw IllegalArgumentException("Step must be positive, was: $innerStepArg.")
// else throw IllegalArgumentException("Step must be positive, was: $innerStepArg.")
// //
// // Additional variables for outer step progression `(A..B step C) step D`: // // Additional variables for outer step progression `(A..B step C) step D`:
// // No nested first var because `innerNestedFirst` is a local variable get (cannot have side-effects) // // No nested first var because `innerNestedFirst` is a local variable get (cannot have side-effects)
// val outerNestedLast = // "last" for `A..B step C` // val outerNestedLast = // "last" for `A..B step C`
// getProgressionLastElement(innerNestedFirst, innerNestedLast, innerNewStep) // getProgressionLastElement(innerNestedFirst, innerNestedLast, innerStepArg)
// // No nested step var because nested step `innerNewStep` is a local variable get (cannot have side-effects) // // No nested step var because nested step `innerStepArg` is a local variable get (cannot have side-effects)
// val outerStepArg = D // val outerStepArg = D
// val outerNewStep = if (outerStepArg > 0) outerStepArg // if (outerStepArg <= 0) throw IllegalArgumentException("Step must be positive, was: $outerStepArg.")
// else throw IllegalArgumentException("Step must be positive, was: $outerStepArg.")
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = innerNestedFirst // var inductionVar = innerNestedFirst
// val last = // "last" for `(A..B step C) step D` // val last = // "last" for `(A..B step C) step D`
// getProgressionLastElement(innerNestedFirst, // "Passed through" from inner step progression // getProgressionLastElement(innerNestedFirst, // "Passed through" from inner step progression
// outerNestedLast, outerNewStep) // outerNestedLast, outerStepArg)
// val step = outerNewStep
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += outerStepArg
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -214,21 +233,19 @@ internal class StepHandler(
// val nestedFirst = progression.first // val nestedFirst = progression.first
// val nestedLast = progression.last // val nestedLast = progression.last
// val nestedStep = progression.step // val nestedStep = progression.step
// val stepArg = C // var stepArg = C
// val checkedStep = if (stepArg > 0) stepArg // if (stepArg <= 0) throw IllegalArgumentException("Step must be positive, was: $stepArg.")
// else throw IllegalArgumentException("Step must be positive, was: $stepArg.") // // Direction of P is unknown so we check its step to determine whether to negate
// val newStep = // Direction of P is unknown so we check its step to determine whether to negate // if (nestedStep <= 0) stepArg = -stepArg
// if (nestedStep > 0) checkedStep else -checkedStep
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = nestedFirst // var inductionVar = nestedFirst
// val last = getProgressionLastElement(nestedFirst, nestedLast, newStep) // val last = getProgressionLastElement(nestedFirst, nestedLast, stepArg)
// val step = newStep // if ((stepArg > 0 && inductionVar <= last) || (stepArg < 0 && last <= inductionVar)) {
// if ((step > 0 && inductionVar <= last) || (step < 0 && last <= inductionVar)) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += stepArg
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -239,19 +256,19 @@ internal class StepHandler(
// //
// ...in the nested HeaderInfo, "first" is `B` and "last" is `A` (the progression goes from `B` to `A`). Therefore in this case, // ...in the nested HeaderInfo, "first" is `B` and "last" is `A` (the progression goes from `B` to `A`). Therefore in this case,
// the nested "last" variable must come before the nested "first" variable (if both variables are necessary). // the nested "last" variable must come before the nested "first" variable (if both variables are necessary).
val additionalVariables = nestedInfo.additionalVariables + if (nestedInfo.isReversed) { val additionalStatements = nestedInfo.additionalStatements + if (nestedInfo.isReversed) {
listOfNotNull(nestedLastVar, nestedFirstVar, nestedStepVar, stepArgVar, checkedStepVar, newStepVar) listOfNotNull(nestedLastVar, nestedFirstVar, nestedStepVar, stepArgVar, stepCheck, stepNegation)
} else { } else {
listOfNotNull(nestedFirstVar, nestedLastVar, nestedStepVar, stepArgVar, checkedStepVar, newStepVar) listOfNotNull(nestedFirstVar, nestedLastVar, nestedStepVar, stepArgVar, stepCheck, stepNegation)
} }
return ProgressionHeaderInfo( return ProgressionHeaderInfo(
data, data,
first = nestedFirstExpression, first = nestedFirstExpression,
last = recalculatedLast, last = recalculatedLast,
step = newStepExpression, step = finalStepExpression,
isReversed = nestedInfo.isReversed, isReversed = nestedInfo.isReversed,
additionalVariables = additionalVariables, additionalStatements = additionalStatements,
additionalNotEmptyCondition = nestedInfo.additionalNotEmptyCondition, additionalNotEmptyCondition = nestedInfo.additionalNotEmptyCondition,
direction = nestedInfo.direction direction = nestedInfo.direction
) )
@@ -120,7 +120,7 @@ internal class UntilHandler(private val context: CommonBackendContext, private v
last = last, last = last,
step = irInt(1), step = irInt(1),
canOverflow = false, canOverflow = false,
additionalVariables = additionalVariables, additionalStatements = additionalVariables,
additionalNotEmptyCondition = additionalNotEmptyCondition, additionalNotEmptyCondition = additionalNotEmptyCondition,
direction = ProgressionDirection.INCREASING direction = ProgressionDirection.INCREASING
) )
@@ -15,12 +15,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 2 // var inductionVar = 2
// val last = getProgressionLastElement(2, Int.MIN_VALUE - 1, 2) // `(Int.MIN_VALUE - 1)` underflows to Int.MAX_VALUE // val last = getProgressionLastElement(2, Int.MIN_VALUE - 1, 2) // `(Int.MIN_VALUE - 1)` underflows to Int.MAX_VALUE
// val step = 2
// if (false && inductionVar <= last) { // `false` comes from constant folding of `Int.MIN_VALUE != Int.MIN_VALUE` // if (false && inductionVar <= last) { // `false` comes from constant folding of `Int.MIN_VALUE != Int.MIN_VALUE`
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -11,18 +11,17 @@ fun box(): String {
// //
// Expected lowered form of loop (before bytecode optimization): // Expected lowered form of loop (before bytecode optimization):
// //
// // Additional variables: // // Additional statements:
// val newStep = throw IllegalArgumentException("Step must be positive, was: 0.") // throw IllegalArgumentException("Step must be positive, was: 0.")
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = getProgressionLastElement(1, 6, newStep) // val last = getProgressionLastElement(1, 6, 0)
// val step = newStep
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 0
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -15,12 +15,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// val last = getProgressionLastElement(8, 1, -2) // val last = getProgressionLastElement(8, 1, -2)
// var inductionVar = 8 // var inductionVar = 8
// val step = -2
// if (last <= inductionVar) { // if (last <= inductionVar) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += -2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -15,12 +15,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = getProgressionLastElement(1, 7, 2) // val last = getProgressionLastElement(1, 7, 2)
// val step = 2
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -14,22 +14,21 @@ fun box(): String {
// //
// Expected lowered form of loop: // Expected lowered form of loop:
// //
// // Additional variables: // // Additional statements:
// val progression = intProgression // val progression = intProgression
// val nestedFirst = progression.first // val nestedFirst = progression.first
// val nestedLast = progression.last // val nestedLast = progression.last
// val nestedStep = progression.step // val nestedStep = progression.step
// val newStep = if (nestedStep > 0) 2 else -2 // val maybeNegatedStep = if (nestedStep <= 0) -2 else 2
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = nestedFirst // var inductionVar = nestedFirst
// val last = getProgressionLastElement(nestedFirst, nestedLast, newStep) // val last = getProgressionLastElement(nestedFirst, nestedLast, maybeNegatedStep)
// val step = newStep // if ((maybeNegatedStep > 0 && inductionVar <= last) || (maybeNegatedStep < 0 && last <= inductionVar)) {
// if ((step > 0 && inductionVar <= last) || (step < 0 && last <= inductionVar)) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += maybeNegatedStep
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -46,7 +45,8 @@ fun box(): String {
// 1 IF_ICMPGT // 1 IF_ICMPGT
// 1 IF_ICMPLE // 1 IF_ICMPLE
// 1 IF_ICMPNE // 1 IF_ICMPNE
// 2 IFLE // 1 IFLE
// 1 IFGT
// 1 IFGE // 1 IFGE
// 6 IF // 6 IF
// 0 INEG // 0 INEG
@@ -13,20 +13,18 @@ fun box(): String {
// //
// Expected lowered form of loop: // Expected lowered form of loop:
// //
// // Additional variables: // // Additional statements:
// val stepArg = one() // var stepArg = one()
// val newStep = if (stepArg > 0) stepArg // if (stepArg <= 0) throw IllegalArgumentException("Step must be positive, was: $stepArg.")
// else throw IllegalArgumentException("Step must be positive, was: $stepArg.")
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = getProgressionLastElement(1, 7, newStep) // val last = getProgressionLastElement(1, 7, stepArg)
// val step = newStep
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += stepArg
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -42,5 +40,5 @@ fun box(): String {
// 1 ATHROW // 1 ATHROW
// 1 IF_ICMPGT // 1 IF_ICMPGT
// 1 IF_ICMPNE // 1 IF_ICMPNE
// 1 IFLE // 1 IFGT
// 3 IF // 3 IF
@@ -15,25 +15,23 @@ fun box(): String {
// //
// Expected lowered form of loop: // Expected lowered form of loop:
// //
// // Additional variables: // // Additional statements:
// val progression = intProgression // val progression = intProgression
// val nestedFirst = progression.first // val nestedFirst = progression.first
// val nestedLast = progression.last // val nestedLast = progression.last
// val nestedStep = progression.step // val nestedStep = progression.step
// val stepArg = one() // var stepArg = one()
// val checkedStep = if (stepArg > 0) stepArg // if (stepArg <= 0) throw IllegalArgumentException("Step must be positive, was: $stepArg.")
// else throw IllegalArgumentException("Step must be positive, was: $stepArg.") // if (nestedStep <= 0) stepArg = -stepArg
// val newStep = if (nestedStep > 0) checkedStep else -checkedStep
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = nestedFirst // var inductionVar = nestedFirst
// val last = getProgressionLastElement(nestedFirst, nestedLast, newStep) // val last = getProgressionLastElement(nestedFirst, nestedLast, stepArg)
// val step = newStep // if ((stepArg > 0 && inductionVar <= last) || (stepArg < 0 && last <= inductionVar)) {
// if ((step > 0 && inductionVar <= last) || (step < 0 && last <= inductionVar)) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += stepArg
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -50,7 +48,8 @@ fun box(): String {
// 1 IF_ICMPGT // 1 IF_ICMPGT
// 1 IF_ICMPLE // 1 IF_ICMPLE
// 1 IF_ICMPNE // 1 IF_ICMPNE
// 3 IFLE // 1 IFLE
// 2 IFGT
// 1 IFGE // 1 IFGE
// 7 IF // 7 IF
// 1 INEG // 1 INEG
@@ -14,12 +14,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = 4 // val last = 4
// val step = 1
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 1
// // Loop body // // Loop body
// } while (inductionVar <= last) // } while (inductionVar <= last)
// } // }
@@ -14,12 +14,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = 4 // val last = 4
// val step = 1
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 1
// // Loop body // // Loop body
// } while (inductionVar <= last) // } while (inductionVar <= last)
// } // }
@@ -19,12 +19,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = getProgressionLastElement(1, outerNestedLast, 2) // val last = getProgressionLastElement(1, outerNestedLast, 2)
// val step = 2
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -15,12 +15,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// val last = 1 // val last = 1
// var inductionVar = getProgressionLastElement(1, 8, 2) // var inductionVar = getProgressionLastElement(1, 8, 2)
// val step = -2
// if (last <= inductionVar) { // if (last <= inductionVar) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += -2
// // Loop body // // Loop body
// } while (last <= inductionVar) // } while (last <= inductionVar)
// } // }
@@ -16,12 +16,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = getProgressionLastElement(1, 8, 2) // val last = getProgressionLastElement(1, 8, 2)
// val step = 2
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -13,24 +13,21 @@ fun box(): String {
// //
// Expected lowered form of loop: // Expected lowered form of loop:
// //
// // Additional variables: // // Additional statments:
// val innerStepArg = one() // var innerStepArg = one()
// val innerNewStep = if (innerStepArg > 0) innerStepArg // if (innerStepArg <= 0) throw IllegalArgumentException("Step must be positive, was: $innerStepArg.")
// else throw IllegalArgumentException("Step must be positive, was: $innerStepArg.") // val outerNestedLast = getProgressionLastElement(1, 6, innerStepArg)
// val outerNestedLast = getProgressionLastElement(1, 6, innerNewStep) // var outerStepArg = one()
// val outerStepArg = one() // if (outerStepArg <= 0) throw IllegalArgumentException("Step must be positive, was: $outerStepArg.")
// val outerNewStep = if (outerStepArg > 0) outerStepArg
// else throw IllegalArgumentException("Step must be positive, was: $outerStepArg.")
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = getProgressionLastElement(1, outerNestedLast, outerNewStep) // val last = getProgressionLastElement(1, outerNestedLast, outerStepArg)
// val step = outerNewStep
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += outerStepArg
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -46,5 +43,5 @@ fun box(): String {
// 2 ATHROW // 2 ATHROW
// 1 IF_ICMPGT // 1 IF_ICMPGT
// 1 IF_ICMPNE // 1 IF_ICMPNE
// 2 IFLE // 2 IFGT
// 4 IF // 4 IF
@@ -19,12 +19,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = innerNestedLast // val last = innerNestedLast
// val step = 1
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 1
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -12,19 +12,18 @@ fun box(): String {
// //
// Expected lowered form of loop (before bytecode optimizations): // Expected lowered form of loop (before bytecode optimizations):
// //
// // Additional variables: // // Additional statements:
// val untilArg = nine() // val untilArg = nine()
// val nestedLast = untilArg - 1 // val nestedLast = untilArg - 1
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = getProgressionLastElement(1, nestedLast, 2) // val last = getProgressionLastElement(1, nestedLast, 2)
// val step = 2
// if (untilArg != Int.MIN_VALUE && inductionVar <= last) { // if (untilArg != Int.MIN_VALUE && inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -16,12 +16,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 2u // var inductionVar = 2u
// val last = getProgressionLastElement(2u, UInt.MIN_VALUE - 1, 2) // `(UInt.MIN_VALUE - 1)` underflows to UInt.MAX_VALUE // val last = getProgressionLastElement(2u, UInt.MIN_VALUE - 1, 2) // `(UInt.MIN_VALUE - 1)` underflows to UInt.MAX_VALUE
// val step = 2
// if (false && inductionVar <= last) { // `false` comes from constant folding of `Int.MIN_VALUE != Int.MIN_VALUE` // if (false && inductionVar <= last) { // `false` comes from constant folding of `Int.MIN_VALUE != Int.MIN_VALUE`
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -12,18 +12,17 @@ fun box(): String {
// //
// Expected lowered form of loop (before bytecode optimization): // Expected lowered form of loop (before bytecode optimization):
// //
// // Additional variables: // // Additional statements:
// val newStep = throw IllegalArgumentException("Step must be positive, was: 0.") // throw IllegalArgumentException("Step must be positive, was: 0.")
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1u // var inductionVar = 1u
// val last = getProgressionLastElement(1u, 6u, newStep) // val last = getProgressionLastElement(1u, 6u, 0)
// val step = newStep
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 0
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -16,12 +16,11 @@ fun box(): String {
// // Standard form of loop over progression // // Standard form of loop over progression
// val last = getProgressionLastElement(8u, 1u, -2) // val last = getProgressionLastElement(8u, 1u, -2)
// var inductionVar = 8u // var inductionVar = 8u
// val step = -2
// if (last <= inductionVar) { // if (last <= inductionVar) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += -2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -15,22 +15,21 @@ fun box(): String {
// //
// Expected lowered form of loop: // Expected lowered form of loop:
// //
// // Additional variables: // // Additional statements:
// val progression = intProgression // val progression = intProgression
// val nestedFirst = progression.first // val nestedFirst = progression.first
// val nestedLast = progression.last // val nestedLast = progression.last
// val nestedStep = progression.step // val nestedStep = progression.step
// val newStep = if (nestedStep > 0) 2 else -2 // val maybeNegatedStep = if (nestedStep <= 0) -2 else 2
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = nestedFirst // var inductionVar = nestedFirst
// val last = getProgressionLastElement(nestedFirst, nestedLast, newStep) // val last = getProgressionLastElement(nestedFirst, nestedLast, maybeNegatedStep)
// val step = newStep // if ((maybeNegatedStep > 0 && inductionVar <= last) || (maybeNegatedStep < 0 && last <= inductionVar)) {
// if ((step > 0 && inductionVar <= last) || (step < 0 && last <= inductionVar)) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += maybeNegatedStep
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -45,9 +44,9 @@ fun box(): String {
// 0 NEW java/lang/IllegalArgumentException // 0 NEW java/lang/IllegalArgumentException
// 0 ATHROW // 0 ATHROW
// 2 INVOKESTATIC kotlin/UnsignedKt.uintCompare // 2 INVOKESTATIC kotlin/UnsignedKt.uintCompare
// 1 IFGT // 2 IFGT
// 1 IF_ICMPNE // 1 IF_ICMPNE
// 3 IFLE // 2 IFLE
// 1 IFGE // 1 IFGE
// 6 IF // 6 IF
// 0 INEG // 0 INEG
@@ -16,25 +16,23 @@ fun box(): String {
// //
// Expected lowered form of loop: // Expected lowered form of loop:
// //
// // Additional variables: // // Additional statements:
// val progression = intProgression // val progression = intProgression
// val nestedFirst = progression.first // val nestedFirst = progression.first
// val nestedLast = progression.last // val nestedLast = progression.last
// val nestedStep = progression.step // val nestedStep = progression.step
// val stepArg = one() // var stepArg = one()
// val checkedStep = if (stepArg > 0) stepArg // if (stepArg <= 0) throw IllegalArgumentException("Step must be positive, was: $stepArg.")
// else throw IllegalArgumentException("Step must be positive, was: $stepArg.") // if (nestedStep <= 0) stepArg = -stepArg
// val newStep = if (nestedStep > 0) checkedStep else -checkedStep
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = nestedFirst // var inductionVar = nestedFirst
// val last = getProgressionLastElement(nestedFirst, nestedLast, newStep) // val last = getProgressionLastElement(nestedFirst, nestedLast, stepArg)
// val step = newStep // if ((stepArg > 0 && inductionVar <= last) || (stepArg < 0 && last <= inductionVar)) {
// if ((step > 0 && inductionVar <= last) || (step < 0 && last <= inductionVar)) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += stepArg
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -49,9 +47,9 @@ fun box(): String {
// 1 NEW java/lang/IllegalArgumentException // 1 NEW java/lang/IllegalArgumentException
// 1 ATHROW // 1 ATHROW
// 2 INVOKESTATIC kotlin/UnsignedKt.uintCompare // 2 INVOKESTATIC kotlin/UnsignedKt.uintCompare
// 1 IFGT // 3 IFGT
// 1 IF_ICMPNE // 1 IF_ICMPNE
// 4 IFLE // 2 IFLE
// 1 IFGE // 1 IFGE
// 7 IF // 7 IF
// 1 INEG // 1 INEG
@@ -14,18 +14,17 @@ fun box(): String {
// //
// Expected lowered form of loop: // Expected lowered form of loop:
// //
// // Additional variables: // // Additional statements:
// val outerNestedLast = getProgressionLastElement(1u, 7u, 3) // val outerNestedLast = getProgressionLastElement(1u, 7u, 3)
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1u // var inductionVar = 1u
// val last = getProgressionLastElement(1u, outerNestedLast, 2) // val last = getProgressionLastElement(1u, outerNestedLast, 2)
// val step = 2
// if (inductionVar <= last) { // if (inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }
@@ -13,19 +13,18 @@ fun box(): String {
// //
// Expected lowered form of loop (before bytecode optimizations): // Expected lowered form of loop (before bytecode optimizations):
// //
// // Additional variables: // // Additional statements:
// val untilArg = nine() // val untilArg = nine()
// val nestedLast = untilArg - 1u // val nestedLast = untilArg - 1u
// //
// // Standard form of loop over progression // // Standard form of loop over progression
// var inductionVar = 1 // var inductionVar = 1
// val last = getProgressionLastElement(1u, nestedLast, 2) // val last = getProgressionLastElement(1u, nestedLast, 2)
// val step = 2
// if (untilArg != UInt.MIN_VALUE && inductionVar <= last) { // if (untilArg != UInt.MIN_VALUE && inductionVar <= last) {
// // Loop is not empty // // Loop is not empty
// do { // do {
// val i = inductionVar // val i = inductionVar
// inductionVar += step // inductionVar += 2
// // Loop body // // Loop body
// } while (i != last) // } while (i != last)
// } // }