Convert const values in ranges without explicit cast
This commit is contained in:
+65
-18
@@ -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 }
|
||||
}
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
+2
-2
@@ -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
|
||||
+2
-2
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user