[JS_IR] Enable RangeContainsLowering optimizations.

This commit is contained in:
Mark Punzalan
2020-09-03 00:49:14 -07:00
committed by Roman
parent 88755a8d20
commit 16ab11289c
11 changed files with 105 additions and 137 deletions
@@ -335,6 +335,12 @@ private val returnableBlockLoweringPhase = makeBodyLoweringPhase(
prerequisite = setOf(functionInliningPhase)
)
private val rangeContainsLoweringPhase = makeBodyLoweringPhase(
::RangeContainsLowering,
name = "RangeContainsLowering",
description = "[Optimization] Optimizes calls to contains() for ClosedRanges"
)
private val forLoopsLoweringPhase = makeBodyLoweringPhase(
::ForLoopsLowering,
name = "ForLoopsLowering",
@@ -703,6 +709,7 @@ val loweringList = listOf<Lowering>(
propertyReferenceLoweringPhase,
interopCallableReferenceLoweringPhase,
returnableBlockLoweringPhase,
rangeContainsLoweringPhase,
forLoopsLoweringPhase,
primitiveCompanionLoweringPhase,
propertyAccessorInlinerLoweringPhase,
@@ -1,9 +1,5 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
class ComparablePair<T : Comparable<T>>(val first: T, val second: T) : Comparable<ComparablePair<T>> {
override fun compareTo(other: ComparablePair<T>): Int {
@@ -21,32 +17,33 @@ operator fun Float.rangeTo(other: Float) = object : ClosedFloatingPointRange<Flo
override fun lessThanOrEquals(a: Float, b: Float) = a >= b
}
// assert\((.*)\) \{\s*(".*")\s*}
fun check(x: Double, left: Double, right: Double): Boolean {
val result = x in left..right
val range = left..right
assert(result == x in range) { "Failed: unoptimized === unoptimized for custom double $range" }
assertTrue(result == x in range, "Failed: unoptimized === unoptimized for custom double $range")
return result
}
fun check(x: Float, left: Float, right: Float): Boolean {
val result = x in left..right
val range = left..right
assert(result == x in range) { "Failed: unoptimized === unoptimized for standard float $range" }
assertTrue(result == x in range, "Failed: unoptimized === unoptimized for standard float $range")
return result
}
fun box(): String {
assert("a" !in "b".."c")
assert("b" in "a".."d")
assertTrue("a" !in "b".."c")
assertTrue("b" in "a".."d")
assert(ComparablePair(2, 2) !in ComparablePair(1, 10)..ComparablePair(2, 1))
assert(ComparablePair(2, 2) in ComparablePair(2, 0)..ComparablePair(2, 10))
assertTrue(ComparablePair(2, 2) !in ComparablePair(1, 10)..ComparablePair(2, 1))
assertTrue(ComparablePair(2, 2) in ComparablePair(2, 0)..ComparablePair(2, 10))
assert(!check(-0.0, 0.0, 0.0))
assert(check(Double.NaN, Double.NaN, Double.NaN))
assertTrue(!check(-0.0, 0.0, 0.0))
assertTrue(check(Double.NaN, Double.NaN, Double.NaN))
assert(check(-0.0f, 0.0f, 0.0f))
assert(!check(Float.NaN, Float.NaN, Float.NaN))
assertTrue(check(-0.0f, 0.0f, 0.0f))
assertTrue(!check(Float.NaN, Float.NaN, Float.NaN))
return "OK"
}
@@ -1,23 +1,19 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
operator fun Int.rangeTo(right: String): ClosedRange<Int> = this..this + 1
operator fun Long.rangeTo(right: Double): ClosedRange<Long> = this..right.toLong() + 1
operator fun String.rangeTo(right: Int): ClosedRange<String> = this..this
fun box(): String {
assert(0 !in 1.."a")
assert(1 in 1.."a")
assertTrue(0 !in 1.."a")
assertTrue(1 in 1.."a")
assert(0L !in 1L..2.0)
assert(2L in 1L..3.0)
assertTrue(0L !in 1L..2.0)
assertTrue(2L in 1L..3.0)
assert("a" !in "b"..1)
assert("a" in "a"..1)
assertTrue("a" !in "b"..1)
assertTrue("a" in "a"..1)
return "OK"
}
+8 -12
View File
@@ -1,23 +1,19 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
fun box(): String {
for (x in 1..10) {
assert(x in 1..10)
assert(x + 10 !in 1..10)
assertTrue(x in 1..10)
assertTrue(x + 10 !in 1..10)
}
var x = 0
assert(0 !in 1..2)
assertTrue(0 !in 1..2)
assert(++x in 1..1)
assert(++x !in 1..1)
assertTrue(++x in 1..1)
assertTrue(++x !in 1..1)
assert(sideEffect(x) in 2..3)
assertTrue(sideEffect(x) in 2..3)
return "OK"
}
@@ -25,6 +21,6 @@ fun box(): String {
var invocationCounter = 0
fun sideEffect(x: Int): Int {
++invocationCounter
assert(invocationCounter == 1)
assertTrue(invocationCounter == 1)
return x
}
@@ -1,16 +1,12 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
fun check(x: Double, left: Double, right: Double): Boolean {
val result = x in left..right
val manual = x >= left && x <= right
val range = left..right
assert(result == manual) { "Failed: optimized === manual for $range" }
assert(result == checkUnoptimized(x, range)) { "Failed: optimized === unoptimized for $range" }
assertTrue(result == manual, "Failed: optimized === manual for $range")
assertTrue(result == checkUnoptimized(x, range), "Failed: optimized === unoptimized for $range")
return result
}
@@ -19,23 +15,23 @@ fun checkUnoptimized(x: Double, range: ClosedRange<Double>): Boolean {
}
fun box(): String {
assert(check(1.0, 0.0, 2.0))
assert(!check(1.0, -1.0, 0.0))
assertTrue(check(1.0, 0.0, 2.0))
assertTrue(!check(1.0, -1.0, 0.0))
assert(check(Double.MIN_VALUE, 0.0, 1.0))
assert(check(Double.MAX_VALUE, Double.MAX_VALUE - Double.MIN_VALUE, Double.MAX_VALUE))
assert(!check(Double.NaN, Double.NaN, Double.NaN))
assert(!check(0.0, Double.NaN, Double.NaN))
assertTrue(check(Double.MIN_VALUE, 0.0, 1.0))
assertTrue(check(Double.MAX_VALUE, Double.MAX_VALUE - Double.MIN_VALUE, Double.MAX_VALUE))
assertTrue(!check(Double.NaN, Double.NaN, Double.NaN))
assertTrue(!check(0.0, Double.NaN, Double.NaN))
assert(check(-0.0, -0.0, +0.0))
assert(check(-0.0, -0.0, -0.0))
assert(check(-0.0, +0.0, +0.0))
assert(check(+0.0, -0.0, -0.0))
assert(check(+0.0, +0.0, +0.0))
assert(check(+0.0, -0.0, +0.0))
assertTrue(check(-0.0, -0.0, +0.0))
assertTrue(check(-0.0, -0.0, -0.0))
assertTrue(check(-0.0, +0.0, +0.0))
assertTrue(check(+0.0, -0.0, -0.0))
assertTrue(check(+0.0, +0.0, +0.0))
assertTrue(check(+0.0, -0.0, +0.0))
var value = 0.0
assert(++value in 1.0..1.0)
assert(++value !in 1.0..1.0)
assertTrue(++value in 1.0..1.0)
assertTrue(++value !in 1.0..1.0)
return "OK"
}
@@ -1,16 +1,12 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
fun check(x: Float, left: Float, right: Float): Boolean {
val result = x in left..right
val manual = x >= left && x <= right
val range = left..right
assert(result == manual) { "Failed: optimized === manual for $range" }
assert(result == checkUnoptimized(x, range)) { "Failed: optimized === unoptimized for $range" }
assertTrue(result == manual, "Failed: optimized === manual for $range")
assertTrue(result == checkUnoptimized(x, range), "Failed: optimized === unoptimized for $range")
return result
}
@@ -19,23 +15,23 @@ fun checkUnoptimized(x: Float, range: ClosedRange<Float>): Boolean {
}
fun box(): String {
assert(check(1.0f, 0.0f, 2.0f))
assert(!check(1.0f, -1.0f, 0.0f))
assertTrue(check(1.0f, 0.0f, 2.0f))
assertTrue(!check(1.0f, -1.0f, 0.0f))
assert(check(Float.MIN_VALUE, 0.0f, 1.0f))
assert(check(Float.MAX_VALUE, Float.MAX_VALUE - Float.MIN_VALUE, Float.MAX_VALUE))
assert(!check(Float.NaN, Float.NaN, Float.NaN))
assert(!check(0.0f, Float.NaN, Float.NaN))
assertTrue(check(Float.MIN_VALUE, 0.0f, 1.0f))
assertTrue(check(Float.MAX_VALUE, Float.MAX_VALUE - Float.MIN_VALUE, Float.MAX_VALUE))
assertTrue(!check(Float.NaN, Float.NaN, Float.NaN))
assertTrue(!check(0.0f, Float.NaN, Float.NaN))
assert(check(-0.0f, -0.0f, +0.0f))
assert(check(-0.0f, -0.0f, -0.0f))
assert(check(-0.0f, +0.0f, +0.0f))
assert(check(+0.0f, -0.0f, -0.0f))
assert(check(+0.0f, +0.0f, +0.0f))
assert(check(+0.0f, -0.0f, +0.0f))
assertTrue(check(-0.0f, -0.0f, +0.0f))
assertTrue(check(-0.0f, -0.0f, -0.0f))
assertTrue(check(-0.0f, +0.0f, +0.0f))
assertTrue(check(+0.0f, -0.0f, -0.0f))
assertTrue(check(+0.0f, +0.0f, +0.0f))
assertTrue(check(+0.0f, -0.0f, +0.0f))
var value = 0.0f
assert(++value in 1.0f..1.0f)
assert(++value !in 1.0f..1.0f)
assertTrue(++value in 1.0f..1.0f)
assertTrue(++value !in 1.0f..1.0f)
return "OK"
}
@@ -1,16 +1,12 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
fun check(x: Int, left: Int, right: Int): Boolean {
val result = x in left..right
val manual = x >= left && x <= right
val range = left..right
assert(result == manual) { "Failed: optimized === manual for $range" }
assert(result == checkUnoptimized(x, range)) { "Failed: optimized === unoptimized for $range" }
assertTrue(result == manual, "Failed: optimized === manual for $range")
assertTrue(result == checkUnoptimized(x, range), "Failed: optimized === unoptimized for $range")
return result
}
@@ -19,16 +15,16 @@ fun checkUnoptimized(x: Int, range: ClosedRange<Int>): Boolean {
}
fun box(): String {
assert(check(1, 0, 2))
assert(!check(1, -1, 0))
assert(!check(239, 239, 238))
assert(check(239, 238, 239))
assertTrue(check(1, 0, 2))
assertTrue(!check(1, -1, 0))
assertTrue(!check(239, 239, 238))
assertTrue(check(239, 238, 239))
assert(check(Int.MIN_VALUE, Int.MIN_VALUE, Int.MIN_VALUE))
assert(check(Int.MAX_VALUE, Int.MIN_VALUE, Int.MAX_VALUE))
assertTrue(check(Int.MIN_VALUE, Int.MIN_VALUE, Int.MIN_VALUE))
assertTrue(check(Int.MAX_VALUE, Int.MIN_VALUE, Int.MAX_VALUE))
var value = 0
assert(++value in 1..1)
assert(++value !in 1..1)
assertTrue(++value in 1..1)
assertTrue(++value !in 1..1)
return "OK"
}
@@ -1,16 +1,12 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
fun check(x: Long, left: Long, right: Long): Boolean {
val result = x in left..right
val manual = x >= left && x <= right
val range = left..right
assert(result == manual) { "Failed: optimized === manual for $range" }
assert(result == checkUnoptimized(x, range)) { "Failed: optimized === unoptimized for $range" }
assertTrue(result == manual, "Failed: optimized === manual for $range")
assertTrue(result == checkUnoptimized(x, range), "Failed: optimized === unoptimized for $range")
return result
}
@@ -19,16 +15,16 @@ fun checkUnoptimized(x: Long, range: ClosedRange<Long>): Boolean {
}
fun box(): String {
assert(check(1L, 0L, 2L))
assert(!check(1L, -1L, 0L))
assert(!check(239L, 239L, 238L))
assert(check(239L, 238L, 239L))
assertTrue(check(1L, 0L, 2L))
assertTrue(!check(1L, -1L, 0L))
assertTrue(!check(239L, 239L, 238L))
assertTrue(check(239L, 238L, 239L))
assert(check(Long.MIN_VALUE, Long.MIN_VALUE, Long.MIN_VALUE))
assert(check(Long.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE))
assertTrue(check(Long.MIN_VALUE, Long.MIN_VALUE, Long.MIN_VALUE))
assertTrue(check(Long.MAX_VALUE, Long.MIN_VALUE, Long.MAX_VALUE))
var value = 0L
assert(++value in 1L..1L)
assert(++value !in 1L..1L)
assertTrue(++value in 1L..1L)
assertTrue(++value !in 1L..1L)
return "OK"
}
@@ -1,9 +1,5 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
class Value(val x: Int) : Comparable<Value> {
override fun compareTo(other: Value): Int {
@@ -22,8 +18,8 @@ class ValueRange(override val start: Value,
operator fun Value.rangeTo(other: Value): ClosedRange<Value> = ValueRange(this, other)
fun box(): String {
assert(Value(42) in Value(1)..Value(2))
assert(Value(41) !in Value(40)..Value(42))
assertTrue(Value(42) in Value(1)..Value(2))
assertTrue(Value(41) !in Value(40)..Value(42))
return "OK"
}
@@ -1,9 +1,5 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
fun Long.inLongs(l: Long, r: Long): Boolean {
return this in l..r
@@ -14,11 +10,11 @@ fun Double.inDoubles(l: Double, r: Double): Boolean {
}
fun box(): String {
assert(2L.inLongs(1L, 3L))
assert(!2L.inLongs(0L, 1L))
assertTrue(2L.inLongs(1L, 3L))
assertTrue(!2L.inLongs(0L, 1L))
assert(2.0.inDoubles(1.0, 3.0))
assert(!2.0.inDoubles(0.0, 1.0))
assertTrue(2.0.inDoubles(1.0, 3.0))
assertTrue(!2.0.inDoubles(0.0, 1.0))
return "OK"
}
@@ -1,17 +1,13 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_RUNTIME
import kotlin.test.*
fun box(): String {
assert(Long.MAX_VALUE !in Int.MIN_VALUE..Int.MAX_VALUE)
assert(Int.MAX_VALUE in Long.MIN_VALUE..Long.MAX_VALUE)
assert(Double.MAX_VALUE !in Float.MIN_VALUE..Float.MAX_VALUE)
assert(Float.MIN_VALUE in 0.0..1.0)
assert(2.0 !in 1.0f..0.0f)
assert(1L in 0..2)
assertTrue(Long.MAX_VALUE !in Int.MIN_VALUE..Int.MAX_VALUE)
assertTrue(Int.MAX_VALUE in Long.MIN_VALUE..Long.MAX_VALUE)
assertTrue(Double.MAX_VALUE !in Float.MIN_VALUE..Float.MAX_VALUE)
assertTrue(Float.MIN_VALUE in 0.0..1.0)
assertTrue(2.0 !in 1.0f..0.0f)
assertTrue(1L in 0..2)
return "OK"
}