Skip to content

Commit

Permalink
[IR] Make casting inside for loop optimizations aware of an initial t…
Browse files Browse the repository at this point in the history
…ype of expressions

It can be different from the value type for unsigned types

#KT-67383


Merge-request: KT-MR-16926
Merged-by: Evgeniy Zhelenskiy <[email protected]>
  • Loading branch information
zhelenskiy authored and qodana-bot committed Sep 3, 2024
1 parent 63f7588 commit 3f0fc86
Show file tree
Hide file tree
Showing 22 changed files with 361 additions and 50 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -85,50 +85,15 @@ 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()
is Char -> code.toLong()
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
get() = when {
this !is IrConst -> null
type.isUByte() -> (value as? Number)?.toLong()?.toUByte()?.toLong()
type.isUShort() -> (value as? Number)?.toLong()?.toUShort()?.toLong()
type.isUInt() -> (value as? Number)?.toLong()?.toUInt()?.toLong()
type.isChar() -> (value as? Char)?.code?.toLong()
else -> (value as? Number)?.toLong()
}

/**
* If [expression] can have side effects ([IrExpression.canHaveSideEffects]), this function creates a temporary local variable for that
Expand Down Expand Up @@ -174,15 +139,31 @@ internal fun IrExpression.castIfNecessary(targetClass: IrClass) =
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?
this is IrConst && targetClass.defaultType.isPrimitiveType() -> {
val targetType = targetClass.defaultType
val longOrSmallerValue = constLongValue
val uLongValue = if (targetType.isULong()) longOrSmallerValue!!.toULong() else null
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()!!)
PrimitiveType.BYTE -> IrConstImpl.byte(startOffset, endOffset, targetType, longOrSmallerValue!!.toByte())
PrimitiveType.SHORT -> IrConstImpl.short(startOffset, endOffset, targetType, longOrSmallerValue!!.toShort())
PrimitiveType.INT -> IrConstImpl.int(startOffset, endOffset, targetType, longOrSmallerValue!!.toInt())
PrimitiveType.LONG -> IrConstImpl.long(startOffset, endOffset, targetType, longOrSmallerValue!!.toLong())
PrimitiveType.FLOAT -> {
val floatValue = when (val value = value) {
is Float -> value
is Double -> value.toFloat()
else -> uLongValue?.toFloat() ?: longOrSmallerValue?.toFloat()
}
IrConstImpl.float(startOffset, endOffset, targetType, floatValue!!)
}
PrimitiveType.DOUBLE -> {
val doubleValue = when (val value = value) {
is Float -> value.toDouble()
is Double -> value
else -> uLongValue?.toDouble() ?: longOrSmallerValue?.toDouble()
}
IrConstImpl.double(startOffset, endOffset, targetType, doubleValue!!)
}
else -> error("Cannot cast expression of type ${type.render()} to ${targetType.render()}")
}
}
Expand Down
211 changes: 211 additions & 0 deletions compiler/testData/codegen/box/ranges/unsigned/kt67383.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// WITH_STDLIB
// IGNORE_BACKEND: JVM

fun ubyte_rangeTo() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UByte.MIN_VALUE..UByte.MAX_VALUE) {
ints.add(b.toInt())
if (++counter > 256) error("Something went wrong")
}
require(ints == (0..255).toList()) { ints.toString() }
}

fun ubyte_downTo() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UByte.MAX_VALUE downTo UByte.MIN_VALUE) {
ints.add(b.toInt())
if (++counter > 256) error("Something went wrong")
}
require(ints == (255 downTo 0).toList()) { ints.toString() }
}

fun ubyte_rangeUntil() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UByte.MIN_VALUE..<UByte.MAX_VALUE) {
ints.add(b.toInt())
if (++counter > 255) error("Something went wrong")
}
require(ints == (0..<255).toList()) { ints.toString() }
}

fun ubyte_rangeTo2() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UByte.MIN_VALUE..UByte.MAX_VALUE step 2) {
ints.add(b.toInt())
if (++counter > 256) error("Something went wrong")
}
require(ints == (0..255 step 2).toList()) { ints.toString() }
}

fun ubyte_downTo2() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UByte.MAX_VALUE downTo UByte.MIN_VALUE step 2) {
ints.add(b.toInt())
if (++counter > 256) error("Something went wrong")
}
require(ints == (255 downTo 0 step 2).toList()) { ints.toString() }
}

fun ubyte_rangeUntil2() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UByte.MIN_VALUE..<UByte.MAX_VALUE step 2) {
ints.add(b.toInt())
if (++counter > 255) error("Something went wrong")
}
require(ints == (0..<255 step 2).toList()) { ints.toString() }
}

fun ubyte_rangeTo3() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UByte.MIN_VALUE..UByte.MAX_VALUE step 3) {
ints.add(b.toInt())
if (++counter > 256) error("Something went wrong")
}
require(ints == (0..255 step 3).toList()) { ints.toString() }
}

fun ubyte_downTo3() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UByte.MAX_VALUE downTo UByte.MIN_VALUE step 3) {
ints.add(b.toInt())
if (++counter > 256) error("Something went wrong")
}
require(ints == (255 downTo 0 step 3).toList()) { ints.toString() }
}

fun ubyte_rangeUntil3() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UByte.MIN_VALUE..<UByte.MAX_VALUE step 3) {
ints.add(b.toInt())
if (++counter > 255) error("Something went wrong")
}
require(ints == (0..<255 step 3).toList()) { ints.toString() }
}

fun ushort_rangeTo() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UShort.MIN_VALUE..UShort.MAX_VALUE) {
ints.add(b.toInt())
if (++counter > 65536) error("Something went wrong")
}
require(ints == (0..65535).toList()) { ints.toString() }
}

fun ushort_downTo() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UShort.MAX_VALUE downTo UShort.MIN_VALUE) {
ints.add(b.toInt())
if (++counter > 65536) error("Something went wrong")
}
require(ints == (65535 downTo 0).toList()) { ints.toString() }
}

fun ushort_rangeUntil() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UShort.MIN_VALUE..<UShort.MAX_VALUE) {
ints.add(b.toInt())
if (++counter > 65535) error("Something went wrong")
}
require(ints == (0..<65535).toList()) { ints.toString() }
}

fun ushort_rangeTo2() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UShort.MIN_VALUE..UShort.MAX_VALUE step 2) {
ints.add(b.toInt())
if (++counter > 65536) error("Something went wrong")
}
require(ints == (0..65535 step 2).toList()) { ints.toString() }
}

fun ushort_downTo2() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UShort.MAX_VALUE downTo UShort.MIN_VALUE step 2) {
ints.add(b.toInt())
if (++counter > 65536) error("Something went wrong")
}
require(ints == (65535 downTo 0 step 2).toList()) { ints.toString() }
}

fun ushort_rangeUntil2() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UShort.MIN_VALUE..<UShort.MAX_VALUE step 2) {
ints.add(b.toInt())
if (++counter > 65535) error("Something went wrong")
}
require(ints == (0..<65535 step 2).toList()) { ints.toString() }
}

fun ushort_rangeTo3() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UShort.MIN_VALUE..UShort.MAX_VALUE step 3) {
ints.add(b.toInt())
if (++counter > 65536) error("Something went wrong")
}
require(ints == (0..65535 step 3).toList()) { ints.toString() }
}

fun ushort_downTo3() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UShort.MAX_VALUE downTo UShort.MIN_VALUE step 3) {
ints.add(b.toInt())
if (++counter > 65536) error("Something went wrong")
}
require(ints == (65535 downTo 0 step 3).toList()) { ints.toString() }
}

fun ushort_rangeUntil3() {
var counter = 0
val ints = mutableListOf<Int>()
for (b in UShort.MIN_VALUE..<UShort.MAX_VALUE step 3) {
ints.add(b.toInt())
if (++counter > 65535) error("Something went wrong")
}
require(ints == (0..<65535 step 3).toList()) { ints.toString() }
}

fun box(): String {
ubyte_rangeTo()
ubyte_downTo()
ubyte_rangeUntil()

ubyte_rangeTo2()
ubyte_downTo2()
ubyte_rangeUntil2()

ubyte_rangeTo3()
ubyte_downTo3()
ubyte_rangeUntil3()


ushort_rangeTo()
ushort_downTo()
ushort_rangeUntil()

ushort_rangeTo2()
ushort_downTo2()
ushort_rangeUntil2()

ushort_rangeTo3()
ushort_downTo3()
ushort_rangeUntil3()

return "OK"
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3f0fc86

Please sign in to comment.