IR: simplify for-loop lowering internals a bit

Remove ExpressionHandler, HeaderInfoFromCallHandler, ProgressionHandler.
This commit is contained in:
Alexander Udalov
2022-12-09 15:53:59 +01:00
parent 812e257d54
commit 18950b448c
13 changed files with 74 additions and 87 deletions
@@ -411,15 +411,16 @@ internal open class RangeHeaderInfoBuilder(context: CommonBackendContext, scopeO
}
/** Builds a [HeaderInfo] for closed floating-point ranges built using the `rangeTo` function. */
internal object FloatingPointRangeToHandler : HeaderInfoFromCallHandler<Nothing?> {
override val matcher = SimpleCalleeMatcher {
internal object FloatingPointRangeToHandler : HeaderInfoHandler<IrCall, Nothing?> {
private val matcher = SimpleCalleeMatcher {
fqName { it == FqName("kotlin.ranges.${OperatorNameConventions.RANGE_TO}") }
extensionReceiver { it != null && it.type.run { isFloat() || isDouble() } }
parameterCount { it == 1 }
parameter(0) { it.type.run { isFloat() || isDouble() } }
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
FloatingPointRangeHeaderInfo(
start = expression.extensionReceiver!!,
@@ -428,14 +429,15 @@ internal object FloatingPointRangeToHandler : HeaderInfoFromCallHandler<Nothing?
}
/** Builds a [HeaderInfo] for ranges of Comparables built using the `rangeTo` extension function. */
internal class ComparableRangeToHandler(context: CommonBackendContext) : HeaderInfoFromCallHandler<Nothing?> {
override val matcher = SimpleCalleeMatcher {
internal class ComparableRangeToHandler(context: CommonBackendContext) : HeaderInfoHandler<IrCall, Nothing?> {
private val matcher = SimpleCalleeMatcher {
fqName { it == FqName("kotlin.ranges.${OperatorNameConventions.RANGE_TO}") }
extensionReceiver { it != null && it.type.isSubtypeOfClass(context.ir.symbols.comparable) }
parameterCount { it == 1 }
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
ComparableRangeInfo(
start = expression.extensionReceiver!!,
@@ -3,8 +3,6 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:OptIn(ExperimentalUnsignedTypes::class)
package org.jetbrains.kotlin.backend.common.lower.loops
import org.jetbrains.kotlin.backend.common.CommonBackendContext
@@ -258,27 +256,11 @@ internal interface HeaderInfoHandler<E : IrExpression, D> {
}
}
internal interface ExpressionHandler : HeaderInfoHandler<IrExpression, Nothing?> {
fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo?
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol) = build(expression, scopeOwner)
}
/** Matches a call to build an iterable and builds a [HeaderInfo] from the call's context. */
internal interface HeaderInfoFromCallHandler<D> : HeaderInfoHandler<IrCall, D> {
val matcher: IrCallMatcher
override fun matchIterable(expression: IrCall) = matcher(expression)
}
internal typealias ProgressionHandler = HeaderInfoFromCallHandler<ProgressionType>
internal abstract class HeaderInfoBuilder(
context: CommonBackendContext,
private val scopeOwnerSymbol: () -> IrSymbol,
private val allowUnsignedBounds: Boolean = false
) :
IrElementVisitor<HeaderInfo?, IrCall?> {
) : IrElementVisitor<HeaderInfo?, IrCall?> {
private val symbols = context.ir.symbols
protected open val progressionHandlers = listOf(
@@ -291,8 +273,8 @@ internal abstract class HeaderInfoBuilder(
StepHandler(context, this)
)
protected abstract val callHandlers: List<HeaderInfoFromCallHandler<Nothing?>>
protected abstract val expressionHandlers: List<ExpressionHandler>
protected abstract val callHandlers: List<HeaderInfoHandler<IrCall, Nothing?>>
protected abstract val expressionHandlers: List<HeaderInfoHandler<IrExpression, Nothing?>>
override fun visitElement(element: IrElement, data: IrCall?): HeaderInfo? = null
@@ -7,8 +7,8 @@ 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.ExpressionHandler
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfo
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
import org.jetbrains.kotlin.backend.common.lower.loops.IterableHeaderInfo
import org.jetbrains.kotlin.ir.builders.createTmpVariable
import org.jetbrains.kotlin.ir.builders.irCall
@@ -19,13 +19,12 @@ import org.jetbrains.kotlin.ir.util.getSimpleFunction
import org.jetbrains.kotlin.util.OperatorNameConventions
/** Builds a [HeaderInfo] for Iterables not handled by more specialized handlers. */
internal class DefaultIterableHandler(private val context: CommonBackendContext) : ExpressionHandler {
internal class DefaultIterableHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrExpression, Nothing?> {
private val iterableClassSymbol = context.ir.symbols.iterable
override fun matchIterable(expression: IrExpression) = expression.type.isSubtypeOfClass(iterableClassSymbol)
override fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo? =
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
val iteratorFun =
iterableClassSymbol.getSimpleFunction(OperatorNameConventions.ITERATOR.asString())!!.owner
@@ -33,4 +32,4 @@ internal class DefaultIterableHandler(private val context: CommonBackendContext)
scope.createTmpVariable(irCall(iteratorFun).apply { dispatchReceiver = expression }, nameHint = "iterator")
)
}
}
}
@@ -18,9 +18,9 @@ import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.ir.util.shallowCopy
/** Builds a [HeaderInfo] for progressions not handled by more specialized handlers. */
internal class DefaultProgressionHandler(private val context: CommonBackendContext, private val allowUnsignedBounds: Boolean = false) :
ExpressionHandler {
internal class DefaultProgressionHandler(
private val context: CommonBackendContext, private val allowUnsignedBounds: Boolean = false
) : HeaderInfoHandler<IrExpression, Nothing?> {
private val symbols = context.ir.symbols
private val rangeClassesTypes = symbols.rangeClasses.map { it.defaultType }.toSet()
@@ -30,7 +30,7 @@ internal class DefaultProgressionHandler(private val context: CommonBackendConte
allowUnsignedBounds
) != null
override fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo? =
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
// Directly use the `first/last/step` properties of the progression.
val (progressionVar, progressionExpression) = createTemporaryVariableIfNecessary(expression, nameHint = "progression")
@@ -62,4 +62,4 @@ internal class DefaultProgressionHandler(private val context: CommonBackendConte
direction = direction
)
}
}
}
@@ -7,8 +7,8 @@ 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.ExpressionHandler
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfo
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
import org.jetbrains.kotlin.backend.common.lower.loops.IterableHeaderInfo
import org.jetbrains.kotlin.ir.builders.createTmpVariable
import org.jetbrains.kotlin.ir.builders.irCall
@@ -19,14 +19,13 @@ import org.jetbrains.kotlin.ir.util.getSimpleFunction
import org.jetbrains.kotlin.util.OperatorNameConventions
/** Builds a [HeaderInfo] for Sequences not handled by more specialized handlers. */
internal class DefaultSequenceHandler(private val context: CommonBackendContext) : ExpressionHandler {
internal class DefaultSequenceHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrExpression, Nothing?> {
private val sequenceClassSymbol = context.ir.symbols.sequence
override fun matchIterable(expression: IrExpression) =
sequenceClassSymbol != null && expression.type.isSubtypeOfClass(sequenceClassSymbol)
override fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo? =
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
val iteratorFun =
sequenceClassSymbol!!.getSimpleFunction(OperatorNameConventions.ITERATOR.asString())!!.owner
@@ -34,4 +33,4 @@ internal class DefaultSequenceHandler(private val context: CommonBackendContext)
scope.createTmpVariable(irCall(iteratorFun).apply { dispatchReceiver = expression }, nameHint = "iterator")
)
}
}
}
@@ -20,19 +20,19 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.name.FqName
/** Builds a [HeaderInfo] for progressions built using the `downTo` extension function. */
internal class DownToHandler(private val context: CommonBackendContext) :
ProgressionHandler {
internal class DownToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
override val matcher = SimpleCalleeMatcher {
private val matcher = SimpleCalleeMatcher {
singleArgumentExtension(FqName("kotlin.ranges.downTo"), progressionElementTypes)
parameterCount { it == 1 }
parameter(0) { it.type in progressionElementTypes }
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol) =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
val first = expression.extensionReceiver!!
@@ -108,4 +108,4 @@ internal class DownToHandler(private val context: CommonBackendContext) :
null
}
}
}
}
@@ -7,8 +7,8 @@ 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.ExpressionHandler
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfo
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
import org.jetbrains.kotlin.backend.common.lower.loops.IndexedGetHeaderInfo
import org.jetbrains.kotlin.backend.common.lower.matchers.Quantifier
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
@@ -31,8 +31,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
abstract class IndexedGetIterationHandler(
protected val context: CommonBackendContext,
private val canCacheLast: Boolean
) : ExpressionHandler {
override fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo? =
) : HeaderInfoHandler<IrExpression, Nothing?> {
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo? =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
// Consider the case like:
//
@@ -156,4 +156,4 @@ internal class StringIterationHandler(context: CommonBackendContext) : CharSeque
override val IrType.getFunction: IrSimpleFunction
get() = context.ir.symbols.string.getSimpleFunction(OperatorNameConventions.GET.asString())!!.owner
}
}
@@ -22,9 +22,7 @@ import org.jetbrains.kotlin.ir.util.isUnsignedArray
import org.jetbrains.kotlin.name.FqName
/** Builds a [HeaderInfo] for progressions built using the `indices` extension property. */
internal abstract class IndicesHandler(protected val context: CommonBackendContext) :
ProgressionHandler {
internal abstract class IndicesHandler(protected val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
@@ -64,13 +62,14 @@ internal abstract class IndicesHandler(protected val context: CommonBackendConte
}
internal class CollectionIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
override val matcher = SimpleCalleeMatcher {
private val matcher = SimpleCalleeMatcher {
extensionReceiver { it?.type?.isCollection() == true }
fqName { it == FqName("kotlin.collections.<get-indices>") }
parameterCount { it == 0 }
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override val IrType.sizePropertyGetter: IrSimpleFunction
get() = context.ir.symbols.collection.getPropertyGetter("size")!!.owner
}
@@ -78,7 +77,7 @@ internal class CollectionIndicesHandler(context: CommonBackendContext) : Indices
internal class ArrayIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
override val matcher = SimpleCalleeMatcher {
private val matcher = SimpleCalleeMatcher {
extensionReceiver {
it != null && it.type.run {
isArray() || isPrimitiveArray() || (supportsUnsignedArrays && isUnsignedArray())
@@ -88,18 +87,21 @@ internal class ArrayIndicesHandler(context: CommonBackendContext) : IndicesHandl
parameterCount { it == 0 }
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override val IrType.sizePropertyGetter: IrSimpleFunction
get() = getClass()!!.getPropertyGetter("size")!!.owner
}
internal class CharSequenceIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
override val matcher = SimpleCalleeMatcher {
private val matcher = SimpleCalleeMatcher {
extensionReceiver { it != null && it.type.run { isCharSequence() } }
fqName { it == FqName("kotlin.text.<get-indices>") }
parameterCount { it == 0 }
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override val IrType.sizePropertyGetter: IrSimpleFunction
get() = context.ir.symbols.charSequence.getPropertyGetter("length")!!.owner
}
}
@@ -17,20 +17,20 @@ import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.util.OperatorNameConventions
/** Builds a [HeaderInfo] for progressions built using the `rangeTo` function. */
internal class RangeToHandler(private val context: CommonBackendContext) :
ProgressionHandler {
internal class RangeToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
override val matcher = SimpleCalleeMatcher {
private val matcher = SimpleCalleeMatcher {
dispatchReceiver { it != null && it.type in progressionElementTypes }
fqName { it.pathSegments().last() == OperatorNameConventions.RANGE_TO }
parameterCount { it == 1 }
parameter(0) { it.type in progressionElementTypes }
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol) =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
val first = expression.dispatchReceiver!!
@@ -145,4 +145,4 @@ internal class RangeToHandler(private val context: CommonBackendContext) :
null
}
}
}
}
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.backend.common.lower.loops.handlers
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoBuilder
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoFromCallHandler
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
import org.jetbrains.kotlin.backend.common.lower.matchers.Quantifier
import org.jetbrains.kotlin.backend.common.lower.matchers.createIrCallMatcher
import org.jetbrains.kotlin.ir.expressions.IrCall
@@ -17,12 +17,11 @@ import org.jetbrains.kotlin.name.FqName
/** Builds a [HeaderInfo] for calls to reverse an iterable. */
internal class ReversedHandler(context: CommonBackendContext, private val visitor: HeaderInfoBuilder) :
HeaderInfoFromCallHandler<Nothing?> {
HeaderInfoHandler<IrCall, Nothing?> {
private val progressionClassesTypes = context.ir.symbols.progressionClasses.map { it.defaultType }.toSet()
// Use Quantifier.ANY so we can handle all reversed iterables in the same manner.
override val matcher =
private val matcher =
createIrCallMatcher(Quantifier.ANY) {
// Matcher for reversed progression.
callee {
@@ -34,7 +33,9 @@ internal class ReversedHandler(context: CommonBackendContext, private val visito
// TODO: Handle reversed String, Progression.withIndex(), etc.
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
// Reverse the HeaderInfo from the underlying progression or array (if any).
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
expression.extensionReceiver!!.accept(visitor, null)?.asReversed()
}
}
@@ -28,19 +28,19 @@ import kotlin.math.absoluteValue
/** Builds a [HeaderInfo] for progressions built using the `step` extension function. */
internal class StepHandler(
private val context: CommonBackendContext,
private val visitor: HeaderInfoBuilder
) : ProgressionHandler {
private val context: CommonBackendContext, private val visitor: HeaderInfoBuilder
) : HeaderInfoHandler<IrCall, ProgressionType> {
private val symbols = context.ir.symbols
override val matcher = SimpleCalleeMatcher {
private val matcher = SimpleCalleeMatcher {
singleArgumentExtension(
FqName("kotlin.ranges.step"),
symbols.progressionClasses.map { it.defaultType })
parameter(0) { it.type.isInt() || it.type.isLong() }
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
// Retrieve the HeaderInfo from the underlying progression (if any).
@@ -321,4 +321,4 @@ internal class StepHandler(
}
}
}
}
}
@@ -16,18 +16,18 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.name.FqName
/** Builds a [HeaderInfo] for progressions built using the `until` extension function. */
internal class UntilHandler(private val context: CommonBackendContext) :
ProgressionHandler {
internal class UntilHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
private val symbols = context.ir.symbols
private val progressionElementTypes = symbols.progressionElementTypes
override val matcher = SimpleCalleeMatcher {
private val matcher = SimpleCalleeMatcher {
singleArgumentExtension(FqName("kotlin.ranges.until"), progressionElementTypes)
parameterCount { it == 1 }
parameter(0) { it.type in progressionElementTypes }
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
ProgressionHeaderInfo(
@@ -40,4 +40,4 @@ internal class UntilHandler(private val context: CommonBackendContext) :
direction = ProgressionDirection.INCREASING
)
}
}
}
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.backend.common.lower.loops.handlers
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfo
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoFromCallHandler
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
import org.jetbrains.kotlin.backend.common.lower.loops.NestedHeaderInfoBuilderForWithIndex
import org.jetbrains.kotlin.backend.common.lower.loops.WithIndexHeaderInfo
import org.jetbrains.kotlin.backend.common.lower.matchers.Quantifier
@@ -23,13 +23,13 @@ import org.jetbrains.kotlin.ir.util.isUnsignedArray
import org.jetbrains.kotlin.name.FqName
/** Builds a [HeaderInfo] for calls to `withIndex()`. */
internal class WithIndexHandler(context: CommonBackendContext, private val visitor: NestedHeaderInfoBuilderForWithIndex) :
HeaderInfoFromCallHandler<Nothing?> {
internal class WithIndexHandler(
context: CommonBackendContext, private val visitor: NestedHeaderInfoBuilderForWithIndex
) : HeaderInfoHandler<IrCall, Nothing?> {
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
// Use Quantifier.ANY so we can handle all `withIndex()` calls in the same manner.
override val matcher =
private val matcher =
createIrCallMatcher(Quantifier.ANY) {
callee {
fqName { it == FqName("kotlin.collections.withIndex") }
@@ -53,6 +53,8 @@ internal class WithIndexHandler(context: CommonBackendContext, private val visit
}
}
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo? {
// WithIndexHeaderInfo is a composite that contains the HeaderInfo for the underlying iterable (if any).
val nestedInfo = expression.extensionReceiver!!.accept(visitor, null) ?: return null
@@ -63,4 +65,4 @@ internal class WithIndexHandler(context: CommonBackendContext, private val visit
return WithIndexHeaderInfo(nestedInfo)
}
}
}