diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt index 9d7c9e7bd1f..ccb27f92ca4 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/Utils.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.common.lower.loops import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder +import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.ir.builders.createTmpVariable import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.declarations.IrClass @@ -13,9 +14,7 @@ import org.jetbrains.kotlin.ir.declarations.IrVariable 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.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.OperatorNameConventions @@ -83,6 +82,27 @@ internal val IrExpression.canChangeValueDuringExecution: Boolean internal val IrExpression.canHaveSideEffects: Boolean get() = !isTrivial() +private fun Any?.toByte(): Byte? = + when (this) { + is Number -> toByte() + is Char -> code.toByte() + else -> null + } + +private fun Any?.toShort(): Short? = + when (this) { + is Number -> toShort() + is Char -> code.toShort() + else -> null + } + +private fun Any?.toInt(): Int? = + when (this) { + is Number -> toInt() + is Char -> code + else -> null + } + private fun Any?.toLong(): Long? = when (this) { is Number -> toLong() @@ -90,6 +110,20 @@ private fun Any?.toLong(): Long? = else -> null } +private fun Any?.toFloat(): Float? = + when (this) { + is Number -> toFloat() + is Char -> code.toFloat() + else -> null + } + +private fun Any?.toDouble(): Double? = + when (this) { + is Number -> toDouble() + is Char -> code.toDouble() + else -> null + } + internal val IrExpression.constLongValue: Long? get() = if (this is IrConst<*>) value.toLong() else null @@ -133,20 +167,33 @@ internal fun DeclarationIrBuilder.createLoopTemporaryVariableIfNecessary( } internal fun IrExpression.castIfNecessary(targetClass: IrClass) = - // This expression's type could be Nothing from an exception throw. - if (type == targetClass.defaultType || type.isNothing()) { - this - } else { - val numberCastFunctionName = Name.identifier("to${targetClass.name.asString()}") - val classifier = type.getClass() ?: error("Has to be a class ${type.render()}") - val castFun = classifier.functions.single { - it.name == numberCastFunctionName && - it.dispatchReceiverParameter != null && it.extensionReceiverParameter == null && it.valueParameters.isEmpty() + when { + // This expression's type could be Nothing from an exception throw. + type == targetClass.defaultType || type.isNothing() -> this + this is IrConst<*> && targetClass.defaultType.isPrimitiveType() -> { // TODO: convert unsigned too? + val targetType = targetClass.defaultType + when (targetType.getPrimitiveType()) { + PrimitiveType.BYTE -> IrConstImpl.byte(startOffset, endOffset, targetType, value.toByte()!!) + PrimitiveType.SHORT -> IrConstImpl.short(startOffset, endOffset, targetType, value.toShort()!!) + PrimitiveType.INT -> IrConstImpl.int(startOffset, endOffset, targetType, value.toInt()!!) + PrimitiveType.LONG -> IrConstImpl.long(startOffset, endOffset, targetType, value.toLong()!!) + PrimitiveType.FLOAT -> IrConstImpl.float(startOffset, endOffset, targetType, value.toFloat()!!) + PrimitiveType.DOUBLE -> IrConstImpl.double(startOffset, endOffset, targetType, value.toDouble()!!) + else -> error("Cannot cast expression of type ${type.render()} to ${targetType.render()}") + } + } + else -> { + val numberCastFunctionName = Name.identifier("to${targetClass.name.asString()}") + val classifier = type.getClass() ?: error("Has to be a class ${type.render()}") + val castFun = classifier.functions.single { + it.name == numberCastFunctionName && + it.dispatchReceiverParameter != null && it.extensionReceiverParameter == null && it.valueParameters.isEmpty() + } + IrCallImpl( + startOffset, endOffset, + castFun.returnType, castFun.symbol, + typeArgumentsCount = 0, + valueArgumentsCount = 0 + ).apply { dispatchReceiver = this@castIfNecessary } } - IrCallImpl( - startOffset, endOffset, - castFun.returnType, castFun.symbol, - typeArgumentsCount = 0, - valueArgumentsCount = 0 - ).apply { dispatchReceiver = this@castIfNecessary } } \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInConstBoundUnsignedRange.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInConstBoundUnsignedRange.kt index 88de4cfbc7f..f1d8de72fb8 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInConstBoundUnsignedRange.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInConstBoundUnsignedRange.kt @@ -69,8 +69,8 @@ fun testULongDownTo(a: ULong): Int { // 0 INVOKE\w+ kotlin/U(Int|Long).(un)?box-impl // JVM_IR_TEMPLATES -// 31 ILOAD -// 21 ISTORE +// 26 ILOAD +// 18 ISTORE // 6 IADD // 0 ISUB // 3 IINC diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToUIntMaxValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToUIntMaxValue.kt index 30404492b87..5ac3349f146 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToUIntMaxValue.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInRangeToUIntMaxValue.kt @@ -31,8 +31,8 @@ fun f(a: UInt): Int { // 0 INVOKE\w+ kotlin/UInt.(un)?box-impl // JVM_IR_TEMPLATES -// 7 ILOAD -// 4 ISTORE +// 5 ILOAD +// 3 ISTORE // 0 IADD // 0 ISUB // 2 IINC \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMaxValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMaxValue.kt index 2df741779db..fa11e26ac2c 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMaxValue.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMaxValue.kt @@ -39,8 +39,8 @@ fun f(a: UInt): Int { // 1 IF // JVM_IR_TEMPLATES -// 5 ILOAD -// 4 ISTORE +// 4 ILOAD +// 3 ISTORE // 0 IADD // 0 ISUB // 2 IINC \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMinValue.kt b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMinValue.kt index cf4a83ff08d..4d106fb5732 100644 --- a/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMinValue.kt +++ b/compiler/testData/codegen/bytecodeText/forLoop/unsigned/forInUntilUIntMinValue.kt @@ -38,8 +38,8 @@ fun f(a: UInt): Int { // 1 IF // JVM_IR_TEMPLATES -// 5 ILOAD -// 4 ISTORE +// 4 ILOAD +// 3 ISTORE // 0 IADD // 0 ISUB // 2 IINC