Optimize rangeUntil operator in for-loops and contains

Newly added tests are basically copies of the existing tests on `until`.
Note that this operator is optimized for all backends, but the fact that
it's optimized is only checked for the JVM backend in bytecode text
tests.

 #KT-53330 Fixed
This commit is contained in:
Alexander Udalov
2022-12-09 14:57:22 +01:00
committed by Space Team
parent bc5acb5e9d
commit 28759a3ac3
17 changed files with 611 additions and 1 deletions
@@ -0,0 +1,37 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
// IMPORTANT!
// Please, when your changes cause failures in bytecodeText tests for 'for' loops,
// examine the resulting bytecode shape carefully.
// Range and progression-based loops generated with Kotlin compiler should be
// as close as possible to Java counter loops ('for (int i = a; i < b; ++i) { ... }').
// Otherwise it may result in performance regression due to missing HotSpot optimizations.
// Run Kotlin compiler benchmarks (https://github.com/Kotlin/kotlin-benchmarks)
// with compiler built from your changes if you are not sure.
fun test(a: Char, b: Char): String {
var s = ""
for (i in a..<b) {
s += i
}
return s
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 IF_ICMPGE
// 0 IF_ICMPLT
// 1 IF
// JVM_IR_TEMPLATES
// 5 ILOAD
// 2 ISTORE
// 1 IADD
// 0 ISUB
// 0 IINC
@@ -0,0 +1,39 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
// IMPORTANT!
// Please, when your changes cause failures in bytecodeText tests for 'for' loops,
// examine the resulting bytecode shape carefully.
// Range and progression-based loops generated with Kotlin compiler should be
// as close as possible to Java counter loops ('for (int i = a; i < b; ++i) { ... }').
// Otherwise it may result in performance regression due to missing HotSpot optimizations.
// Run Kotlin compiler benchmarks (https://github.com/Kotlin/kotlin-benchmarks)
// with compiler built from your changes if you are not sure.
const val M = Char.MAX_VALUE
fun f(a: Char): 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 IF_ICMPGE
// 0 IF_ICMPLT
// 1 IF
// JVM_IR_TEMPLATES
// 4 ILOAD
// 3 ISTORE
// 1 IADD
// 0 ISUB
// 1 IINC
@@ -0,0 +1,38 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
// IMPORTANT!
// Please, when your changes cause failures in bytecodeText tests for 'for' loops,
// examine the resulting bytecode shape carefully.
// Range and progression-based loops generated with Kotlin compiler should be
// as close as possible to Java counter loops ('for (int i = a; i < b; ++i) { ... }').
// Otherwise it may result in performance regression due to missing HotSpot optimizations.
// Run Kotlin compiler benchmarks (https://github.com/Kotlin/kotlin-benchmarks)
// with compiler built from your changes if you are not sure.
const val M = Char.MIN_VALUE
fun f(a: Char): 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 IFGE
// 1 IF
// JVM_IR_TEMPLATES
// 4 ILOAD
// 3 ISTORE
// 1 IADD
// 0 ISUB
// 1 IINC
@@ -0,0 +1,36 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
// IMPORTANT!
// Please, when your changes cause failures in bytecodeText tests for 'for' loops,
// examine the resulting bytecode shape carefully.
// Range and progression-based loops generated with Kotlin compiler should be
// as close as possible to Java counter loops ('for (int i = a; i < b; ++i) { ... }').
// Otherwise it may result in performance regression due to missing HotSpot optimizations.
// Run Kotlin compiler benchmarks (https://github.com/Kotlin/kotlin-benchmarks)
// with compiler built from your changes if you are not sure.
fun test(a: Int, b: Int): Int {
var sum = 0
for (i in a..<b) {
sum = sum * 10 + i
}
return sum
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 IF_ICMPGE
// 1 IF
// JVM_IR_TEMPLATES
// 6 ILOAD
// 3 ISTORE
// 1 IADD
// 0 ISUB
// 1 IINC
@@ -0,0 +1,38 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
// IMPORTANT!
// Please, when your changes cause failures in bytecodeText tests for 'for' loops,
// examine the resulting bytecode shape carefully.
// Range and progression-based loops generated with Kotlin compiler should be
// as close as possible to Java counter loops ('for (int i = a; i < b; ++i) { ... }').
// Otherwise it may result in performance regression due to missing HotSpot optimizations.
// Run Kotlin compiler benchmarks (https://github.com/Kotlin/kotlin-benchmarks)
// with compiler built from your changes if you are not sure.
const val M = Int.MAX_VALUE
fun f(a: Int): 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 IF_ICMPGE
// 1 IF
// JVM_IR_TEMPLATES
// 3 ILOAD
// 2 ISTORE
// 0 IADD
// 0 ISUB
// 2 IINC
@@ -0,0 +1,41 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
// IMPORTANT!
// Please, when your changes cause failures in bytecodeText tests for 'for' loops,
// examine the resulting bytecode shape carefully.
// Range and progression-based loops generated with Kotlin compiler should be
// as close as possible to Java counter loops ('for (int i = a; i < b; ++i) { ... }').
// Otherwise it may result in performance regression due to missing HotSpot optimizations.
// Run Kotlin compiler benchmarks (https://github.com/Kotlin/kotlin-benchmarks)
// with compiler built from your changes if you are not sure.
const val M = Int.MIN_VALUE
fun f(a: Int): Int {
var n = 0
for (i in a..<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
// 1 IF_ICMPGE
// 1 IF
// JVM_IR_TEMPLATES
// 3 ILOAD
// 2 ISTORE
// 0 IADD
// 0 ISUB
// 2 IINC
@@ -0,0 +1,37 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
// IMPORTANT!
// Please, when your changes cause failures in bytecodeText tests for 'for' loops,
// examine the resulting bytecode shape carefully.
// Range and progression-based loops generated with Kotlin compiler should be
// as close as possible to Java counter loops ('for (int i = a; i < b; ++i) { ... }').
// Otherwise it may result in performance regression due to missing HotSpot optimizations.
// Run Kotlin compiler benchmarks (https://github.com/Kotlin/kotlin-benchmarks)
// with compiler built from your changes if you are not sure.
fun test(a: Long, b: Long): Long {
var sum = 0L
for (i in a..<b) {
sum = sum * 10L + i
}
return sum
}
// 0 iterator
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
// 1 LCMP
// 1 IFGE
// 1 IF
// JVM_IR_TEMPLATES
// 0 ILOAD
// 0 ISTORE
// 0 IADD
// 0 ISUB
// 0 IINC
@@ -0,0 +1,39 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
// IMPORTANT!
// Please, when your changes cause failures in bytecodeText tests for 'for' loops,
// examine the resulting bytecode shape carefully.
// Range and progression-based loops generated with Kotlin compiler should be
// as close as possible to Java counter loops ('for (int i = a; i < b; ++i) { ... }').
// Otherwise it may result in performance regression due to missing HotSpot optimizations.
// Run Kotlin compiler benchmarks (https://github.com/Kotlin/kotlin-benchmarks)
// with compiler built from your changes if you are not sure.
const val M = Long.MAX_VALUE
fun f(a: Long): 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 LCMP
// 1 IFGE
// 1 IF
// JVM_IR_TEMPLATES
// 1 ILOAD
// 1 ISTORE
// 0 IADD
// 0 ISUB
// 1 IINC
@@ -0,0 +1,38 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
// IMPORTANT!
// Please, when your changes cause failures in bytecodeText tests for 'for' loops,
// examine the resulting bytecode shape carefully.
// Range and progression-based loops generated with Kotlin compiler should be
// as close as possible to Java counter loops ('for (int i = a; i < b; ++i) { ... }').
// Otherwise it may result in performance regression due to missing HotSpot optimizations.
// Run Kotlin compiler benchmarks (https://github.com/Kotlin/kotlin-benchmarks)
// with compiler built from your changes if you are not sure.
const val M = Long.MIN_VALUE
fun f(a: Long): 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 IFGE
// 1 IF
// JVM_IR_TEMPLATES
// 1 ILOAD
// 1 ISTORE
// 0 IADD
// 0 ISUB
// 1 IINC
@@ -0,0 +1,16 @@
// !OPT_IN: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JVM
fun testChar(a: Char, x: Char, y: Char) = a in x..<y
fun testByte(a: Byte, x: Byte, y: Byte) = a in x..<y
fun testShort(a: Short, x: Short, y: Short) = a in x..<y
fun testInt(a: Int, x: Int, y: Int) = a in x..<y
fun testLong(a: Long, x: Long, y: Long) = a in x..<y
// 0 until
// 0 INVOKEVIRTUAL
// 0 contains