Specialize Comparable#compareTo for boxed primitives

Support Comparable#compareTo for boxed primitive in redundant
boxing/unboxing analysis, along with CHECKCAST to java.lang.Comparable.

Note that we can do that for Float and Double, too, because
Float#compareTo(Float) and Double#compareTo(Double) are delegated to
Float#compare(float, float) and Double#compare(double, double),
respectively.

Fuse specialized comparison for integers with conditional jumps
if possible (both for Comparable#compareTo and Intrinsics#areEqual).

 #KT-11959 Fixed
This commit is contained in:
Dmitry Petrov
2017-05-19 10:34:15 +03:00
parent bd5b984da9
commit e1b41eee15
14 changed files with 526 additions and 30 deletions
@@ -0,0 +1,46 @@
inline fun ltx(a: Comparable<Any>, b: Any) = a < b
inline fun lex(a: Comparable<Any>, b: Any) = a <= b
inline fun gex(a: Comparable<Any>, b: Any) = a >= b
inline fun gtx(a: Comparable<Any>, b: Any) = a > b
inline fun lt(a: Any, b: Any) = ltx(a as Comparable<Any>, b)
inline fun le(a: Any, b: Any) = lex(a as Comparable<Any>, b)
inline fun ge(a: Any, b: Any) = gex(a as Comparable<Any>, b)
inline fun gt(a: Any, b: Any) = gtx(a as Comparable<Any>, b)
val ONE = 1
val ONEL = 1L
fun box(): String {
return when {
!lt(ONE, 42) -> "Fail 1 LT"
lt(42, ONE) -> "Fail 2 LT"
!le(ONE, 42) -> "Fail 1 LE"
le(42, ONE) -> "Fail 2 LE"
!le(1, ONE) -> "Fail 3 LE"
!ge(42, ONE) -> "Fail 1 GE"
ge(ONE, 42) -> "Fail 2 GE"
!ge(1, ONE) -> "Fail 3 GE"
gt(ONE, 42) -> "Fail 1 GT"
!gt(42, ONE) -> "Fail 2 GT"
!lt(ONEL, 42L) -> "Fail 1 LT L"
lt(42L, ONEL) -> "Fail 2 LT L"
!le(ONEL, 42L) -> "Fail 1 LE L"
le(42L, ONEL) -> "Fail 2 LE L"
!le(ONEL, 1L) -> "Fail 3 LE L"
!ge(42L, ONEL) -> "Fail 1 GE L"
ge(ONEL, 42L) -> "Fail 2 GE L"
!ge(ONEL, 1L) -> "Fail 3 GE L"
gt(ONEL, 42L) -> "Fail 1 GT L"
!gt(42L, ONEL) -> "Fail 2 GT L"
else -> "OK"
}
}
@@ -0,0 +1,21 @@
inline fun eq(a: Any, b: Any) = a == b
inline fun ne(a: Any, b: Any) = a != b
val ONE = 1
val ONEL = 1L
fun box(): String {
return when {
eq(ONE, 2) -> "Fail 1"
!eq(ONE, 1) -> "Fail 2"
!ne(ONE, 2) -> "Fail 3"
ne(ONE, 1) -> "Fail 4"
eq(ONEL, 42L) -> "Fail 1L"
!eq(ONEL, 1L) -> "Fail 2L"
!ne(ONEL, 42L) -> "Fail 3L"
ne(ONEL, 1L) -> "Fail 4L"
else -> "OK"
}
}
@@ -0,0 +1,82 @@
// IGNORE_BACKEND: JS, NATIVE
inline fun ltx(a: Comparable<Any>, b: Any) = a < b
inline fun lex(a: Comparable<Any>, b: Any) = a <= b
inline fun gex(a: Comparable<Any>, b: Any) = a >= b
inline fun gtx(a: Comparable<Any>, b: Any) = a > b
inline fun lt(a: Any, b: Any) = ltx(a as Comparable<Any>, b)
inline fun le(a: Any, b: Any) = lex(a as Comparable<Any>, b)
inline fun ge(a: Any, b: Any) = gex(a as Comparable<Any>, b)
inline fun gt(a: Any, b: Any) = gtx(a as Comparable<Any>, b)
val PLUS0F = 0.0F
val MINUS0F = -0.0F
val PLUS0D = 0.0
val MINUS0D = -0.0
fun box(): String {
return when {
!lt(1.0F, 42.0F) -> "Fail 1 LT F"
lt(42.0F, 1.0F) -> "Fail 2 LT F"
!le(1.0F, 42.0F) -> "Fail 1 LE F"
le(42.0F, 1.0F) -> "Fail 2 LE F"
!le(1.0F, 1.0F) -> "Fail 3 LE F"
!ge(42.0F, 1.0F) -> "Fail 1 GE F"
ge(1.0F, 42.0F) -> "Fail 2 GE F"
!ge(1.0F, 1.0F) -> "Fail 3 GE F"
gt(1.0F, 42.0F) -> "Fail 1 GT F"
!gt(42.0F, 1.0F) -> "Fail 2 GT F"
!lt(1.0, 42.0) -> "Fail 1 LT D"
lt(42.0, 1.0) -> "Fail 2 LT D"
!le(1.0, 42.0) -> "Fail 1 LE D"
le(42.0, 1.0) -> "Fail 2 LE D"
!le(1.0, 1.0) -> "Fail 3 LE D"
!ge(42.0, 1.0) -> "Fail 1 GE D"
ge(1.0, 42.0) -> "Fail 2 GE D"
!ge(1.0, 1.0) -> "Fail 3 GE D"
gt(1.0, 42.0) -> "Fail 1 GT D"
!gt(42.0, 1.0) -> "Fail 2 GT D"
!lt(MINUS0F, PLUS0F) -> "Fail 1 LT +-0 F"
lt(PLUS0F, MINUS0F) -> "Fail 2 LT +-0 F"
!le(MINUS0F, PLUS0F) -> "Fail 1 LE +-0 F"
le(PLUS0F, MINUS0F) -> "Fail 2 LE +-0 F"
!le(MINUS0F, MINUS0F) -> "Fail 3 LE +-0 F"
!le(PLUS0F, PLUS0F) -> "Fail 3 LE +-0 F"
ge(MINUS0F, PLUS0F) -> "Fail 1 GE +-0 F"
!ge(PLUS0F, MINUS0F) -> "Fail 2 GE +-0 F"
!ge(MINUS0F, MINUS0F) -> "Fail 3 GE +-0 F"
!ge(PLUS0F, PLUS0F) -> "Fail 3 GE +-0 F"
gt(MINUS0F, PLUS0F) -> "Fail 1 GT +-0 F"
!gt(PLUS0F, MINUS0F) -> "Fail 2 GT +-0 F"
!lt(MINUS0D, PLUS0D) -> "Fail 1 LT +-0 D"
lt(PLUS0D, MINUS0D) -> "Fail 2 LT +-0 D"
!le(MINUS0D, PLUS0D) -> "Fail 1 LE +-0 D"
le(PLUS0D, MINUS0D) -> "Fail 2 LE +-0 D"
!le(MINUS0D, MINUS0D) -> "Fail 3 LE +-0 D"
!le(PLUS0D, PLUS0D) -> "Fail 3 LE +-0 D"
ge(MINUS0D, PLUS0D) -> "Fail 1 GE +-0 D"
!ge(PLUS0D, MINUS0D) -> "Fail 2 GE +-0 D"
!ge(MINUS0D, MINUS0D) -> "Fail 3 GE +-0 D"
!ge(PLUS0D, PLUS0D) -> "Fail 3 GE +-0 D"
gt(MINUS0D, PLUS0D) -> "Fail 1 GT +-0 D"
!gt(PLUS0D, MINUS0D) -> "Fail 2 GT +-0 D"
else -> "OK"
}
}
@@ -0,0 +1,8 @@
fun box(): String {
val a: Any = 1
val b: Any = 42
val test = (a as Comparable<Any>).compareTo(b)
if (test != -1) return "Fail: $test"
return "OK"
}
@@ -0,0 +1,20 @@
// WITH_RUNTIME
fun box(): String {
val intList = listOf(1, 2, 3)
val longList = listOf(1L, 2L, 3L)
val intListMin = intList.minBy { it }
if (intListMin != 1) return "Fail intListMin=$intListMin"
val intListMax = intList.maxBy { it }
if (intListMax != 3) return "Fail intListMax=$intListMax"
val longListMin = longList.minBy { it }
if (longListMin != 1L) return "Fail longListMin=$longListMin"
val longListMax = longList.maxBy { it }
if (longListMax != 3L) return "Fail longListMax=$longListMax"
return "OK"
}