Use while loop for progressions that cannot overflow (instead of

do-while with enclosing "not empty" check).

Also do not add additional "not empty" condition for `until` loops when
the given bound is a constant != MIN_VALUE.
This commit is contained in:
Mark Punzalan
2019-03-29 10:33:30 -07:00
committed by max-kammerer
parent ba0e016c4e
commit 7680e7fd56
25 changed files with 403 additions and 94 deletions
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -39,41 +40,50 @@ val forLoopsPhase = makeIrFilePhase(
* a simple while loop over primitive induction variable.
*
* For example, this loop:
*
* ```
* for (i in first..last step foo) { ... }
* for (i in first..last) { // Do something with i }
* ```
*
* is represented in IR in such a manner:
* ```
* val it = (first..last).iterator()
* while (it.hasNext()) {
* val i = it.next()
* // Do something with i
* }
* ```
* We transform it into one of the following loops:
*
* ```
* val it = (first..last step foo).iterator()
* while (it.hasNext()) {
* val i = it.next()
* ...
* }
* ```
* // 1. If the induction variable cannot overflow, i.e., `last` is const and != MAX_VALUE (if increasing, or MIN_VALUE if decreasing),
* // OR if loop is an until loop (e.g., `for (i in first until last)`):
*
* We transform it into the following loop:
* var inductionVar = first
* while (inductionVar <= last) { // (inductionVar >= last if the progression is decreasing)
* val i = inductionVar
* inductionVar++
* // Do something with i
* }
*
* ```
* var it = first
* if (it <= last) { // (it >= last if the progression is decreasing)
* do {
* val i = it++
* ...
* } while (i != last)
* }
* ```
*
* In case of iteration over array we transform it into following:
* // 2. If the induction variable CAN overflow, i.e., `last` is not const or is MAX/MIN_VALUE:
*
* var inductionVar = first
* if (inductionVar <= last) { // (inductionVar >= last if the progression is decreasing)
* // Loop is not empty
* do {
* val i = inductionVar
* inductionVar++
* // Do something with i
* } while (i != last)
* }
* ```
* while (it <= array.size - 1) {
* val i = array[it]
* it++
* ...
* }
* In case of iteration over an array, we transform it into the following:
* ```
* var inductionVar = 0
* val last = array.size - 1
* while (inductionVar <= last) {
* val i = array[inductionVar++]
* // Do something with i
* }
* ```
*/
internal class ForLoopsLowering(val context: CommonBackendContext) : FileLoweringPass {
@@ -202,17 +212,13 @@ private class RangeLoopTransformer(
// The "next" statement (at the top of the loop):
//
// ```
// val i = it.next()
// ```
// val i = it.next()
//
// ...is lowered into:
//
// ```
// val i = initialValue() // `inductionVariable` for progressions
// // `array[inductionVariable]` for arrays
// inductionVariable = inductionVariable + step
// ```
// val i = initializeLoopVariable() // `inductionVariable` for progressions
// // `array[inductionVariable]` for arrays
// inductionVariable = inductionVariable + step
return with(context.createIrBuilder(getScopeOwnerSymbol(), initializer.startOffset, initializer.endOffset)) {
variable.initializer = forLoopInfo.initializeLoopVariable(symbols, this)
val plusFun = forLoopInfo.inductionVariable.type.getClass()!!.functions.first {
@@ -65,7 +65,7 @@ internal sealed class HeaderInfo(
) {
val direction: ProgressionDirection by lazy {
// If step is a constant (either Int or Long), then we can determine the direction.
val stepValue = (step as? IrConst<*>)?.value as? Number?
val stepValue = (step as? IrConst<*>)?.value as? Number
val stepValueAsLong = stepValue?.toLong()
when {
stepValueAsLong == null -> ProgressionDirection.UNKNOWN
@@ -82,9 +82,42 @@ internal class ProgressionHeaderInfo(
first: IrExpression,
last: IrExpression,
step: IrExpression,
canOverflow: Boolean? = null,
val additionalVariables: List<IrVariable> = listOf(),
val additionalNotEmptyCondition: IrExpression? = null
) : HeaderInfo(progressionType, first, last, step)
) : HeaderInfo(progressionType, first, last, step) {
private val _canOverflow: Boolean? = canOverflow
val canOverflow: Boolean by lazy {
if (_canOverflow != null) return@lazy _canOverflow
// Induction variable can overflow if it is not a const, or is MAX/MIN_VALUE (depending on direction).
val lastValue = (last as? IrConst<*>)?.value
val lastValueAsLong = when (lastValue) {
is Number -> lastValue.toLong()
is Char -> lastValue.toLong()
else -> return@lazy true // If "last" is not a const Number or Char.
}
val constLimitAsLong = when (direction) {
ProgressionDirection.UNKNOWN ->
// If we don't know the direction, we can't be sure which limit to use.
return@lazy true
ProgressionDirection.DECREASING ->
when (progressionType) {
ProgressionType.INT_PROGRESSION -> Int.MIN_VALUE.toLong()
ProgressionType.CHAR_PROGRESSION -> Char.MIN_VALUE.toLong()
ProgressionType.LONG_PROGRESSION -> Long.MIN_VALUE
}
ProgressionDirection.INCREASING ->
when (progressionType) {
ProgressionType.INT_PROGRESSION -> Int.MAX_VALUE.toLong()
ProgressionType.CHAR_PROGRESSION -> Char.MAX_VALUE.toLong()
ProgressionType.LONG_PROGRESSION -> Long.MAX_VALUE
}
}
constLimitAsLong == lastValueAsLong
}
}
/** Information about a for-loop over an array. The internal induction variable used is an Int. */
internal class ArrayHeaderInfo(
@@ -66,24 +66,36 @@ internal class ProgressionLoopHeader(
get() = headerInfo.additionalVariables + listOf(inductionVariable, last, step)
override fun buildInnerLoop(builder: DeclarationIrBuilder, loop: IrLoop, newBody: IrExpression?): IrLoop = with(builder) {
// Condition: loopVariable != last
assert(loopVariable != null)
val booleanNotFun = context.irBuiltIns.booleanClass.functions.first { it.owner.name.asString() == "not" }
val newCondition = irCallOp(booleanNotFun, booleanNotFun.owner.returnType, irCall(context.irBuiltIns.eqeqSymbol).apply {
putValueArgument(0, irGet(loopVariable!!))
putValueArgument(1, irGet(last))
})
// TODO: Build while loop (instead of do-while) where possible, e.g., in "until" ranges, or when "last" is known to be < MAX_VALUE
IrDoWhileLoopImpl(loop.startOffset, loop.endOffset, loop.type, loop.origin).apply {
label = loop.label
condition = newCondition
body = newBody
if (headerInfo.canOverflow) {
// Condition: loopVariable != last. We cannot use the induction variable because it can overflow.
assert(loopVariable != null)
val booleanNotFun = context.irBuiltIns.booleanClass.functions.first { it.owner.name.asString() == "not" }
val newCondition = irCallOp(booleanNotFun, booleanNotFun.owner.returnType, irCall(context.irBuiltIns.eqeqSymbol).apply {
putValueArgument(0, irGet(loopVariable!!))
putValueArgument(1, irGet(last))
})
IrDoWhileLoopImpl(loop.startOffset, loop.endOffset, loop.type, loop.origin).apply {
label = loop.label
condition = newCondition
body = newBody
}
} else {
// If the induction variable cannot overflow, use a while loop using the "not empty" condition.
val newCondition = buildNotEmptyCondition(this@with)
IrWhileLoopImpl(loop.startOffset, loop.endOffset, loop.type, loop.origin).apply {
label = loop.label
condition = newCondition
body = newBody
}
}
}
// If the induction variable cannot overflow, we do NOT need the enclosing "not empty" check because the for-loop is lowered into a
// while loop that uses the "not empty" condition (see buildInnerLoop()); the enclosing check would be redundant.
override fun buildNotEmptyConditionIfNecessary(builder: DeclarationIrBuilder): IrExpression? =
if (headerInfo.canOverflow) buildNotEmptyCondition(builder) else null
private fun buildNotEmptyCondition(builder: DeclarationIrBuilder): IrExpression =
with(builder) {
val builtIns = context.irBuiltIns
val progressionKotlinType = progressionType.elementType(builtIns).toKotlinType()
@@ -158,7 +170,7 @@ internal class ArrayLoopHeader(
get() = listOf(headerInfo.arrayVariable, inductionVariable, last, step)
override fun buildInnerLoop(builder: DeclarationIrBuilder, loop: IrLoop, newBody: IrExpression?): IrLoop = with(builder) {
// Condition: loopVariable != last
// Condition: inductionVariable != last
val builtIns = context.irBuiltIns
val callee = builtIns.lessOrEqualFunByOperandType[builtIns.int]!!
val newCondition = irCall(callee).apply {
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.types.getClass
@@ -79,42 +80,65 @@ internal class UntilHandler(private val context: CommonBackendContext, private v
override fun build(call: IrCall, data: ProgressionType): HeaderInfo? =
with(context.createIrBuilder(call.symbol, call.startOffset, call.endOffset)) {
// `last = bound - 1` for the loop `for (i in first until bound)`.
val bound = scope.createTemporaryVariable(
ensureNotNullable(
call.getValueArgument(0)!!.castIfNecessary(
data.elementType(context.irBuiltIns),
data.elementCastFunctionName
)
), nameHint = "bound",
origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE
val boundArg = call.getValueArgument(0)!!
val bound = ensureNotNullable(
boundArg.castIfNecessary(
data.elementType(context.irBuiltIns),
data.elementCastFunctionName
)
)
val decFun = data.decFun(context.irBuiltIns)
val last = irCallOp(decFun.symbol, bound.type, irGet(bound))
// `bound` may be needed for an additional condition to the emptiness check (see comments below). If so, store `bound` in a
// temporary variable as it may be an expression with side-effects and we should only evaluate it once.
val boundVar = if (needsMinValueCondition(data, boundArg)) scope.createTemporaryVariable(
bound,
nameHint = "bound",
origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE
) else null
// The default "not empty" check cannot be used for the required for the corner case:
// `last = bound - 1` for the loop `for (i in first until bound)`.
val decFun = data.decFun(context.irBuiltIns)
val last = irCallOp(decFun.symbol, bound.type, if (boundVar != null) irGet(boundVar) else bound)
// The default "not empty" check cannot be used for the corner case:
//
// for (i in a until MIN_VALUE) {}
//
// ...which should always be considered an empty range. When the given bound is MIN_VALUE, and because `last = bound - 1`,
// "last" will underflow to MAX_VALUE, therefore the default "not empty" check:
//
// if (first <= last) { /* loop */ }
// if (inductionVar <= last) { /* loop */ }
//
// ...will always be true and won't consider the range as empty. Therefore, we need to add an additional condition to the
// emptiness check so that it becomes:
// "not empty" check so that it becomes:
//
// if (first <= last && bound > MIN_VALUE) { /* loop */ }
// if (inductionVar <= last && bound > MIN_VALUE) { /* loop */ }
ProgressionHeaderInfo(
data,
first = call.extensionReceiver!!,
last = last,
step = irInt(1),
additionalVariables = listOf(bound),
additionalNotEmptyCondition = buildMinValueCondition(data, irGet(bound))
canOverflow = false,
additionalVariables = listOfNotNull(boundVar),
additionalNotEmptyCondition = if (boundVar != null) buildMinValueCondition(data, irGet(boundVar)) else null
)
}
/** Returns true (i.e., min value condition is needed) if `bound` is non-const OR is MIN_VALUE. */
private fun needsMinValueCondition(progressionType: ProgressionType, bound: IrExpression): Boolean {
val boundValue = (bound as? IrConst<*>)?.value
val boundValueAsLong = when (boundValue) {
is Number -> boundValue.toLong()
is Char -> boundValue.toLong()
else -> return true // If "bound" is not a const Number or Char.
}
val minValueAsLong = when (progressionType) {
ProgressionType.INT_PROGRESSION -> Int.MIN_VALUE.toLong()
ProgressionType.CHAR_PROGRESSION -> Char.MIN_VALUE.toLong()
ProgressionType.LONG_PROGRESSION -> Long.MIN_VALUE
}
return minValueAsLong == boundValueAsLong
}
private fun DeclarationIrBuilder.buildMinValueCondition(progressionType: ProgressionType, bound: IrExpression): IrExpression {
val irBuiltIns = context.irBuiltIns
val minConst = when (progressionType) {
@@ -154,7 +178,8 @@ internal class IndicesHandler(val context: CommonBackendContext) : ProgressionHa
data,
first = irInt(0),
last = last,
step = irInt(1)
step = irInt(1),
canOverflow = false // Cannot overflow because `last` is at most MAX_VALUE - 1
)
}
}
@@ -0,0 +1,14 @@
const val M = Char.MIN_VALUE
fun f(a: Char) {
for (i in a downTo M) {
}
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 2 IF
@@ -0,0 +1,14 @@
const val M = Int.MIN_VALUE
fun f(a: Int) {
for (i in a downTo M) {
}
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 2 IF_ICMP
@@ -0,0 +1,15 @@
const val M = Long.MIN_VALUE
fun f(a: Long) {
for (i in a downTo M) {
}
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 2 LCMP
// 2 IF
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun test() {
var sum = 0
for (i in arrayOf("", "", "", "").indices) {
@@ -12,6 +11,4 @@ fun test() {
// 0 getFirst
// 0 getLast
// 0 IF_ICMPGT
// 0 IF_ICMPEQ
// 1 IF_ICMPGE
// 1 IF_ICMP
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun test() {
var sum = 0
for (i in intArrayOf(0, 0, 0, 0).indices) {
@@ -12,6 +11,4 @@ fun test() {
// 0 getFirst
// 0 getLast
// 0 IF_ICMPGT
// 0 IF_ICMPEQ
// 1 IF_ICMPGE
// 1 IF_ICMP
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
const val N = 'Z'
fun test(): Int {
@@ -9,5 +8,10 @@ fun test(): Int {
return sum
}
// 0 IF_ICMPEQ
// 1 IF_ICMPGT
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 IF_ICMP
@@ -0,0 +1,14 @@
const val M = Char.MAX_VALUE
fun f(a: Char) {
for (i in a..M) {
}
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 2 IF_ICMP
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
const val N = 42
fun test(): Int {
@@ -9,5 +8,10 @@ fun test(): Int {
return sum
}
// 0 IF_ICMPEQ
// 1 IF_ICMPGT
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 IF_ICMP
@@ -0,0 +1,14 @@
const val M = Int.MAX_VALUE
fun f(a: Int) {
for (i in a..M) {
}
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 2 IF_ICMP
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
const val N = 42L
fun test(): Long {
@@ -9,6 +8,14 @@ fun test(): Long {
return sum
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 LCMP
// 0 IFEQ
// 1 IFGT
// 1 IFGT
// 0 L2I
// 0 I2L
@@ -0,0 +1,15 @@
const val M = Long.MAX_VALUE
fun f(a: Long) {
for (i in a..M) {
}
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 2 LCMP
// 2 IF
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
object Host {
const val M = 1
const val N = 4
@@ -12,5 +11,10 @@ fun test(): Int {
return s
}
// 0 IF_ICMPEQ
// 1 IF_ICMPGT
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 IF_ICMP
@@ -11,4 +11,5 @@ fun test(): Int {
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 0 getStep
// 1 IF_ICMP
@@ -0,0 +1,14 @@
const val M = Char.MAX_VALUE
fun f(a: Char) {
for (i in a until M) {
}
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 IF_ICMP
@@ -0,0 +1,14 @@
const val M = Int.MAX_VALUE
fun f(a: Int) {
for (i in a until M) {
}
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 IF_ICMP
@@ -0,0 +1,15 @@
const val M = Long.MAX_VALUE
fun f(a: Long) {
for (i in a until M) {
}
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 LCMP
// 1 IF
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun test(): Int {
var sum = 0
for (i in 4 downTo 1) {
@@ -12,5 +11,4 @@ fun test(): Int {
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 IF_ICMPEQ
// 1 IF_ICMPLT
// 1 IF_ICMP
@@ -8,4 +8,5 @@ fun f() {
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 0 getStep
// 1 IF_ICMP
@@ -8,4 +8,5 @@ fun f(a: Int, b: Int) {
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 0 getStep
// 2 IF_ICMP
@@ -1627,6 +1627,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInCharSequence.kt");
}
@TestMetadata("forInDownToCharMinValue.kt")
public void testForInDownToCharMinValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInDownToCharMinValue.kt");
}
@TestMetadata("forInDownToIntMinValue.kt")
public void testForInDownToIntMinValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInDownToIntMinValue.kt");
}
@TestMetadata("forInDownToLongMinValue.kt")
public void testForInDownToLongMinValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInDownToLongMinValue.kt");
}
@TestMetadata("forInObjectArray.kt")
public void testForInObjectArray() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInObjectArray.kt");
@@ -1652,16 +1667,31 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToCharConst.kt");
}
@TestMetadata("forInRangeToCharMaxValue.kt")
public void testForInRangeToCharMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToCharMaxValue.kt");
}
@TestMetadata("forInRangeToConst.kt")
public void testForInRangeToConst() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToConst.kt");
}
@TestMetadata("forInRangeToIntMaxValue.kt")
public void testForInRangeToIntMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToIntMaxValue.kt");
}
@TestMetadata("forInRangeToLongConst.kt")
public void testForInRangeToLongConst() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToLongConst.kt");
}
@TestMetadata("forInRangeToLongMaxValue.kt")
public void testForInRangeToLongMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToLongMaxValue.kt");
}
@TestMetadata("forInRangeToQualifiedConst.kt")
public void testForInRangeToQualifiedConst() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToQualifiedConst.kt");
@@ -1682,6 +1712,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInUntil.kt");
}
@TestMetadata("forInUntilCharMaxValue.kt")
public void testForInUntilCharMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInUntilCharMaxValue.kt");
}
@TestMetadata("forInUntilIntMaxValue.kt")
public void testForInUntilIntMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInUntilIntMaxValue.kt");
}
@TestMetadata("forInUntilLongMaxValue.kt")
public void testForInUntilLongMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInUntilLongMaxValue.kt");
}
@TestMetadata("forIntInDownTo.kt")
public void testForIntInDownTo() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forIntInDownTo.kt");
@@ -1637,6 +1637,21 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInCharSequence.kt");
}
@TestMetadata("forInDownToCharMinValue.kt")
public void testForInDownToCharMinValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInDownToCharMinValue.kt");
}
@TestMetadata("forInDownToIntMinValue.kt")
public void testForInDownToIntMinValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInDownToIntMinValue.kt");
}
@TestMetadata("forInDownToLongMinValue.kt")
public void testForInDownToLongMinValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInDownToLongMinValue.kt");
}
@TestMetadata("forInObjectArray.kt")
public void testForInObjectArray() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInObjectArray.kt");
@@ -1662,16 +1677,31 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToCharConst.kt");
}
@TestMetadata("forInRangeToCharMaxValue.kt")
public void testForInRangeToCharMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToCharMaxValue.kt");
}
@TestMetadata("forInRangeToConst.kt")
public void testForInRangeToConst() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToConst.kt");
}
@TestMetadata("forInRangeToIntMaxValue.kt")
public void testForInRangeToIntMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToIntMaxValue.kt");
}
@TestMetadata("forInRangeToLongConst.kt")
public void testForInRangeToLongConst() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToLongConst.kt");
}
@TestMetadata("forInRangeToLongMaxValue.kt")
public void testForInRangeToLongMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToLongMaxValue.kt");
}
@TestMetadata("forInRangeToQualifiedConst.kt")
public void testForInRangeToQualifiedConst() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeToQualifiedConst.kt");
@@ -1692,6 +1722,21 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInUntil.kt");
}
@TestMetadata("forInUntilCharMaxValue.kt")
public void testForInUntilCharMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInUntilCharMaxValue.kt");
}
@TestMetadata("forInUntilIntMaxValue.kt")
public void testForInUntilIntMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInUntilIntMaxValue.kt");
}
@TestMetadata("forInUntilLongMaxValue.kt")
public void testForInUntilLongMaxValue() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forInUntilLongMaxValue.kt");
}
@TestMetadata("forIntInDownTo.kt")
public void testForIntInDownTo() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/forLoop/forIntInDownTo.kt");