JVM_IR prefer loop with inclusive bound for unsigned integer ranges
In general, we would rather prefer a range-based for loop to look like
a counter loop in Java ('for (i = start; i < end; ++i) { <BODY> }').
This corresponds to
i = start;
do {
if (i >= end) break;
<BODY>
} while ( { ++i; true } )
However, HotSpot doesn't recognize Kotlin unsigned integer comparison
in 'if (i >= end) break;' as a counter loop condition. Thus, the loop
doesn't get optimized as a counter loop, resulting in a performance
regression.
If we use exclusive range-based for loop instead, then we actually use
unsigned integer equality instead of unsigned integer comparison, which
is Ok for HotSpot.
KT-49444
This commit is contained in:
+10
-2
@@ -314,8 +314,11 @@ class ProgressionLoopHeader(
|
||||
|
||||
override fun buildLoop(builder: DeclarationIrBuilder, oldLoop: IrLoop, newBody: IrExpression?) =
|
||||
with(builder) {
|
||||
if (headerInfo.canOverflow) {
|
||||
// If the induction variable CAN overflow, we cannot use it in the loop condition. Loop is lowered into something like:
|
||||
if (headerInfo.canOverflow ||
|
||||
preferJavaLikeCounterLoop && headerInfo.progressionType is UnsignedProgressionType && headerInfo.isLastInclusive
|
||||
) {
|
||||
// If the induction variable CAN overflow, we cannot use it in the loop condition.
|
||||
// Loop is lowered into something like:
|
||||
//
|
||||
// if (inductionVar <= last) {
|
||||
// // Loop is not empty
|
||||
@@ -325,6 +328,11 @@ class ProgressionLoopHeader(
|
||||
// // Loop body
|
||||
// } while (loopVar != last)
|
||||
// }
|
||||
//
|
||||
// This loop form is also preferable for loops over unsigned progressions on JVM,
|
||||
// because HotSpot doesn't recognize unsigned integer comparison as a counter loop condition.
|
||||
// Unsigned integer equality is fine, though.
|
||||
// See KT-49444 for performance comparison example.
|
||||
val newLoopOrigin = if (preferJavaLikeCounterLoop)
|
||||
this@ProgressionLoopHeader.context.doWhileCounterLoopOrigin
|
||||
else
|
||||
|
||||
+2
-1
@@ -63,7 +63,8 @@ internal class DownToHandler(private val context: CommonBackendContext) :
|
||||
|
||||
private fun IrExpression.convertToExclusiveLowerBound(progressionType: ProgressionType): IrExpression? {
|
||||
if (progressionType is UnsignedProgressionType) {
|
||||
if (this.constLongValue == 0L) return null
|
||||
// On JVM, prefer unsigned counter loop with inclusive bound
|
||||
if (preferJavaLikeCounterLoop || this.constLongValue == 0L) return null
|
||||
}
|
||||
|
||||
val irConst = this as? IrConst<*> ?: return null
|
||||
|
||||
+2
-1
@@ -63,7 +63,8 @@ internal class RangeToHandler(private val context: CommonBackendContext) :
|
||||
|
||||
private fun IrExpression.convertToExclusiveUpperBound(progressionType: ProgressionType): IrExpression? {
|
||||
if (progressionType is UnsignedProgressionType) {
|
||||
if (this.constLongValue == -1L) return null
|
||||
// On JVM, prefer unsigned counter loop with inclusive bound
|
||||
if (preferJavaLikeCounterLoop || this.constLongValue == -1L) return null
|
||||
}
|
||||
|
||||
val irConst = this as? IrConst<*> ?: return null
|
||||
|
||||
Reference in New Issue
Block a user