backend: Don't cast step in 'for' loop lowering
This commit is contained in:
+31
-18
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
Reference in New Issue
Block a user