From ea9572ad285ba9c5931808f8cde9d8fc9a4ada0a Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Wed, 20 Mar 2019 00:01:32 -0700 Subject: [PATCH] Add DefaultProgressionHandler that handles for-loops over non-specialized progressions, including "step" progressions. DefaultProgressionHandler uses the "first/last/step" properties of the progression when building the loop header. --- .../backend/common/lower/loops/HeaderInfo.kt | 14 +++++-- .../common/lower/loops/ProgressionHandlers.kt | 38 +++++++++++++++++++ .../forInIndices/forInNonOptimizedIndices.kt | 1 - .../forLoop/forInRangeWithImplicitReceiver.kt | 1 + .../forLoop/primitiveLiteralRange1.kt | 3 +- .../forLoop/primitiveLiteralRange2.kt | 3 +- .../forLoop/primitiveProgression.kt | 1 - .../bytecodeText/forLoop/primitiveRange.kt | 4 +- .../codegen/bytecodeText/intRangeNoBoxing.kt | 1 - 9 files changed, 56 insertions(+), 10 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt index e314a4994ae..c2dcd6199e4 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt @@ -134,12 +134,20 @@ private class ProgressionHeaderInfoBuilder(val context: CommonBackendContext) : } internal class HeaderInfoBuilder(context: CommonBackendContext) { - private val progressionInfoBuilder = ProgressionHeaderInfoBuilder(context) + private val progressionHeaderInfoBuilder = ProgressionHeaderInfoBuilder(context) private val arrayIterationHandler = ArrayIterationHandler(context) + private val defaultProgressionHandler = DefaultProgressionHandler(context) fun build(variable: IrVariable): HeaderInfo? { - val initializer = variable.initializer!! as IrCall + // TODO: Merge DefaultProgressionHandler into ProgressionHeaderInfoBuilder. Not + // straightforward because ProgressionHeaderInfoBuilder works only on calls and not just + // any progression expression (i.e., progression may not be a call result). + + // DefaultProgressionHandler must come AFTER ProgressionHeaderInfoBuilder, which handles + // more specialized forms of progressions. + val initializer = variable.initializer as IrCall return arrayIterationHandler.handle(initializer, null) - ?: initializer.dispatchReceiver?.accept(progressionInfoBuilder, null) + ?: initializer.dispatchReceiver?.accept(progressionHeaderInfoBuilder, null) + ?: defaultProgressionHandler.handle(initializer, null) } } \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt index 6d3c7823e16..5cd1b1c6b26 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt @@ -161,6 +161,44 @@ internal class IndicesHandler(val context: CommonBackendContext) : ProgressionHa } } +/** Builds a [HeaderInfo] for progressions not handled by more specialized handlers. */ +internal class DefaultProgressionHandler(private val context: CommonBackendContext) : HeaderInfoHandler { + + private val symbols = context.ir.symbols + + override val matcher = createIrCallMatcher { + origin { it == IrStatementOrigin.FOR_LOOP_ITERATOR } + dispatchReceiver { it != null && ProgressionType.fromIrType(it.type, symbols) != null } + } + + override fun build(call: IrCall, progressionType: Nothing?): HeaderInfo? = + with(context.createIrBuilder(call.symbol, call.startOffset, call.endOffset)) { + // Directly use the `first/last/step` properties of the progression. + val progression = scope.createTemporaryVariable(call.dispatchReceiver!!) + val progressionClass = progression.type.getClass()!! + val firstProperty = progressionClass.properties.first { it.name.asString() == "first" } + val first = irCall(firstProperty.getter!!).apply { + dispatchReceiver = irGet(progression) + } + val lastProperty = progressionClass.properties.first { it.name.asString() == "last" } + val last = irCall(lastProperty.getter!!).apply { + dispatchReceiver = irGet(progression) + } + val stepProperty = progressionClass.properties.first { it.name.asString() == "step" } + val step = irCall(stepProperty.getter!!).apply { + dispatchReceiver = irGet(progression) + } + + ProgressionHeaderInfo( + ProgressionType.fromIrType(progression.type, symbols)!!, + first, + last, + step, + additionalVariables = listOf(progression) + ) + } +} + internal class ArrayIterationHandler(private val context: CommonBackendContext) : HeaderInfoHandler { private val intDecFun = ProgressionType.INT_PROGRESSION.decFun(context.irBuiltIns) diff --git a/compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInNonOptimizedIndices.kt b/compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInNonOptimizedIndices.kt index 3afb1efa800..94b39a240c4 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInNonOptimizedIndices.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInNonOptimizedIndices.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR import kotlin.test.assertEquals fun test(coll: Collection<*>?): Int { diff --git a/compiler/testData/codegen/bytecodeText/forLoop/forInRangeWithImplicitReceiver.kt b/compiler/testData/codegen/bytecodeText/forLoop/forInRangeWithImplicitReceiver.kt index 178849e1b5b..01c8280c6c2 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/forInRangeWithImplicitReceiver.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/forInRangeWithImplicitReceiver.kt @@ -11,3 +11,4 @@ fun Int.digitsUpto(end: Int): Int { // 0 getEnd // 0 getFirst // 0 getLast +// 0 getStep \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/primitiveLiteralRange1.kt b/compiler/testData/codegen/bytecodeText/forLoop/primitiveLiteralRange1.kt index aad6cac37d4..fc049d3ecd7 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/primitiveLiteralRange1.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/primitiveLiteralRange1.kt @@ -7,4 +7,5 @@ fun f() { // 0 getStart // 0 getEnd // 0 getFirst -// 0 getLast \ No newline at end of file +// 0 getLast +// 0 getStep \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/primitiveLiteralRange2.kt b/compiler/testData/codegen/bytecodeText/forLoop/primitiveLiteralRange2.kt index 112e70eb779..00580934a1b 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/primitiveLiteralRange2.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/primitiveLiteralRange2.kt @@ -7,4 +7,5 @@ fun f(a: Int, b: Int) { // 0 getStart // 0 getEnd // 0 getFirst -// 0 getLast \ No newline at end of file +// 0 getLast +// 0 getStep \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/primitiveProgression.kt b/compiler/testData/codegen/bytecodeText/forLoop/primitiveProgression.kt index b0cce240467..ec759232526 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/primitiveProgression.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/primitiveProgression.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR fun f() { for (i in 0..5 step 2) { } diff --git a/compiler/testData/codegen/bytecodeText/forLoop/primitiveRange.kt b/compiler/testData/codegen/bytecodeText/forLoop/primitiveRange.kt index 00da0c6e9f3..e9afbe9ec09 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/primitiveRange.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/primitiveRange.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR fun f(r: IntRange) { for (i in r) { } @@ -8,4 +7,5 @@ fun f(r: IntRange) { // 0 getStart // 0 getEnd // 1 getFirst -// 1 getLast \ No newline at end of file +// 1 getLast +// 1 getStep \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/intRangeNoBoxing.kt b/compiler/testData/codegen/bytecodeText/intRangeNoBoxing.kt index cb8e20085f9..766ede8b317 100644 --- a/compiler/testData/codegen/bytecodeText/intRangeNoBoxing.kt +++ b/compiler/testData/codegen/bytecodeText/intRangeNoBoxing.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR fun Int.until(other: Int) = this..other - 1 fun foo() { val range = 1 until 2