IR KT-49372 cache progression loop parameters if their values can change
This commit is contained in:
committed by
teamcityserver
parent
7fb82232cd
commit
45a4cea655
+6
@@ -31847,6 +31847,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInDownToWithPossibleUnderflow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forInSumDownToSum.kt")
|
||||
public void testForInSumDownToSum() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInSumDownToSum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forIntInDownTo.kt")
|
||||
public void testForIntInDownTo() throws Exception {
|
||||
|
||||
+2
-2
@@ -112,7 +112,7 @@ abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
val last = headerInfo.last.asElementType()
|
||||
|
||||
if (headerInfo.canCacheLast) {
|
||||
val (variable, expression) = createTemporaryVariableIfNecessary(last, nameHint = "last")
|
||||
val (variable, expression) = createLoopTemporaryVariableIfNecessary(last, nameHint = "last")
|
||||
lastVariableIfCanCacheLast = variable
|
||||
lastExpression = expression.shallowCopy()
|
||||
} else {
|
||||
@@ -121,7 +121,7 @@ abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||
}
|
||||
|
||||
val (tmpStepVar, tmpStepExpression) =
|
||||
createTemporaryVariableIfNecessary(
|
||||
createLoopTemporaryVariableIfNecessary(
|
||||
ensureNotNullable(headerInfo.step.asStepType()),
|
||||
nameHint = "step",
|
||||
irType = stepClass.defaultType
|
||||
|
||||
+39
-10
@@ -10,19 +10,13 @@ import org.jetbrains.kotlin.ir.builders.createTmpVariable
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.isTrivial
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
@@ -74,6 +68,18 @@ internal fun IrExpression.decrement(): IrExpression {
|
||||
}
|
||||
}
|
||||
|
||||
internal val IrExpression.canChangeValueDuringExecution: Boolean
|
||||
get() = when (this) {
|
||||
is IrGetValue ->
|
||||
!this.symbol.owner.isImmutable
|
||||
is IrConst<*>,
|
||||
is IrGetObjectValue,
|
||||
is IrGetEnumValue ->
|
||||
false
|
||||
else ->
|
||||
true
|
||||
}
|
||||
|
||||
internal val IrExpression.canHaveSideEffects: Boolean
|
||||
get() = !isTrivial()
|
||||
|
||||
@@ -94,8 +100,10 @@ internal val IrExpression.constLongValue: Long?
|
||||
* This helps reduce local variable usage.
|
||||
*/
|
||||
internal fun DeclarationIrBuilder.createTemporaryVariableIfNecessary(
|
||||
expression: IrExpression, nameHint: String? = null,
|
||||
irType: IrType? = null, isMutable: Boolean = false
|
||||
expression: IrExpression,
|
||||
nameHint: String? = null,
|
||||
irType: IrType? = null,
|
||||
isMutable: Boolean = false
|
||||
): Pair<IrVariable?, IrExpression> =
|
||||
if (expression.canHaveSideEffects) {
|
||||
scope.createTmpVariable(expression, nameHint = nameHint, irType = irType, isMutable = isMutable).let { Pair(it, irGet(it)) }
|
||||
@@ -103,6 +111,27 @@ internal fun DeclarationIrBuilder.createTemporaryVariableIfNecessary(
|
||||
Pair(null, expression)
|
||||
}
|
||||
|
||||
/**
|
||||
* If [expression] can change value during execution ([IrExpression.canChangeValueDuringExecution]),
|
||||
* this function creates a temporary local variable for that expression and returns that variable and an [IrGetValue] for it.
|
||||
* Otherwise, it returns no variable and [expression].
|
||||
* Note that a variable expression doesn't have side effects per se, but can change value during execution,
|
||||
* so if it's denotes a value that would be used in a loop (say, a loop bound), it should be cached in a temporary at the loop header.
|
||||
*
|
||||
* This helps reduce local variable usage.
|
||||
*/
|
||||
internal fun DeclarationIrBuilder.createLoopTemporaryVariableIfNecessary(
|
||||
expression: IrExpression,
|
||||
nameHint: String? = null,
|
||||
irType: IrType? = null,
|
||||
isMutable: Boolean = false
|
||||
): Pair<IrVariable?, IrExpression> =
|
||||
if (expression.canChangeValueDuringExecution) {
|
||||
scope.createTmpVariable(expression, nameHint = nameHint, irType = irType, isMutable = isMutable).let { Pair(it, irGet(it)) }
|
||||
} else {
|
||||
Pair(null, expression)
|
||||
}
|
||||
|
||||
internal fun IrExpression.castIfNecessary(targetClass: IrClass) =
|
||||
// This expression's type could be Nothing from an exception throw.
|
||||
if (type == targetClass.defaultType || type.isNothing()) {
|
||||
|
||||
+4
-4
@@ -67,7 +67,7 @@ internal class StepHandler(
|
||||
|
||||
// To reduce local variable usage, we create and use temporary variables only if necessary.
|
||||
// This temporary variable for step needs to be mutable for certain cases (see below).
|
||||
val (stepArgVar, stepArgExpression) = createTemporaryVariableIfNecessary(stepArg, "stepArg", isMutable = true)
|
||||
val (stepArgVar, stepArgExpression) = createLoopTemporaryVariableIfNecessary(stepArg, "stepArg", isMutable = true)
|
||||
|
||||
// The `step` standard library function only accepts positive values, and performs the following check:
|
||||
//
|
||||
@@ -131,7 +131,7 @@ internal class StepHandler(
|
||||
// Check value of nested step and negate step arg if needed: `if (nestedStep <= 0) -step else step`
|
||||
// A temporary variable is created only if necessary, so we can preserve the evaluation order.
|
||||
val nestedStep = nestedInfo.step
|
||||
val (tmpNestedStepVar, nestedStepExpression) = createTemporaryVariableIfNecessary(nestedStep, "nestedStep")
|
||||
val (tmpNestedStepVar, nestedStepExpression) = createLoopTemporaryVariableIfNecessary(nestedStep, "nestedStep")
|
||||
nestedStepVar = tmpNestedStepVar
|
||||
val nestedStepNonPositiveCheck = irCall(stepCompFun).apply {
|
||||
putValueArgument(0, nestedStepExpression.shallowCopy())
|
||||
@@ -163,8 +163,8 @@ internal class StepHandler(
|
||||
|
||||
// Store the nested "first" and "last" and final "step" in temporary variables only if necessary, so we can preserve the
|
||||
// evaluation order.
|
||||
val (nestedFirstVar, nestedFirstExpression) = createTemporaryVariableIfNecessary(nestedInfo.first, "nestedFirst")
|
||||
val (nestedLastVar, nestedLastExpression) = createTemporaryVariableIfNecessary(nestedInfo.last, "nestedLast")
|
||||
val (nestedFirstVar, nestedFirstExpression) = createLoopTemporaryVariableIfNecessary(nestedInfo.first, "nestedFirst")
|
||||
val (nestedLastVar, nestedLastExpression) = createLoopTemporaryVariableIfNecessary(nestedInfo.last, "nestedLast")
|
||||
|
||||
// Creating a progression with a step value != 1 may result in a "last" value that is smaller than the given "last". The new
|
||||
// "last" value is such that iterating over the progression (by incrementing by "step") does not go over the "last" value.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun test(): Int {
|
||||
var sum = 0
|
||||
for (i in sum downTo sum) {
|
||||
sum += 1 + i
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val t1 = test()
|
||||
if (t1 != 1) return "Failed: t1=$t1"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -35,8 +35,8 @@ fun box(): String {
|
||||
// 1 IF_ICMPEQ
|
||||
// 1 IFGT
|
||||
// 3 IF
|
||||
// 9 ILOAD
|
||||
// 4 ISTORE
|
||||
// 10 ILOAD
|
||||
// 5 ISTORE
|
||||
// 1 IADD
|
||||
// 0 ISUB
|
||||
// 0 IINC
|
||||
Vendored
+2
-2
@@ -42,8 +42,8 @@ fun box(): String {
|
||||
// 1 IFGE
|
||||
// 7 IF
|
||||
// 1 INEG
|
||||
// 18 ILOAD
|
||||
// 8 ISTORE
|
||||
// 19 ILOAD
|
||||
// 9 ISTORE
|
||||
// 1 IADD
|
||||
// 0 ISUB
|
||||
// 0 IINC
|
||||
+2
-2
@@ -35,8 +35,8 @@ fun box(): String {
|
||||
// 1 IF_ICMPEQ
|
||||
// 2 IFGT
|
||||
// 4 IF
|
||||
// 13 ILOAD
|
||||
// 6 ISTORE
|
||||
// 14 ILOAD
|
||||
// 7 ISTORE
|
||||
// 1 IADD
|
||||
// 0 ISUB
|
||||
// 0 IINC
|
||||
|
||||
Vendored
+2
-2
@@ -42,8 +42,8 @@ fun box(): String {
|
||||
// 1 INEG
|
||||
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||
// 19 ILOAD
|
||||
// 9 ISTORE
|
||||
// 20 ILOAD
|
||||
// 10 ISTORE
|
||||
// 1 IADD
|
||||
// 0 ISUB
|
||||
// 0 IINC
|
||||
+6
@@ -31709,6 +31709,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInDownToWithPossibleUnderflow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forInSumDownToSum.kt")
|
||||
public void testForInSumDownToSum() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInSumDownToSum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forIntInDownTo.kt")
|
||||
public void testForIntInDownTo() throws Exception {
|
||||
|
||||
+6
@@ -31847,6 +31847,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInDownToWithPossibleUnderflow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forInSumDownToSum.kt")
|
||||
public void testForInSumDownToSum() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInSumDownToSum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forIntInDownTo.kt")
|
||||
public void testForIntInDownTo() throws Exception {
|
||||
|
||||
+5
@@ -27001,6 +27001,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInDownToWithPossibleUnderflow.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forInSumDownToSum.kt")
|
||||
public void testForInSumDownToSum() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInSumDownToSum.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forIntInDownTo.kt")
|
||||
public void testForIntInDownTo() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forIntInDownTo.kt");
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+5
@@ -21405,6 +21405,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInDownToWithPossibleUnderflow.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forInSumDownToSum.kt")
|
||||
public void testForInSumDownToSum() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInSumDownToSum.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forIntInDownTo.kt")
|
||||
public void testForIntInDownTo() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forIntInDownTo.kt");
|
||||
|
||||
Generated
+5
@@ -20811,6 +20811,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInDownToWithPossibleUnderflow.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forInSumDownToSum.kt")
|
||||
public void testForInSumDownToSum() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInSumDownToSum.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forIntInDownTo.kt")
|
||||
public void testForIntInDownTo() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forIntInDownTo.kt");
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+5
@@ -19951,6 +19951,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInDownToWithPossibleUnderflow.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forInSumDownToSum.kt")
|
||||
public void testForInSumDownToSum() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInSumDownToSum.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("forIntInDownTo.kt")
|
||||
public void testForIntInDownTo() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forIntInDownTo.kt");
|
||||
|
||||
+6
@@ -23311,6 +23311,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInDownToWithPossibleUnderflow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forInSumDownToSum.kt")
|
||||
public void testForInSumDownToSum() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/ranges/forInDownTo/forInSumDownToSum.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forIntInDownTo.kt")
|
||||
public void testForIntInDownTo() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user