backend: Don't cast step in 'for' loop lowering

This commit is contained in:
Ilya Matveev
2017-07-13 15:51:41 +07:00
committed by ilmat192
parent 3184ae57c6
commit 01f0540fac
3 changed files with 85 additions and 20 deletions
@@ -74,12 +74,6 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
private val scopeOwnerSymbol
get() = currentScope!!.scope.scopeOwnerSymbol
private fun irConstOne(startOffset: Int, endOffset: Int) =
IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, 1)
private fun irConstMinusOne(startOffset: Int, endOffset: Int) =
IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, -1)
private val progressionElementClasses: Set<IrClassSymbol> = mutableSetOf(symbols.char).apply {
addAll(symbols.integerClasses)
}
@@ -149,6 +143,18 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
dispatchReceiver = this@unaryMinus
}
private fun ProgressionInfo.defaultStep(startOffset: Int, endOffset: Int): IrExpression =
progressionType.elementType.let { type ->
val step = if (increasing) 1 else -1
when {
KotlinBuiltIns.isInt(type) || KotlinBuiltIns.isChar(type) ->
IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, step)
KotlinBuiltIns.isLong(type) ->
IrConstImpl.long(startOffset, endOffset, context.builtIns.longType, step.toLong())
else -> throw IllegalArgumentException()
}
}
private fun IrConst<*>.isOne() =
when (kind) {
IrConstKind.Long -> value as Long == 1L
@@ -156,6 +162,11 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
else -> false
}
// Used only by the assert.
private fun stepHasRightType(step: IrExpression, progressionType: ProgressionType) =
((progressionType.isCharProgression() || progressionType.isIntProgression()) && KotlinBuiltIns.isInt(step.type)) ||
(progressionType.isLongProgression() && KotlinBuiltIns.isLong(step.type))
private fun irCheckProgressionStep(progressionType: ProgressionType,
step: IrExpression): Pair<IrExpression, Boolean> {
if (step is IrConst<*> &&
@@ -163,11 +174,14 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
(step.kind == IrConstKind.Int && step.value as Int > 0))) {
return step to !step.isOne()
}
val castedStep = step.castIfNecessary(progressionType, false)
val symbol = symbols.checkProgressionStep[castedStep.type]
// The frontend checks if the step has a right type (Long for LongProgression and Int for {Int/Char}Progression)
// so there is no need to cast it.
assert(stepHasRightType(step, progressionType))
val symbol = symbols.checkProgressionStep[step.type]
?: throw IllegalArgumentException("Unknown progression element type: ${step.type}")
return IrCallImpl(step.startOffset, step.endOffset, symbol).apply {
putValueArgument(0, castedStep)
putValueArgument(0, step)
} to true
}
@@ -190,7 +204,11 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
//region Util classes ==============================================================================================
// TODO: Replace with a cast when such support is added in the boxing lowering.
private data class ProgressionType(val elementType: KotlinType,
val numberCastFunctionName: Name)
val numberCastFunctionName: Name) {
fun isIntProgression() = KotlinBuiltIns.isInt(elementType)
fun isLongProgression() = KotlinBuiltIns.isLong(elementType)
fun isCharProgression() = KotlinBuiltIns.isChar(elementType)
}
private data class ProgressionInfo(
val progressionType: ProgressionType,
@@ -287,11 +305,7 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
return builder.irBlock {
with(progressionInfo) {
val inductionVariable = irTemporaryVar(first.castIfNecessary(progressionType), "inductionVariable")
val stepExpression = if (increasing) { // TODO: Remove the casts.
step ?: irConstOne(startOffset, endOffset).castIfNecessary(progressionType, false)
} else {
step?.unaryMinus() ?: irConstMinusOne(startOffset, endOffset).castIfNecessary(progressionType, false)
}
val stepExpression = (if (increasing) step else step?.unaryMinus()) ?: defaultStep(startOffset, endOffset)
val stepValue = irTemporary(stepExpression, "step")
// Don't call progression bound calculation if the step is 1.
val boundExpression = if (needBoundCalculation) {
@@ -357,11 +371,11 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
val irIteratorAccess = oldCondition.dispatchReceiver as? IrGetValue ?: throw AssertionError()
// Return null if we didn't lower a corresponding header.
val forLoopInfo = iteratorToLoopInfo[irIteratorAccess.symbol] ?: return null
val loopVariable = forLoopInfo.loopVariable!! // TODO: Check!
assert(forLoopInfo.loopVariable != null)
return irCall(context.irBuiltIns.booleanNotSymbol).apply {
val eqeqCall = irCall(context.irBuiltIns.eqeqSymbol).apply {
putValueArgument(0, irGet(loopVariable))
putValueArgument(0, irGet(forLoopInfo.loopVariable!!))
putValueArgument(1, irGet(forLoopInfo.bound))
}
putValueArgument(0, eqeqCall)
@@ -400,7 +414,6 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
// Transform accesses to the old iterator (see visitVariable method). Store loopVariable in loopInfo.
val newBody = loop.body?.transform(this@ForLoopsTransformer, null)
val (newCondition, forLoopInfo) = buildNewCondition(loop.condition) ?: return super.visitWhileLoop(loop)
assert(forLoopInfo.loopVariable != null)
val newLoop = IrDoWhileLoopImpl(loop.startOffset, loop.endOffset, loop.type, loop.origin).apply {
label = loop.label
+3 -1
View File
@@ -317,7 +317,9 @@ task codegen_basics_for_loops_types(type: RunKonanTest) {
goldValue = "01234\n01234\n01234\n01234\n01234\n01234\n01234\n01234\n01234\n01234\n01234\n01234\n01234\n01234\n" +
"01234\n01234\n0123\n0123\n0123\n0123\n0123\n0123\n0123\n0123\n0123\n0123\n0123\n0123\n0123\n0123\n0123\n" +
"0123\n43210\n43210\n43210\n43210\n43210\n43210\n43210\n43210\n43210\n43210\n43210\n43210\n43210\n43210\n" +
"43210\n43210\nabcd\nabc\ndcba\n"
"43210\n43210\nabcd\nabc\ndcba\n024\n024\n024\n024\n024\n024\n024\n024\n024\n024\n024\n024\n024\n024\n" +
"024\n024\n02\n02\n02\n02\n02\n02\n02\n02\n02\n02\n02\n02\n02\n02\n02\n02\n420\n420\n420\n420\n420\n420\n" +
"420\n420\n420\n420\n420\n420\n420\n420\n420\n420\nac\nac\ndb\n"
}
task codegen_basics_for_loops_overflow(type: RunKonanTest) {
@@ -51,5 +51,55 @@ fun main(args: Array<String>) {
for (i in 'a' until 'd') print(i); println()
for (i in 'd' downTo 'a') print(i); println()
// TODO: Add step tests.
for (i in 0.toByte() .. 4.toByte() step 2) print(i); println()
for (i in 0.toByte() .. 4.toShort() step 2) print(i); println()
for (i in 0.toByte() .. 4.toInt() step 2) print(i); println()
for (i in 0.toByte() .. 4.toLong() step 2L) print(i); println()
for (i in 0.toShort() .. 4.toByte() step 2) print(i); println()
for (i in 0.toShort() .. 4.toShort() step 2) print(i); println()
for (i in 0.toShort() .. 4.toInt() step 2) print(i); println()
for (i in 0.toShort() .. 4.toLong() step 2L) print(i); println()
for (i in 0.toInt() .. 4.toByte() step 2) print(i); println()
for (i in 0.toInt() .. 4.toShort() step 2) print(i); println()
for (i in 0.toInt() .. 4.toInt() step 2) print(i); println()
for (i in 0.toInt() .. 4.toLong() step 2L) print(i); println()
for (i in 0.toLong() .. 4.toByte() step 2L) print(i); println()
for (i in 0.toLong() .. 4.toShort() step 2L) print(i); println()
for (i in 0.toLong() .. 4.toInt() step 2L) print(i); println()
for (i in 0.toLong() .. 4.toLong() step 2L) print(i); println()
for (i in 0.toByte() until 4.toByte() step 2) print(i); println()
for (i in 0.toByte() until 4.toShort() step 2) print(i); println()
for (i in 0.toByte() until 4.toInt() step 2) print(i); println()
for (i in 0.toByte() until 4.toLong() step 2L) print(i); println()
for (i in 0.toShort() until 4.toByte() step 2) print(i); println()
for (i in 0.toShort() until 4.toShort() step 2) print(i); println()
for (i in 0.toShort() until 4.toInt() step 2) print(i); println()
for (i in 0.toShort() until 4.toLong() step 2L) print(i); println()
for (i in 0.toInt() until 4.toByte() step 2) print(i); println()
for (i in 0.toInt() until 4.toShort() step 2) print(i); println()
for (i in 0.toInt() until 4.toInt() step 2) print(i); println()
for (i in 0.toInt() until 4.toLong() step 2L) print(i); println()
for (i in 0.toLong() until 4.toByte() step 2L) print(i); println()
for (i in 0.toLong() until 4.toShort() step 2L) print(i); println()
for (i in 0.toLong() until 4.toInt() step 2L) print(i); println()
for (i in 0.toLong() until 4.toLong() step 2L) print(i); println()
for (i in 4.toByte() downTo 0.toByte() step 2) print(i); println()
for (i in 4.toByte() downTo 0.toShort() step 2) print(i); println()
for (i in 4.toByte() downTo 0.toInt() step 2) print(i); println()
for (i in 4.toByte() downTo 0.toLong() step 2L) print(i); println()
for (i in 4.toShort() downTo 0.toByte() step 2) print(i); println()
for (i in 4.toShort() downTo 0.toShort() step 2) print(i); println()
for (i in 4.toShort() downTo 0.toInt() step 2) print(i); println()
for (i in 4.toShort() downTo 0.toLong() step 2L) print(i); println()
for (i in 4.toInt() downTo 0.toByte() step 2) print(i); println()
for (i in 4.toInt() downTo 0.toShort() step 2) print(i); println()
for (i in 4.toInt() downTo 0.toInt() step 2) print(i); println()
for (i in 4.toInt() downTo 0.toLong() step 2L) print(i); println()
for (i in 4.toLong() downTo 0.toByte() step 2L) print(i); println()
for (i in 4.toLong() downTo 0.toShort() step 2L) print(i); println()
for (i in 4.toLong() downTo 0.toInt() step 2L) print(i); println()
for (i in 4.toLong() downTo 0.toLong() step 2L) print(i); println()
for (i in 'a' .. 'd' step 2) print(i); println()
for (i in 'a' until 'd' step 2) print(i); println()
for (i in 'd' downTo 'a' step 2) print(i); println()
}