backend: Don't calculate last element in 'for' loop if the step is 1

This commit is contained in:
Ilya Matveev
2017-07-13 15:28:02 +07:00
committed by ilmat192
parent a97a310987
commit 3184ae57c6
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.KonanIr
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.typeUtil.isBoolean import org.jetbrains.kotlin.types.typeUtil.isBoolean
@@ -87,18 +88,17 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
progressionElementClasses.mapTo(this) { it.descriptor.defaultType } progressionElementClasses.mapTo(this) { it.descriptor.defaultType }
} }
// Symbols for progression building functions ====================================================================== //region Symbols for progression building functions ================================================================
private fun getProgressionBuildingMethods(name: String): Set<IrFunctionSymbol> = private fun getProgressionBuildingMethods(name: String): Set<IrFunctionSymbol> =
getMethodsForProgressionElements(name) { getMethodsForProgressionElements(name) {
it.valueParameters.size == 1 && it.valueParameters.size == 1 && it.valueParameters[0].type in progressionElementClassesTypes
it.valueParameters[0].type in progressionElementClassesTypes
} }
private fun getProgressionBuildingExtensions(name: String, pkg: FqName): Set<IrFunctionSymbol> = private fun getProgressionBuildingExtensions(name: String, pkg: FqName): Set<IrFunctionSymbol> =
getExtensionsForProgressionElements(name, pkg) { getExtensionsForProgressionElements(name, pkg) {
it.extensionReceiverParameter?.type in progressionElementClassesTypes && it.extensionReceiverParameter?.type in progressionElementClassesTypes &&
it.valueParameters.size == 1 && it.valueParameters.size == 1 &&
it.valueParameters[0].type in progressionElementClassesTypes it.valueParameters[0].type in progressionElementClassesTypes
} }
private fun getMethodsForProgressionElements(name: String, private fun getMethodsForProgressionElements(name: String,
@@ -132,6 +132,7 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
(KotlinBuiltIns.isLong(it.valueParameters[0].type) || KotlinBuiltIns.isInt(it.valueParameters[0].type)) (KotlinBuiltIns.isLong(it.valueParameters[0].type) || KotlinBuiltIns.isInt(it.valueParameters[0].type))
} }
} }
//endregion
//region Util methods ============================================================================================== //region Util methods ==============================================================================================
private fun IrExpression.castIfNecessary(progressionType: ProgressionType, castToChar: Boolean = true): IrExpression { private fun IrExpression.castIfNecessary(progressionType: ProgressionType, castToChar: Boolean = true): IrExpression {
@@ -148,19 +149,26 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
dispatchReceiver = this@unaryMinus dispatchReceiver = this@unaryMinus
} }
private fun IrConst<*>.isOne() =
when (kind) {
IrConstKind.Long -> value as Long == 1L
IrConstKind.Int -> value as Int == 1
else -> false
}
private fun irCheckProgressionStep(progressionType: ProgressionType, private fun irCheckProgressionStep(progressionType: ProgressionType,
step: IrExpression): IrExpression { step: IrExpression): Pair<IrExpression, Boolean> {
if (step is IrConst<*> && if (step is IrConst<*> &&
((step.kind == IrConstKind.Long && step.value as Long > 0) || ((step.kind == IrConstKind.Long && step.value as Long > 0) ||
(step.kind == IrConstKind.Int && step.value as Int > 0))) { (step.kind == IrConstKind.Int && step.value as Int > 0))) {
return step return step to !step.isOne()
} }
val castedStep = step.castIfNecessary(progressionType, false) val castedStep = step.castIfNecessary(progressionType, false)
val symbol = symbols.checkProgressionStep[castedStep.type] val symbol = symbols.checkProgressionStep[castedStep.type]
?: throw IllegalArgumentException("Unknown progression element type: ${step.type}") ?: throw IllegalArgumentException("Unknown progression element type: ${step.type}")
return IrCallImpl(step.startOffset, step.endOffset, symbol).apply { return IrCallImpl(step.startOffset, step.endOffset, symbol).apply {
putValueArgument(0, castedStep) putValueArgument(0, castedStep)
} } to true
} }
private fun irGetProgressionBound(progressionType: ProgressionType, private fun irGetProgressionBound(progressionType: ProgressionType,
@@ -179,7 +187,7 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
} }
//endregion //endregion
//region Util classes ==================================================================================================== //region Util classes ==============================================================================================
// TODO: Replace with a cast when such support is added in the boxing lowering. // TODO: Replace with a cast when such support is added in the boxing lowering.
private data class ProgressionType(val elementType: KotlinType, private data class ProgressionType(val elementType: KotlinType,
val numberCastFunctionName: Name) val numberCastFunctionName: Name)
@@ -189,7 +197,8 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
val first: IrExpression, val first: IrExpression,
val last: IrExpression, val last: IrExpression,
val step: IrExpression? = null, val step: IrExpression? = null,
val increasing: Boolean = true) val increasing: Boolean = true,
var needBoundCalculation: Boolean = false)
/** Contains information about variables used in the loop. */ /** Contains information about variables used in the loop. */
private data class ForLoopInfo( private data class ForLoopInfo(
@@ -224,18 +233,20 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
private fun buildStep(expression: IrCall, progressionType: ProgressionType) = private fun buildStep(expression: IrCall, progressionType: ProgressionType) =
expression.extensionReceiver!!.accept(this, null)?.let { expression.extensionReceiver!!.accept(this, null)?.let {
val newStep = expression.getValueArgument(0)!! val newStep = expression.getValueArgument(0)!!
val (newStepCheck, needBoundCalculation) = irCheckProgressionStep(progressionType, newStep)
val step = when { val step = when {
it.step == null -> irCheckProgressionStep(progressionType, newStep) it.step == null -> newStepCheck
// There were step calls before. Just add our check in the container or create a new one. // There were step calls before. Just add our check in the container or create a new one.
it.step is IrStatementContainer -> { it.step is IrStatementContainer -> {
it.step.statements.add(irCheckProgressionStep(progressionType, newStep)); it.step it.step.statements.add(newStepCheck)
it.step
} }
else -> IrCompositeImpl(expression.startOffset, expression.endOffset, newStep.type).apply { else -> IrCompositeImpl(expression.startOffset, expression.endOffset, newStep.type).apply {
statements.add(it.step) statements.add(it.step)
statements.add(irCheckProgressionStep(progressionType, newStep)) statements.add(newStepCheck)
} }
} }
ProgressionInfo(progressionType, it.first, it.last, step, it.increasing) ProgressionInfo(progressionType, it.first, it.last, step, it.increasing, needBoundCalculation)
} }
override fun visitElement(element: IrElement, data: Nothing?): ProgressionInfo? = null override fun visitElement(element: IrElement, data: Nothing?): ProgressionInfo? = null
@@ -261,7 +272,7 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
} }
//endregion //endregion
// Lowering ======================================================================================================== //region Lowering ==================================================================================================
// Lower a loop header. // Lower a loop header.
private fun processHeader(variable: IrVariable, initializer: IrCall): IrStatement? { private fun processHeader(variable: IrVariable, initializer: IrCall): IrStatement? {
val symbol = variable.symbol val symbol = variable.symbol
@@ -282,8 +293,12 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
step?.unaryMinus() ?: irConstMinusOne(startOffset, endOffset).castIfNecessary(progressionType, false) step?.unaryMinus() ?: irConstMinusOne(startOffset, endOffset).castIfNecessary(progressionType, false)
} }
val stepValue = irTemporary(stepExpression, "step") val stepValue = irTemporary(stepExpression, "step")
// TODO: Don't call the check it step is 1 or -1 // Don't call progression bound calculation if the step is 1.
val boundExpression = irGetProgressionBound(progressionType, inductionVariable.symbol, last, stepValue.symbol) val boundExpression = if (needBoundCalculation) {
irGetProgressionBound(progressionType, inductionVariable.symbol, last, stepValue.symbol)
} else {
last.castIfNecessary(progressionType)
}
val boundValue = irTemporary(boundExpression, "bound") val boundValue = irTemporary(boundExpression, "bound")
iteratorToLoopInfo[symbol] = ForLoopInfo(progressionInfo, iteratorToLoopInfo[symbol] = ForLoopInfo(progressionInfo,
inductionVariable.symbol, inductionVariable.symbol,
@@ -410,5 +425,6 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
} }
return result ?: super.visitVariable(declaration) return result ?: super.visitVariable(declaration)
} }
//endregion
} }