Convert const values in ranges without explicit cast

This commit is contained in:
Ivan Kylchik
2021-12-14 14:41:23 +03:00
parent 0b22cf6cb9
commit 44cf64a00c
5 changed files with 73 additions and 26 deletions
@@ -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 }
}
@@ -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
@@ -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
@@ -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
@@ -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