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
|
package org.jetbrains.kotlin.backend.common.lower.loops
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
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.createTmpVariable
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
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.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.getClass
|
|
||||||
import org.jetbrains.kotlin.ir.types.isNothing
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -83,6 +82,27 @@ internal val IrExpression.canChangeValueDuringExecution: Boolean
|
|||||||
internal val IrExpression.canHaveSideEffects: Boolean
|
internal val IrExpression.canHaveSideEffects: Boolean
|
||||||
get() = !isTrivial()
|
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? =
|
private fun Any?.toLong(): Long? =
|
||||||
when (this) {
|
when (this) {
|
||||||
is Number -> toLong()
|
is Number -> toLong()
|
||||||
@@ -90,6 +110,20 @@ private fun Any?.toLong(): Long? =
|
|||||||
else -> null
|
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?
|
internal val IrExpression.constLongValue: Long?
|
||||||
get() = if (this is IrConst<*>) value.toLong() else null
|
get() = if (this is IrConst<*>) value.toLong() else null
|
||||||
|
|
||||||
@@ -133,20 +167,33 @@ internal fun DeclarationIrBuilder.createLoopTemporaryVariableIfNecessary(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun IrExpression.castIfNecessary(targetClass: IrClass) =
|
internal fun IrExpression.castIfNecessary(targetClass: IrClass) =
|
||||||
// This expression's type could be Nothing from an exception throw.
|
when {
|
||||||
if (type == targetClass.defaultType || type.isNothing()) {
|
// This expression's type could be Nothing from an exception throw.
|
||||||
this
|
type == targetClass.defaultType || type.isNothing() -> this
|
||||||
} else {
|
this is IrConst<*> && targetClass.defaultType.isPrimitiveType() -> { // TODO: convert unsigned too?
|
||||||
val numberCastFunctionName = Name.identifier("to${targetClass.name.asString()}")
|
val targetType = targetClass.defaultType
|
||||||
val classifier = type.getClass() ?: error("Has to be a class ${type.render()}")
|
when (targetType.getPrimitiveType()) {
|
||||||
val castFun = classifier.functions.single {
|
PrimitiveType.BYTE -> IrConstImpl.byte(startOffset, endOffset, targetType, value.toByte()!!)
|
||||||
it.name == numberCastFunctionName &&
|
PrimitiveType.SHORT -> IrConstImpl.short(startOffset, endOffset, targetType, value.toShort()!!)
|
||||||
it.dispatchReceiverParameter != null && it.extensionReceiverParameter == null && it.valueParameters.isEmpty()
|
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
|
// 0 INVOKE\w+ kotlin/U(Int|Long).(un)?box-impl
|
||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 31 ILOAD
|
// 26 ILOAD
|
||||||
// 21 ISTORE
|
// 18 ISTORE
|
||||||
// 6 IADD
|
// 6 IADD
|
||||||
// 0 ISUB
|
// 0 ISUB
|
||||||
// 3 IINC
|
// 3 IINC
|
||||||
|
|||||||
+2
-2
@@ -31,8 +31,8 @@ fun f(a: UInt): Int {
|
|||||||
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 7 ILOAD
|
// 5 ILOAD
|
||||||
// 4 ISTORE
|
// 3 ISTORE
|
||||||
// 0 IADD
|
// 0 IADD
|
||||||
// 0 ISUB
|
// 0 ISUB
|
||||||
// 2 IINC
|
// 2 IINC
|
||||||
+2
-2
@@ -39,8 +39,8 @@ fun f(a: UInt): Int {
|
|||||||
// 1 IF
|
// 1 IF
|
||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 5 ILOAD
|
// 4 ILOAD
|
||||||
// 4 ISTORE
|
// 3 ISTORE
|
||||||
// 0 IADD
|
// 0 IADD
|
||||||
// 0 ISUB
|
// 0 ISUB
|
||||||
// 2 IINC
|
// 2 IINC
|
||||||
+2
-2
@@ -38,8 +38,8 @@ fun f(a: UInt): Int {
|
|||||||
// 1 IF
|
// 1 IF
|
||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
// JVM_IR_TEMPLATES
|
||||||
// 5 ILOAD
|
// 4 ILOAD
|
||||||
// 4 ISTORE
|
// 3 ISTORE
|
||||||
// 0 IADD
|
// 0 IADD
|
||||||
// 0 ISUB
|
// 0 ISUB
|
||||||
// 2 IINC
|
// 2 IINC
|
||||||
|
|||||||
Reference in New Issue
Block a user