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
@@ -393,6 +393,7 @@ internal open class RangeHeaderInfoBuilder(context: CommonBackendContext, scopeO
ArrayIndicesHandler(context),
CharSequenceIndicesHandler(context),
UntilHandler(context),
RangeUntilHandler(context),
DownToHandler(context),
RangeToHandler(context)
)
@@ -79,7 +79,7 @@ val forLoopsPhase = makeIrFilePhase(
* } while (loopVar != last)
* }
* ```
* If loop is an until loop (e.g., `for (i in A until B)`), it is transformed into:
* If loop is an until loop (e.g., `for (i in A until B)` or `for (i in A..<B)`, it is transformed into:
* ```
* var inductionVar = A
* val last = B - 1
@@ -266,6 +266,7 @@ internal abstract class HeaderInfoBuilder(
ArrayIndicesHandler(context),
CharSequenceIndicesHandler(context),
UntilHandler(context),
RangeUntilHandler(context),
DownToHandler(context),
RangeToHandler(context),
StepHandler(context, this)
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.lower.loops.handlers
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.loops.*
import org.jetbrains.kotlin.ir.builders.irInt
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.symbols.IrSymbol
/** Builds a [HeaderInfo] for progressions built using the `rangeUntil` member function (`..<` operator). */
internal class RangeUntilHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
override fun matchIterable(expression: IrCall): Boolean {
val callee = expression.symbol.owner
return callee.valueParameters.singleOrNull()?.type in progressionElementTypes &&
callee.extensionReceiverParameter == null &&
callee.dispatchReceiverParameter?.type in progressionElementTypes &&
callee.name.asString() == "rangeUntil"
}
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
ProgressionHeaderInfo(
data,
first = expression.dispatchReceiver!!,
last = expression.getValueArgument(0)!!,
step = irInt(1),
canOverflow = false,
isLastInclusive = false,
direction = ProgressionDirection.INCREASING
)
}
}