ForLoopsLowering: Reduce unnecessary temporary variables.
This commit is contained in:
committed by
Alexander Udalov
parent
eaddd02e9b
commit
e1120f49d8
+32
-22
@@ -66,8 +66,13 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
override val consumesLoopVariableComponents = false
|
override val consumesLoopVariableComponents = false
|
||||||
|
|
||||||
val inductionVariable: IrVariable
|
val inductionVariable: IrVariable
|
||||||
val stepVariable: IrVariable
|
|
||||||
val stepVariableForIncrement: IrVariable?
|
protected val stepVariable: IrVariable?
|
||||||
|
protected val stepVariableForIncrement: IrVariable?
|
||||||
|
val stepExpression: IrExpression
|
||||||
|
// Always copy `stepExpression` is it may be used multiple times.
|
||||||
|
get() = field.deepCopyWithSymbols()
|
||||||
|
|
||||||
protected val lastVariableIfCanCacheLast: IrVariable?
|
protected val lastVariableIfCanCacheLast: IrVariable?
|
||||||
protected val lastExpression: IrExpression
|
protected val lastExpression: IrExpression
|
||||||
// Always copy `lastExpression` is it may be used in multiple conditions.
|
// Always copy `lastExpression` is it may be used in multiple conditions.
|
||||||
@@ -89,7 +94,7 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
//
|
//
|
||||||
// In the above example, if first() is a Long and last() is an Int, this creates a
|
// In the above example, if first() is a Long and last() is an Int, this creates a
|
||||||
// LongProgression so last() should be cast to a Long.
|
// LongProgression so last() should be cast to a Long.
|
||||||
inductionVariable = scope.createTemporaryVariable(
|
inductionVariable = scope.createTmpVariable(
|
||||||
headerInfo.progressionType.castElementIfNecessary(headerInfo.first, context),
|
headerInfo.progressionType.castElementIfNecessary(headerInfo.first, context),
|
||||||
nameHint = "inductionVariable",
|
nameHint = "inductionVariable",
|
||||||
isMutable = true
|
isMutable = true
|
||||||
@@ -102,7 +107,7 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
val last = ensureNotNullable(headerInfo.progressionType.castElementIfNecessary(headerInfo.last, context))
|
val last = ensureNotNullable(headerInfo.progressionType.castElementIfNecessary(headerInfo.last, context))
|
||||||
|
|
||||||
lastVariableIfCanCacheLast = if (headerInfo.canCacheLast) {
|
lastVariableIfCanCacheLast = if (headerInfo.canCacheLast) {
|
||||||
scope.createTemporaryVariable(
|
scope.createTmpVariable(
|
||||||
last,
|
last,
|
||||||
nameHint = "last"
|
nameHint = "last"
|
||||||
)
|
)
|
||||||
@@ -110,25 +115,28 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
|
|
||||||
lastExpression = if (headerInfo.canCacheLast) irGet(lastVariableIfCanCacheLast!!) else last
|
lastExpression = if (headerInfo.canCacheLast) irGet(lastVariableIfCanCacheLast!!) else last
|
||||||
|
|
||||||
stepVariable =
|
val stepType = headerInfo.progressionType.stepType(context.irBuiltIns)
|
||||||
scope.createTemporaryVariable(
|
val (tmpStepVar, tmpStepExpression) =
|
||||||
|
createTemporaryVariableIfNecessary(
|
||||||
ensureNotNullable(headerInfo.progressionType.castStepIfNecessary(headerInfo.step, context)),
|
ensureNotNullable(headerInfo.progressionType.castStepIfNecessary(headerInfo.step, context)),
|
||||||
nameHint = "step",
|
nameHint = "step",
|
||||||
irType = headerInfo.progressionType.stepType(context.irBuiltIns)
|
irType = stepType
|
||||||
)
|
)
|
||||||
|
stepVariable = tmpStepVar
|
||||||
|
stepExpression = tmpStepExpression
|
||||||
|
|
||||||
stepVariableForIncrement = when (headerInfo.progressionType) {
|
stepVariableForIncrement = when (headerInfo.progressionType) {
|
||||||
ProgressionType.UINT_PROGRESSION -> {
|
ProgressionType.UINT_PROGRESSION -> {
|
||||||
val castFun = context.ir.symbols.toUIntByExtensionReceiver.getValue(stepVariable.type.toKotlinType())
|
val castFun = context.ir.symbols.toUIntByExtensionReceiver.getValue(stepType.toKotlinType())
|
||||||
scope.createTemporaryVariable(
|
scope.createTmpVariable(
|
||||||
irCall(castFun).apply { extensionReceiver = irGet(stepVariable) },
|
irCall(castFun).apply { extensionReceiver = stepExpression },
|
||||||
nameHint = "stepForIncrement"
|
nameHint = "stepForIncrement"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ProgressionType.ULONG_PROGRESSION -> {
|
ProgressionType.ULONG_PROGRESSION -> {
|
||||||
val castFun = context.ir.symbols.toULongByExtensionReceiver.getValue(stepVariable.type.toKotlinType())
|
val castFun = context.ir.symbols.toULongByExtensionReceiver.getValue(stepType.toKotlinType())
|
||||||
scope.createTemporaryVariable(
|
scope.createTmpVariable(
|
||||||
irCall(castFun).apply { extensionReceiver = irGet(stepVariable) },
|
irCall(castFun).apply { extensionReceiver = stepExpression },
|
||||||
nameHint = "stepForIncrement"
|
nameHint = "stepForIncrement"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -147,17 +155,20 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
/** Statement used to increment the induction variable. */
|
/** Statement used to increment the induction variable. */
|
||||||
protected fun incrementInductionVariable(builder: DeclarationIrBuilder): IrStatement = with(builder) {
|
protected fun incrementInductionVariable(builder: DeclarationIrBuilder): IrStatement = with(builder) {
|
||||||
// inductionVariable = inductionVariable + step
|
// inductionVariable = inductionVariable + step
|
||||||
val stepVariableToUse = stepVariableForIncrement ?: stepVariable
|
val stepExpressionToUse = stepVariableForIncrement?.let { irGet(stepVariableForIncrement) } ?: stepExpression
|
||||||
|
// NOTE: We cannot use `stepExpression.type` below because it may be of type `Nothing`. This happens in the case of an illegal step
|
||||||
|
// where the "step" is actually a `throw IllegalArgumentException(...)`.
|
||||||
|
val stepType = stepVariableForIncrement?.type ?: headerInfo.progressionType.stepType(context.irBuiltIns)
|
||||||
val plusFun = elementType.getClass()!!.functions.single {
|
val plusFun = elementType.getClass()!!.functions.single {
|
||||||
it.name == OperatorNameConventions.PLUS &&
|
it.name == OperatorNameConventions.PLUS &&
|
||||||
it.valueParameters.size == 1 &&
|
it.valueParameters.size == 1 &&
|
||||||
it.valueParameters[0].type == stepVariableToUse.type
|
it.valueParameters[0].type == stepType
|
||||||
}
|
}
|
||||||
irSetVar(
|
irSetVar(
|
||||||
inductionVariable.symbol, irCallOp(
|
inductionVariable.symbol, irCallOp(
|
||||||
plusFun.symbol, plusFun.returnType,
|
plusFun.symbol, plusFun.returnType,
|
||||||
irGet(inductionVariable),
|
irGet(inductionVariable),
|
||||||
irGet(stepVariableToUse)
|
stepExpressionToUse
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -230,18 +241,17 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
// // (use `<` if last is exclusive)
|
// // (use `<` if last is exclusive)
|
||||||
// (step > 0 && inductionVar <= last) || (step < 0 || last <= inductionVar)
|
// (step > 0 && inductionVar <= last) || (step < 0 || last <= inductionVar)
|
||||||
val stepTypeClassifier = progressionType.stepClassifier(builtIns)
|
val stepTypeClassifier = progressionType.stepClassifier(builtIns)
|
||||||
val isLong = progressionType == ProgressionType.LONG_PROGRESSION
|
|
||||||
context.oror(
|
context.oror(
|
||||||
context.andand(
|
context.andand(
|
||||||
irCall(builtIns.greaterFunByOperandType.getValue(stepTypeClassifier)).apply {
|
irCall(builtIns.greaterFunByOperandType.getValue(stepTypeClassifier)).apply {
|
||||||
putValueArgument(0, irGet(stepVariable))
|
putValueArgument(0, stepExpression)
|
||||||
putValueArgument(1, if (progressionType.isLong) irLong(0) else irInt(0))
|
putValueArgument(1, if (progressionType.isLong) irLong(0) else irInt(0))
|
||||||
},
|
},
|
||||||
conditionForIncreasing()
|
conditionForIncreasing()
|
||||||
),
|
),
|
||||||
context.andand(
|
context.andand(
|
||||||
irCall(builtIns.lessFunByOperandType.getValue(stepTypeClassifier)).apply {
|
irCall(builtIns.lessFunByOperandType.getValue(stepTypeClassifier)).apply {
|
||||||
putValueArgument(0, irGet(stepVariable))
|
putValueArgument(0, stepExpression)
|
||||||
putValueArgument(1, if (progressionType.isLong) irLong(0) else irInt(0))
|
putValueArgument(1, if (progressionType.isLong) irLong(0) else irInt(0))
|
||||||
},
|
},
|
||||||
conditionForDecreasing()
|
conditionForDecreasing()
|
||||||
@@ -287,7 +297,7 @@ internal class ProgressionLoopHeader(
|
|||||||
with(builder) {
|
with(builder) {
|
||||||
// loopVariable is used in the loop condition if it can overflow. If no loopVariable was provided, create one.
|
// loopVariable is used in the loop condition if it can overflow. If no loopVariable was provided, create one.
|
||||||
this@ProgressionLoopHeader.loopVariable = if (headerInfo.canOverflow && loopVariable == null) {
|
this@ProgressionLoopHeader.loopVariable = if (headerInfo.canOverflow && loopVariable == null) {
|
||||||
scope.createTemporaryVariable(
|
scope.createTmpVariable(
|
||||||
irGet(inductionVariable),
|
irGet(inductionVariable),
|
||||||
nameHint = "loopVariable",
|
nameHint = "loopVariable",
|
||||||
isMutable = true
|
isMutable = true
|
||||||
@@ -443,13 +453,13 @@ internal class WithIndexLoopHeader(
|
|||||||
if (nestedLoopHeader is NumericForLoopHeader<*> &&
|
if (nestedLoopHeader is NumericForLoopHeader<*> &&
|
||||||
nestedLoopHeader.inductionVariable.type.isInt() &&
|
nestedLoopHeader.inductionVariable.type.isInt() &&
|
||||||
nestedLoopHeader.inductionVariable.initializer?.constLongValue == 0L &&
|
nestedLoopHeader.inductionVariable.initializer?.constLongValue == 0L &&
|
||||||
nestedLoopHeader.stepVariable.initializer?.constLongValue == 1L
|
nestedLoopHeader.stepExpression.constLongValue == 1L
|
||||||
) {
|
) {
|
||||||
indexVariable = nestedLoopHeader.inductionVariable
|
indexVariable = nestedLoopHeader.inductionVariable
|
||||||
ownsIndexVariable = false
|
ownsIndexVariable = false
|
||||||
incrementIndexStatement = null
|
incrementIndexStatement = null
|
||||||
} else {
|
} else {
|
||||||
indexVariable = scope.createTemporaryVariable(
|
indexVariable = scope.createTmpVariable(
|
||||||
irInt(0),
|
irInt(0),
|
||||||
nameHint = "index",
|
nameHint = "index",
|
||||||
isMutable = true
|
isMutable = true
|
||||||
|
|||||||
+7
-7
@@ -609,24 +609,24 @@ internal class DefaultProgressionHandler(private val context: CommonBackendConte
|
|||||||
override fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo? =
|
override fun build(expression: IrExpression, scopeOwner: IrSymbol): HeaderInfo? =
|
||||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||||
// Directly use the `first/last/step` properties of the progression.
|
// Directly use the `first/last/step` properties of the progression.
|
||||||
val progression = scope.createTmpVariable(expression, nameHint = "progression")
|
val (progressionVar, progressionExpression) = createTemporaryVariableIfNecessary(expression, nameHint = "progression")
|
||||||
val progressionClass = progression.type.getClass()!!
|
val progressionClass = progressionExpression.type.getClass()!!
|
||||||
val first = irCall(progressionClass.symbol.getPropertyGetter("first")!!).apply {
|
val first = irCall(progressionClass.symbol.getPropertyGetter("first")!!).apply {
|
||||||
dispatchReceiver = irGet(progression)
|
dispatchReceiver = progressionExpression
|
||||||
}
|
}
|
||||||
val last = irCall(progressionClass.symbol.getPropertyGetter("last")!!).apply {
|
val last = irCall(progressionClass.symbol.getPropertyGetter("last")!!).apply {
|
||||||
dispatchReceiver = irGet(progression)
|
dispatchReceiver = progressionExpression.deepCopyWithSymbols()
|
||||||
}
|
}
|
||||||
val step = irCall(progressionClass.symbol.getPropertyGetter("step")!!).apply {
|
val step = irCall(progressionClass.symbol.getPropertyGetter("step")!!).apply {
|
||||||
dispatchReceiver = irGet(progression)
|
dispatchReceiver = progressionExpression.deepCopyWithSymbols()
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressionHeaderInfo(
|
ProgressionHeaderInfo(
|
||||||
ProgressionType.fromIrType(progression.type, symbols)!!,
|
ProgressionType.fromIrType(progressionExpression.type, symbols)!!,
|
||||||
first,
|
first,
|
||||||
last,
|
last,
|
||||||
step,
|
step,
|
||||||
additionalVariables = listOf(progression),
|
additionalVariables = listOfNotNull(progressionVar),
|
||||||
direction = ProgressionDirection.UNKNOWN
|
direction = ProgressionDirection.UNKNOWN
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -8,12 +8,16 @@ package org.jetbrains.kotlin.backend.common.lower.loops
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.builders.createTmpVariable
|
import org.jetbrains.kotlin.ir.builders.createTmpVariable
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.getClass
|
import org.jetbrains.kotlin.ir.types.getClass
|
||||||
import org.jetbrains.kotlin.ir.types.isNothing
|
import org.jetbrains.kotlin.ir.types.isNothing
|
||||||
import org.jetbrains.kotlin.ir.util.functions
|
import org.jetbrains.kotlin.ir.util.functions
|
||||||
@@ -75,9 +79,12 @@ internal val IrExpression.constLongValue: Long?
|
|||||||
*
|
*
|
||||||
* This helps reduce local variable usage.
|
* This helps reduce local variable usage.
|
||||||
*/
|
*/
|
||||||
internal fun DeclarationIrBuilder.createTemporaryVariableIfNecessary(expression: IrExpression, nameHint: String? = null) =
|
internal fun DeclarationIrBuilder.createTemporaryVariableIfNecessary(
|
||||||
|
expression: IrExpression, nameHint: String? = null,
|
||||||
|
irType: IrType? = null
|
||||||
|
): Pair<IrVariable?, IrExpression> =
|
||||||
if (expression.canHaveSideEffects) {
|
if (expression.canHaveSideEffects) {
|
||||||
scope.createTmpVariable(expression, nameHint = nameHint).let { Pair(it, irGet(it)) }
|
scope.createTmpVariable(expression, nameHint = nameHint, irType = irType).let { Pair(it, irGet(it)) }
|
||||||
} else {
|
} else {
|
||||||
Pair(null, expression)
|
Pair(null, expression)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user