diff --git a/compiler/testData/codegen/bytecodeText/forLoop/forInUntil/forInUntilIntMinValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/forInUntil/forInUntilIntMinValue.kt index 54e1d5cf10e..0139b5f6453 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/forInUntil/forInUntilIntMinValue.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/forInUntil/forInUntilIntMinValue.kt @@ -17,10 +17,10 @@ fun f(a: Int): Int { // 0 getFirst // 0 getLast // 0 getStep -// 0 LINENUMBER 7 // JVM_TEMPLATES // 1 IF // JVM_IR_TEMPLATES -// 0 IF \ No newline at end of file +// 0 IF +// 0 LINENUMBER 6 diff --git a/compiler/testData/codegen/bytecodeText/forLoop/forInUntil/forInUntilLongMinValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/forInUntil/forInUntilLongMinValue.kt index 698e9735f93..7a0b506cdf3 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/forInUntil/forInUntilLongMinValue.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/forInUntil/forInUntilLongMinValue.kt @@ -17,10 +17,10 @@ fun f(a: Long): Int { // 0 getFirst // 0 getLast // 0 getStep -// 0 LINENUMBER 7 // JVM_TEMPLATES // 1 IF // JVM_IR_TEMPLATES -// 0 IF \ No newline at end of file +// 0 IF +// 0 LINENUMBER 6 diff --git a/compiler/testData/codegen/bytecodeText/forLoop/stepped/emptyUntilProgressionToMinValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/stepped/emptyUntilProgressionToMinValue.kt index 93ef1674acf..748c3a39e6a 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/stepped/emptyUntilProgressionToMinValue.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/stepped/emptyUntilProgressionToMinValue.kt @@ -14,7 +14,7 @@ fun box(): String { // // // Standard form of loop over progression // var inductionVar = 2 -// val last = getProgressionLastElement(1, Int.MIN_VALUE - 1, 2) // `(Int.MIN_VALUE - 1)` underflows to 2147483647 +// 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` // // Loop is not empty diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/emptyUntilProgressionToMinValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/emptyUntilProgressionToMinValue.kt new file mode 100644 index 00000000000..0190e80f543 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/emptyUntilProgressionToMinValue.kt @@ -0,0 +1,38 @@ +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +fun box(): String { + for (i in 2u until UInt.MIN_VALUE step 2) { + } + + return "OK" +} + +// For "until" progressions in JVM IR, there is a check that the range is not empty: upper bound != MIN_VALUE. +// When the upper bound == const MIN_VALUE, the backend can eliminate the entire loop as dead code. +// Calls to getProgressionLastElement() are still present because these happen before the eliminated loop. +// +// Expected lowered form of loop (before bytecode optimizations): +// +// // Standard form of loop over progression +// var inductionVar = 2u +// 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` +// // Loop is not empty +// do { +// val i = inductionVar +// inductionVar += step +// // Loop body +// } while (i != last) +// } + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 1 INVOKESTATIC kotlin/internal/UProgressionUtilKt.getProgressionLastElement +// 0 NEW java/lang/IllegalArgumentException +// 0 ATHROW +// 0 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToUIntMinValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToUIntMinValue.kt new file mode 100644 index 00000000000..cfd85a8a199 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToUIntMinValue.kt @@ -0,0 +1,19 @@ +// WITH_RUNTIME +const val M = UInt.MIN_VALUE + +fun f(a: UInt): Int { + var n = 0 + for (i in a downTo M) { + n++ + } + return n +} + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare +// 2 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToULongMinValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToULongMinValue.kt new file mode 100644 index 00000000000..d56a460ec8d --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToULongMinValue.kt @@ -0,0 +1,19 @@ +// WITH_RUNTIME +const val M = ULong.MIN_VALUE + +fun f(a: ULong): Int { + var n = 0 + for (i in a downTo M) { + n++ + } + return n +} + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 1 INVOKESTATIC kotlin/UnsignedKt.ulongCompare +// 2 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/forInOptimizableUnsignedRange.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInOptimizableUnsignedRange.kt similarity index 92% rename from compiler/testData/codegen/bytecodeText/forLoop/forInOptimizableUnsignedRange.kt rename to compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInOptimizableUnsignedRange.kt index ce704483297..c0ad14bcec1 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/forInOptimizableUnsignedRange.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInOptimizableUnsignedRange.kt @@ -51,3 +51,8 @@ fun testULongDownTo(a: ULong, b: ULong): Int { // 0 iterator // 0 hasNext // 0 next +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToUIntMaxValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToUIntMaxValue.kt new file mode 100644 index 00000000000..177dfbb1e89 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToUIntMaxValue.kt @@ -0,0 +1,18 @@ +const val M = UInt.MAX_VALUE + +fun f(a: UInt): Int { + var n = 0 + for (i in a..M) { + n++ + } + return n +} + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare +// 2 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToULongMaxValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToULongMaxValue.kt new file mode 100644 index 00000000000..5be062007c1 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToULongMaxValue.kt @@ -0,0 +1,19 @@ +// WITH_RUNTIME +const val M = ULong.MAX_VALUE + +fun f(a: ULong): Int { + var n = 0 + for (i in a..M) { + n++ + } + return n +} + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 1 INVOKESTATIC kotlin/UnsignedKt.ulongCompare +// 2 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMaxValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMaxValue.kt new file mode 100644 index 00000000000..8335e41d01a --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMaxValue.kt @@ -0,0 +1,31 @@ +// WITH_RUNTIME +const val M = UInt.MAX_VALUE + +fun f(a: UInt): Int { + var n = 0 + for (i in a until M) { + n++ + } + return n +} + +// JVM non-IR uses while. +// JVM IR uses if + do-while. + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep + +// JVM_TEMPLATES +// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare +// 1 IFGE +// 1 IF + +// JVM_IR_TEMPLATES +// 2 INVOKESTATIC kotlin/UnsignedKt.uintCompare +// 1 IFGT +// 1 IFLE +// 2 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMinValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMinValue.kt new file mode 100644 index 00000000000..1f9e1896f99 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMinValue.kt @@ -0,0 +1,27 @@ +// WITH_RUNTIME +const val M = UInt.MIN_VALUE + +fun f(a: UInt): Int { + var n = 0 + for (i in a until M) { + n++ + } + return n +} + +// For "until" progressions in JVM IR, there is a check that the range is not empty: upper bound != MIN_VALUE. +// When the upper bound == const MIN_VALUE, the backend can eliminate the entire loop as dead code. + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep + +// JVM_TEMPLATES +// 1 IF + +// JVM_IR_TEMPLATES +// 0 IF +// 0 LINENUMBER 7 diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMaxValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMaxValue.kt new file mode 100644 index 00000000000..3a03500ffc8 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMaxValue.kt @@ -0,0 +1,31 @@ +// WITH_RUNTIME +const val M = ULong.MAX_VALUE + +fun f(a: ULong): Int { + var n = 0 + for (i in a until M) { + n++ + } + return n +} + +// JVM non-IR uses while. +// JVM IR uses if + do-while. + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep + +// JVM_TEMPLATES +// 1 INVOKESTATIC kotlin/UnsignedKt.ulongCompare +// 1 IFGE +// 1 IF + +// JVM_IR_TEMPLATES +// 2 INVOKESTATIC kotlin/UnsignedKt.ulongCompare +// 1 IFGT +// 1 IFLE +// 2 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMinValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMinValue.kt new file mode 100644 index 00000000000..07f5bf762ed --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMinValue.kt @@ -0,0 +1,27 @@ +// WITH_RUNTIME +const val M = ULong.MIN_VALUE + +fun f(a: ULong): Int { + var n = 0 + for (i in a until M) { + n++ + } + return n +} + +// For "until" progressions in JVM IR, there is a check that the range is not empty: upper bound != MIN_VALUE. +// When the upper bound == const MIN_VALUE, the backend can eliminate the entire loop as dead code. + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep + +// JVM_TEMPLATES +// 1 IF + +// JVM_IR_TEMPLATES +// 0 IF +// 0 LINENUMBER 7 diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilWithMixedTypeBoundsNoBoundCheckNeededForUIntRangeIR.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilWithMixedTypeBoundsNoBoundCheckNeededForUIntRangeIR.kt new file mode 100644 index 00000000000..2fa3b5d4013 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilWithMixedTypeBoundsNoBoundCheckNeededForUIntRangeIR.kt @@ -0,0 +1,34 @@ +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +fun testUByteUntilUByte(a: UByte, b: UByte): UInt { + var sum = 0u + for (i in a until b) { + sum = sum * 10u + i + } + return sum +} + +fun testUShortUntilUShort(a: UShort, b: UShort): UInt { + var sum = 0u + for (i in a until b) { + sum = sum * 10u + i + } + return sum +} + +// For "until" progressions in JVM IR, there is typically a check that the range is not empty: upper bound != MIN_VALUE. +// However, this check is not needed when the upper bound is smaller than the range element type. +// Here are the available `until` extension functions with mixed bounds that return UIntRange: +// +// infix fun UByte.until(to: UByte): UIntRange // NO bound check needed +// infix fun UShort.until(to: UShort): UIntRange // NO bound check needed + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 2 IFGT +// 2 IFLE +// 4 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/illegalStepConst.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/illegalStepConst.kt new file mode 100644 index 00000000000..6f495e45130 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/illegalStepConst.kt @@ -0,0 +1,41 @@ +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +fun box(): String { + for (i in 1u..6u step 0) { + } + + return "OK" +} + +// For "step" progressions in JVM IR, if the step is constant and <= 0, the expression for step is replaced with an +// IllegalArgumentException. The backend can then eliminate the entire loop and the rest of the function as dead code. +// +// Expected lowered form of loop (before bytecode optimization): +// +// // Additional variables: +// val newStep = throw IllegalArgumentException("Step must be positive, was: 0.") +// +// // Standard form of loop over progression +// var inductionVar = 1u +// val last = getProgressionLastElement(1u, 6u, newStep) +// val step = newStep +// if (inductionVar <= last) { +// // Loop is not empty +// do { +// val i = inductionVar +// inductionVar += step +// // Loop body +// } while (i != last) +// } + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 0 INVOKESTATIC kotlin/internal/ProgressionUtilKt.getProgressionLastElement +// 1 NEW java/lang/IllegalArgumentException +// 1 ATHROW +// 0 IF +// 0 ARETURN \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/reversedThenStep.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/reversedThenStep.kt new file mode 100644 index 00000000000..5624d450da9 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/reversedThenStep.kt @@ -0,0 +1,43 @@ +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +fun box(): String { + for (i in (1u..8u).reversed() step 2) { + } + + return "OK" +} + +// For "step" progressions in JVM IR, a call to getProgressionLastElement() is made to compute the "last" value. +// If the step is non-constant, there is a check that it is > 0, and if not, an IllegalArgumentException is thrown. However, when the +// step is constant and > 0, this check does not need to be added. +// +// Expected lowered form of loop: +// +// // Standard form of loop over progression +// val last = getProgressionLastElement(8u, 1u, -2) +// var inductionVar = 8u +// val step = -2 +// if (last <= inductionVar) { +// // Loop is not empty +// do { +// val i = inductionVar +// inductionVar += step +// // Loop body +// } while (i != last) +// } +// +// We can't use "0 reversed" in the regex below because "reversed" is in the test filename. + +// 0 INVOKE.*reversed +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 1 INVOKESTATIC kotlin/internal/UProgressionUtilKt.getProgressionLastElement +// 0 NEW java/lang/IllegalArgumentException +// 0 ATHROW +// 1 IFGT +// 1 IF_ICMPNE +// 2 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepConstOnNonLiteralProgression.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepConstOnNonLiteralProgression.kt new file mode 100644 index 00000000000..81d05fe9315 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepConstOnNonLiteralProgression.kt @@ -0,0 +1,53 @@ +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +fun box(): String { + val uintProgression = 1u..7u + for (i in uintProgression step 2) { + } + + return "OK" +} + +// For "step" progressions in JVM IR, a call to getProgressionLastElement() is made to compute the "last" value. +// If "step" is called on a non-literal progression, there is a check to see if that progression's step value is < 0. +// If the step is non-constant, there is a check that it is > 0, and if not, an IllegalArgumentException is thrown. However, when the +// step is constant and > 0, this check does not need to be added. +// +// Expected lowered form of loop: +// +// // Additional variables: +// val progression = intProgression +// val nestedFirst = progression.first +// val nestedLast = progression.last +// val nestedStep = progression.step +// val newStep = if (nestedStep > 0) 2 else -2 +// +// // Standard form of loop over progression +// var inductionVar = nestedFirst +// val last = getProgressionLastElement(nestedFirst, nestedLast, newStep) +// val step = newStep +// if ((step > 0 && inductionVar <= last) || (step < 0 && last <= inductionVar)) { +// // Loop is not empty +// do { +// val i = inductionVar +// inductionVar += step +// // Loop body +// } while (i != last) +// } + +// 0 iterator +// 0 getStart +// 0 getEnd +// 1 getFirst +// 1 getLast +// 1 getStep +// 1 INVOKESTATIC kotlin/internal/UProgressionUtilKt.getProgressionLastElement +// 0 NEW java/lang/IllegalArgumentException +// 0 ATHROW +// 2 INVOKESTATIC kotlin/UnsignedKt.uintCompare +// 1 IFGT +// 1 IF_ICMPNE +// 3 IFLE +// 1 IFGE +// 6 IF +// 0 INEG \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepNonConstOnNonLiteralProgression.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepNonConstOnNonLiteralProgression.kt new file mode 100644 index 00000000000..b41db5c1409 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepNonConstOnNonLiteralProgression.kt @@ -0,0 +1,57 @@ +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +fun one() = 1 + +fun box(): String { + val uintProgression = 1u..7u + for (i in uintProgression step one()) { + } + + return "OK" +} + +// For "step" progressions in JVM IR, a call to getProgressionLastElement() is made to compute the "last" value. +// If "step" is called on a non-literal progression, there is a check to see if that progression's step value is < 0. +// If the step is non-constant, there is a check that it is > 0, and if not, an IllegalArgumentException is thrown. +// +// Expected lowered form of loop: +// +// // Additional variables: +// val progression = intProgression +// val nestedFirst = progression.first +// val nestedLast = progression.last +// val nestedStep = progression.step +// val stepArg = one() +// val checkedStep = if (stepArg > 0) stepArg +// else throw IllegalArgumentException("Step must be positive, was: $stepArg.") +// val newStep = if (nestedStep > 0) checkedStep else -checkedStep +// +// // Standard form of loop over progression +// var inductionVar = nestedFirst +// val last = getProgressionLastElement(nestedFirst, nestedLast, newStep) +// val step = newStep +// if ((step > 0 && inductionVar <= last) || (step < 0 && last <= inductionVar)) { +// // Loop is not empty +// do { +// val i = inductionVar +// inductionVar += step +// // Loop body +// } while (i != last) +// } + +// 0 iterator +// 0 getStart +// 0 getEnd +// 1 getFirst +// 1 getLast +// 1 getStep +// 1 INVOKESTATIC kotlin/internal/UProgressionUtilKt.getProgressionLastElement +// 1 NEW java/lang/IllegalArgumentException +// 1 ATHROW +// 2 INVOKESTATIC kotlin/UnsignedKt.uintCompare +// 1 IFGT +// 1 IF_ICMPNE +// 4 IFLE +// 1 IFGE +// 7 IF +// 1 INEG \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepThenDifferentStep.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepThenDifferentStep.kt new file mode 100644 index 00000000000..7579485bfa4 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepThenDifferentStep.kt @@ -0,0 +1,45 @@ +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +fun box(): String { + for (i in 1u..7u step 3 step 2) { + } + + return "OK" +} + +// For "step" progressions in JVM IR, a call to getProgressionLastElement() is made to compute the "last" value. This is done for each +// nested call to "step". +// If the step is non-constant, there is a check that it is > 0, and if not, an IllegalArgumentException is thrown. However, when the +// step is constant and > 0, this check does not need to be added. +// +// Expected lowered form of loop: +// +// // Additional variables: +// val outerNestedLast = getProgressionLastElement(1u, 7u, 3) +// +// // Standard form of loop over progression +// var inductionVar = 1u +// val last = getProgressionLastElement(1u, outerNestedLast, 2) +// val step = 2 +// if (inductionVar <= last) { +// // Loop is not empty +// do { +// val i = inductionVar +// inductionVar += step +// // Loop body +// } while (i != last) +// } + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 2 INVOKESTATIC kotlin/internal/UProgressionUtilKt.getProgressionLastElement +// 0 NEW java/lang/IllegalArgumentException +// 0 ATHROW +// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare +// 1 IFGT +// 1 IF_ICMPNE +// 2 IF \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/untilProgressionToNonConst.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/untilProgressionToNonConst.kt new file mode 100644 index 00000000000..08b9f106bea --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/untilProgressionToNonConst.kt @@ -0,0 +1,45 @@ +// TARGET_BACKEND: JVM_IR +// WITH_RUNTIME +fun nine() = 9u + +fun box(): String { + for (i in 1u until nine() step 2) { + } + + return "OK" +} + +// For "until" progressions in JVM IR, there is a check that the range is not empty: upper bound != MIN_VALUE. +// +// Expected lowered form of loop (before bytecode optimizations): +// +// // Additional variables: +// val untilArg = nine() +// val nestedLast = untilArg - 1u +// +// // Standard form of loop over progression +// var inductionVar = 1 +// val last = getProgressionLastElement(1u, nestedLast, 2) +// val step = 2 +// if (untilArg != UInt.MIN_VALUE && inductionVar <= last) { +// // Loop is not empty +// do { +// val i = inductionVar +// inductionVar += step +// // Loop body +// } while (i != last) +// } + +// 0 iterator +// 0 getStart +// 0 getEnd +// 0 getFirst +// 0 getLast +// 0 getStep +// 1 INVOKESTATIC kotlin/internal/UProgressionUtilKt.getProgressionLastElement +// 0 NEW java/lang/IllegalArgumentException +// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare +// 1 IFEQ +// 1 IFGT +// 1 IF_ICMPNE +// 3 IF \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index a95d33f7126..2d7480f2c05 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1931,11 +1931,6 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInObjectArray.kt"); } - @TestMetadata("forInOptimizableUnsignedRange.kt") - public void testForInOptimizableUnsignedRange() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/forLoop/forInOptimizableUnsignedRange.kt"); - } - @TestMetadata("forInPrimitiveArray.kt") public void testForInPrimitiveArray() throws Exception { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInPrimitiveArray.kt"); @@ -2477,6 +2472,64 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/stepped"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } } + + @TestMetadata("compiler/testData/codegen/bytecodeText/forLoop/unsigned") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Unsigned extends AbstractBytecodeTextTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInUnsigned() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/unsigned"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("forInDownToUIntMinValue.kt") + public void testForInDownToUIntMinValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToUIntMinValue.kt"); + } + + @TestMetadata("forInDownToULongMinValue.kt") + public void testForInDownToULongMinValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToULongMinValue.kt"); + } + + @TestMetadata("forInOptimizableUnsignedRange.kt") + public void testForInOptimizableUnsignedRange() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInOptimizableUnsignedRange.kt"); + } + + @TestMetadata("forInRangeToUIntMaxValue.kt") + public void testForInRangeToUIntMaxValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToUIntMaxValue.kt"); + } + + @TestMetadata("forInRangeToULongMaxValue.kt") + public void testForInRangeToULongMaxValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToULongMaxValue.kt"); + } + + @TestMetadata("forInUntilUIntMaxValue.kt") + public void testForInUntilUIntMaxValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMaxValue.kt"); + } + + @TestMetadata("forInUntilUIntMinValue.kt") + public void testForInUntilUIntMinValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMinValue.kt"); + } + + @TestMetadata("forInUntilULongMaxValue.kt") + public void testForInUntilULongMaxValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMaxValue.kt"); + } + + @TestMetadata("forInUntilULongMinValue.kt") + public void testForInUntilULongMinValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMinValue.kt"); + } + } } @TestMetadata("compiler/testData/codegen/bytecodeText/hashCode") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index 46ebd2b4c94..61b0b40d75d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -1886,11 +1886,6 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInObjectArray.kt"); } - @TestMetadata("forInOptimizableUnsignedRange.kt") - public void testForInOptimizableUnsignedRange() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/forLoop/forInOptimizableUnsignedRange.kt"); - } - @TestMetadata("forInPrimitiveArray.kt") public void testForInPrimitiveArray() throws Exception { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInPrimitiveArray.kt"); @@ -2522,6 +2517,104 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/forLoop/stepped/untilProgressionToNonConst.kt"); } } + + @TestMetadata("compiler/testData/codegen/bytecodeText/forLoop/unsigned") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Unsigned extends AbstractIrBytecodeTextTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + public void testAllFilesPresentInUnsigned() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/unsigned"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("emptyUntilProgressionToMinValue.kt") + public void testEmptyUntilProgressionToMinValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/emptyUntilProgressionToMinValue.kt"); + } + + @TestMetadata("forInDownToUIntMinValue.kt") + public void testForInDownToUIntMinValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToUIntMinValue.kt"); + } + + @TestMetadata("forInDownToULongMinValue.kt") + public void testForInDownToULongMinValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInDownToULongMinValue.kt"); + } + + @TestMetadata("forInOptimizableUnsignedRange.kt") + public void testForInOptimizableUnsignedRange() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInOptimizableUnsignedRange.kt"); + } + + @TestMetadata("forInRangeToUIntMaxValue.kt") + public void testForInRangeToUIntMaxValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToUIntMaxValue.kt"); + } + + @TestMetadata("forInRangeToULongMaxValue.kt") + public void testForInRangeToULongMaxValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToULongMaxValue.kt"); + } + + @TestMetadata("forInUntilUIntMaxValue.kt") + public void testForInUntilUIntMaxValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMaxValue.kt"); + } + + @TestMetadata("forInUntilUIntMinValue.kt") + public void testForInUntilUIntMinValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMinValue.kt"); + } + + @TestMetadata("forInUntilULongMaxValue.kt") + public void testForInUntilULongMaxValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMaxValue.kt"); + } + + @TestMetadata("forInUntilULongMinValue.kt") + public void testForInUntilULongMinValue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilULongMinValue.kt"); + } + + @TestMetadata("forInUntilWithMixedTypeBoundsNoBoundCheckNeededForUIntRangeIR.kt") + public void testForInUntilWithMixedTypeBoundsNoBoundCheckNeededForUIntRangeIR() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilWithMixedTypeBoundsNoBoundCheckNeededForUIntRangeIR.kt"); + } + + @TestMetadata("illegalStepConst.kt") + public void testIllegalStepConst() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/illegalStepConst.kt"); + } + + @TestMetadata("reversedThenStep.kt") + public void testReversedThenStep() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/reversedThenStep.kt"); + } + + @TestMetadata("stepConstOnNonLiteralProgression.kt") + public void testStepConstOnNonLiteralProgression() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepConstOnNonLiteralProgression.kt"); + } + + @TestMetadata("stepNonConstOnNonLiteralProgression.kt") + public void testStepNonConstOnNonLiteralProgression() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepNonConstOnNonLiteralProgression.kt"); + } + + @TestMetadata("stepThenDifferentStep.kt") + public void testStepThenDifferentStep() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/stepThenDifferentStep.kt"); + } + + @TestMetadata("untilProgressionToNonConst.kt") + public void testUntilProgressionToNonConst() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/unsigned/untilProgressionToNonConst.kt"); + } + } } @TestMetadata("compiler/testData/codegen/bytecodeText/hashCode")