diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 429354b2d62..ef7033f8145 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -102,6 +102,7 @@ internal val jvmPhases = namedIrFilePhase( tailrecPhase then toArrayPhase then jvmTypeOperatorLoweringPhase then + foldConstantLoweringPhase then flattenStringConcatenationPhase then jvmBuiltinOptimizationLoweringPhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FoldConstantLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FoldConstantLowering.kt new file mode 100644 index 00000000000..1be0a92bf72 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FoldConstantLowering.kt @@ -0,0 +1,211 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.resolve.constants.evaluate.evaluateBinary +import org.jetbrains.kotlin.resolve.constants.evaluate.evaluateUnary + +internal val foldConstantLoweringPhase = makeIrFilePhase( + ::FoldConstantLowering, + name = "FoldConstantLowering", + description = "Constant Folding" +) + +/** + * A pass to fold constant expressions of most common types. + * + * For example, the expression "O" + 'K' + (1.toLong() + 2.0) will be folded to "OK3.0" at compile time. + * + * TODO: constant fields (e.g. Double.NaN) + */ +class FoldConstantLowering(private val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { + + /** + * ID of an unary operator / method. + * + * An unary operator / method can be identified by its operand type (in full qualified name) and its name. + */ + private data class UnaryOp( + val operandType: String, + val operatorName: String + ) + + /** + * ID of an binary operator / method. + * + * An binary operator / method can be identified by its operand types (in full qualified names) and its name. + */ + private data class BinaryOp( + val lhsType: String, + val rhsType: String, + val operatorName: String + ) + + private data class PrimitiveType(val name: String) + + companion object { + private val BYTE = PrimitiveType("Byte") + private val SHORT = PrimitiveType("Short") + private val INT = PrimitiveType("Int") + private val LONG = PrimitiveType("Long") + private val DOUBLE = PrimitiveType("Double") + private val FLOAT = PrimitiveType("Float") + private val CHAR = PrimitiveType("Char") + private val BOOLEAN = PrimitiveType("Boolean") + private val STRING = PrimitiveType("String") + + private val UNARY_OP_TO_EVALUATOR = HashMap>() + private val BINARY_OP_TO_EVALUATOR = HashMap>() + + @Suppress("UNCHECKED_CAST") + private fun registerBuiltinUnaryOp(operandType: PrimitiveType, operatorName: String, f: (T) -> Any) { + UNARY_OP_TO_EVALUATOR[UnaryOp(operandType.name, operatorName)] = f as Function1 + } + + @Suppress("UNCHECKED_CAST") + private fun registerBuiltinBinaryOp(operandType: PrimitiveType, operatorName: String, f: (T, T) -> Any) { + BINARY_OP_TO_EVALUATOR[BinaryOp(operandType.name, operandType.name, operatorName)] = f as Function2 + } + + init { + // IrBuiltins + registerBuiltinUnaryOp(BOOLEAN, IrBuiltIns.OperatorNames.NOT) { !it } + + registerBuiltinBinaryOp(DOUBLE, IrBuiltIns.OperatorNames.LESS) { a, b -> a < b } + registerBuiltinBinaryOp(DOUBLE, IrBuiltIns.OperatorNames.LESS_OR_EQUAL) { a, b -> a <= b } + registerBuiltinBinaryOp(DOUBLE, IrBuiltIns.OperatorNames.GREATER) { a, b -> a > b } + registerBuiltinBinaryOp(DOUBLE, IrBuiltIns.OperatorNames.GREATER_OR_EQUAL) { a, b -> a >= b } + registerBuiltinBinaryOp(DOUBLE, IrBuiltIns.OperatorNames.IEEE754_EQUALS) { a, b -> a == b } + + registerBuiltinBinaryOp(FLOAT, IrBuiltIns.OperatorNames.LESS) { a, b -> a < b } + registerBuiltinBinaryOp(FLOAT, IrBuiltIns.OperatorNames.LESS_OR_EQUAL) { a, b -> a <= b } + registerBuiltinBinaryOp(FLOAT, IrBuiltIns.OperatorNames.GREATER) { a, b -> a > b } + registerBuiltinBinaryOp(FLOAT, IrBuiltIns.OperatorNames.GREATER_OR_EQUAL) { a, b -> a >= b } + registerBuiltinBinaryOp(FLOAT, IrBuiltIns.OperatorNames.IEEE754_EQUALS) { a, b -> a == b } + + registerBuiltinBinaryOp(INT, IrBuiltIns.OperatorNames.LESS) { a, b -> a < b } + registerBuiltinBinaryOp(INT, IrBuiltIns.OperatorNames.LESS_OR_EQUAL) { a, b -> a <= b } + registerBuiltinBinaryOp(INT, IrBuiltIns.OperatorNames.GREATER) { a, b -> a > b } + registerBuiltinBinaryOp(INT, IrBuiltIns.OperatorNames.GREATER_OR_EQUAL) { a, b -> a >= b } + registerBuiltinBinaryOp(INT, IrBuiltIns.OperatorNames.EQEQ) { a, b -> a == b } + + registerBuiltinBinaryOp(LONG, IrBuiltIns.OperatorNames.LESS) { a, b -> a < b } + registerBuiltinBinaryOp(LONG, IrBuiltIns.OperatorNames.LESS_OR_EQUAL) { a, b -> a <= b } + registerBuiltinBinaryOp(LONG, IrBuiltIns.OperatorNames.GREATER) { a, b -> a > b } + registerBuiltinBinaryOp(LONG, IrBuiltIns.OperatorNames.GREATER_OR_EQUAL) { a, b -> a >= b } + registerBuiltinBinaryOp(LONG, IrBuiltIns.OperatorNames.EQEQ) { a, b -> a == b } + } + } + + private fun buildIrConstant(call: IrCall, v: Any): IrExpression { + return when { + call.type.isInt() -> IrConstImpl.int(call.startOffset, call.endOffset, call.type, v as Int) + call.type.isChar() -> IrConstImpl.char(call.startOffset, call.endOffset, call.type, v as Char) + call.type.isBoolean() -> IrConstImpl.boolean(call.startOffset, call.endOffset, call.type, v as Boolean) + call.type.isByte() -> IrConstImpl.byte(call.startOffset, call.endOffset, call.type, v as Byte) + call.type.isShort() -> IrConstImpl.short(call.startOffset, call.endOffset, call.type, v as Short) + call.type.isLong() -> IrConstImpl.long(call.startOffset, call.endOffset, call.type, v as Long) + call.type.isDouble() -> IrConstImpl.double(call.startOffset, call.endOffset, call.type, v as Double) + call.type.isFloat() -> IrConstImpl.float(call.startOffset, call.endOffset, call.type, v as Float) + call.type.isString() -> IrConstImpl.string(call.startOffset, call.endOffset, call.type, v as String) + else -> throw IllegalArgumentException("Unexpected IrCall return type") + } + } + + private fun tryFoldingUnaryOps(call: IrCall): IrExpression { + val operand = call.dispatchReceiver as? IrConst<*> ?: return call + val evaluated = evaluateUnary( + call.symbol.owner.name.toString(), + operand.kind.toString(), + operand.value!! + ) ?: return call + return buildIrConstant(call, evaluated) + } + + private fun tryFoldingBuiltinUnaryOps(call: IrCall): IrExpression { + if (call.symbol.owner.origin != IrDeclarationOrigin.IR_BUILTINS_STUB) + return call + + val operand = call.getValueArgument(0) as? IrConst<*> ?: return call + val evaluator = UNARY_OP_TO_EVALUATOR[UnaryOp(operand.kind.toString(), call.symbol.owner.name.toString())] ?: return call + + return buildIrConstant(call, evaluator(operand.value!!)) + } + + private fun tryFoldingBinaryOps(call: IrCall): IrExpression { + val lhs = call.dispatchReceiver as? IrConst<*> ?: return call + val rhs = call.getValueArgument(0) as? IrConst<*> ?: return call + + val evaluated = try { + fun String.toNonNullable() = if (this.endsWith('?')) this.dropLast(1) else this + evaluateBinary( + call.symbol.owner.name.toString(), + lhs.kind.toString(), + lhs.value!!, + // 1. Although some operators have nullable parameters, evaluators deals with non-nullable types only. + // The passed parameters are guaranteed to be non-null, since they are from IrConst. + // 2. The operators are registered with prototype as if virtual member functions. They are identified by + // actual_receiver_type.operator_name(parameter_type_in_prototype). + call.symbol.owner.valueParameters[0].type.toKotlinType().toString().toNonNullable(), + rhs.value!! + ) ?: return call + } catch (e: Exception) { + // Don't cast a runtime exception into compile time. E.g., division by zero. + return call + } + + return buildIrConstant(call, evaluated) + } + + private fun tryFoldingBuiltinBinaryOps(call: IrCall): IrExpression { + // Make sure that this is a IrBuiltIn + if (call.symbol.owner.origin != IrDeclarationOrigin.IR_BUILTINS_STUB) + return call + + val lhs = call.getValueArgument(0) as? IrConst<*> ?: return call + val rhs = call.getValueArgument(1) as? IrConst<*> ?: return call + + val evaluated = try { + val evaluator = + BINARY_OP_TO_EVALUATOR[BinaryOp(lhs.kind.toString(), rhs.kind.toString(), call.symbol.owner.name.toString())] ?: return call + evaluator(lhs.value!!, rhs.value!!) + } catch (e: Exception) { + return call + } + + return buildIrConstant(call, evaluated) + } + + override fun lower(irFile: IrFile) { + irFile.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + + return when { + expression.extensionReceiver != null -> expression + expression.dispatchReceiver != null && expression.valueArgumentsCount == 0 -> tryFoldingUnaryOps(expression) + expression.dispatchReceiver != null && expression.valueArgumentsCount == 1 -> tryFoldingBinaryOps(expression) + expression.dispatchReceiver == null && expression.valueArgumentsCount == 1 -> tryFoldingBuiltinUnaryOps(expression) + expression.dispatchReceiver == null && expression.valueArgumentsCount == 2 -> tryFoldingBuiltinBinaryOps(expression) + else -> expression + } + } + }) + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/constants/comparisonFalse.kt b/compiler/testData/codegen/box/constants/comparisonFalse.kt new file mode 100644 index 00000000000..93a528c09c9 --- /dev/null +++ b/compiler/testData/codegen/box/constants/comparisonFalse.kt @@ -0,0 +1,16 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JS_IR +fun foo(): Array { + return arrayOf( + 0.0 / 0 == 0.0 / 0, + 0.0F > -0.0F, + 0.0.equals(-0.0), + (0.0 / 0.0).equals(1.0 / 0.0) + ) +} + +fun box(): String { + if (foo().any { it == true }) + return "fail: ${foo().contentDeepToString()}" + return "OK" +} diff --git a/compiler/testData/codegen/box/constants/comparisonTrue.kt b/compiler/testData/codegen/box/constants/comparisonTrue.kt new file mode 100644 index 00000000000..c7a196e6296 --- /dev/null +++ b/compiler/testData/codegen/box/constants/comparisonTrue.kt @@ -0,0 +1,23 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JS_IR +fun foo(): Array { + return arrayOf( + 19 < 20.0, + 12 > 11, + 3.0F <= 4.0, + 4.0F >= 4, + 0.0 / 0 != 0.0 / 0, + 0.0 == -0.0, + 123 == 123, + 123L == 123L, + 0.0F == -0.0F, + 0.0.compareTo(-0.0) > 0, + (0.0 / 0.0).compareTo(1.0 / 0.0) > 0 + ) +} + +fun box(): String { + if (foo().any { it == false }) + return "fail: ${foo().contentDeepToString()}" + return "OK" +} diff --git a/compiler/testData/codegen/box/constants/divisionByZero.kt b/compiler/testData/codegen/box/constants/divisionByZero.kt new file mode 100644 index 00000000000..fcb9ddd018f --- /dev/null +++ b/compiler/testData/codegen/box/constants/divisionByZero.kt @@ -0,0 +1,25 @@ +// IGNORE_BACKEND: JS_IR +// IGNORE_BACKEND: JS +// reason - no error from division by zero in JS + +fun expectArithmeticException(f: () -> Unit): Boolean { + try { + f() + } catch (e: ArithmeticException) { + return true + } + return false +} + +fun box(): String { + if (!expectArithmeticException { 1 / 0 }) + return "fail: 1 / 0 didn't throw exception" + + if (!expectArithmeticException { 1 * 2 / 0 }) + return "fail: 1 * 2 / 0 didn't throw exception" + + if (!expectArithmeticException { 1 * (2 / 0) }) + return "fail: 1 * (2 / 0) didn't throw exception" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/primitiveTypes/kt2269.kt b/compiler/testData/codegen/box/primitiveTypes/kt2269.kt index 836db5a10b0..e1896168c8f 100644 --- a/compiler/testData/codegen/box/primitiveTypes/kt2269.kt +++ b/compiler/testData/codegen/box/primitiveTypes/kt2269.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR fun box() : String { 230?.toByte()?.hashCode() 9.hashCode() diff --git a/compiler/testData/codegen/box/primitiveTypes/kt2269NotOptimizable.kt b/compiler/testData/codegen/box/primitiveTypes/kt2269NotOptimizable.kt new file mode 100644 index 00000000000..c61ecc0c28c --- /dev/null +++ b/compiler/testData/codegen/box/primitiveTypes/kt2269NotOptimizable.kt @@ -0,0 +1,25 @@ +// IGNORE_BACKEND: JVM_IR +fun identity(x: Int): Int { + return when { + x < 0 -> identity(x + 1) - 1 + x > 0 -> identity(x - 1) + 1 + else -> 0 + } +} + +fun box() : String { + // Just hard enough that the test won't get optimized away at compile time. + val twoThirty = identity(230) + val nine = identity(9) + twoThirty?.toByte()?.hashCode() + nine.hashCode() + + if(twoThirty.equals(nine.toByte())) { + return "fail" + } + + if(twoThirty == nine.toByte().toInt()) { + return "fail" + } + return "OK" +} diff --git a/compiler/testData/codegen/bytecodeText/constants/byte.kt b/compiler/testData/codegen/bytecodeText/constants/byte.kt index b6e0bcc57b9..8809d08dbeb 100644 --- a/compiler/testData/codegen/bytecodeText/constants/byte.kt +++ b/compiler/testData/codegen/bytecodeText/constants/byte.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR val a: Byte = 1 + 10 // 1 BIPUSH 11 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/constants/comparisonFalse.kt b/compiler/testData/codegen/bytecodeText/constants/comparisonFalse.kt new file mode 100644 index 00000000000..dc2cdb90b61 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/constants/comparisonFalse.kt @@ -0,0 +1,22 @@ +// TARGET_BACKEND: JVM_IR + +fun foo(): Array { + return arrayOf( + 0.0 / 0 == 0.0 / 0, + 0.0F > -0.0F, + 0.0.equals(-0.0), + (0.0 / 0.0).equals(1.0 / 0.0) + ) +} + +// Disabled: current backend doesn't fold them. +// 4 INVOKESTATIC +// 4 INVOKESTATIC java/lang/Boolean.valueOf +// 1 ICONST_1 +// 5 ICONST_0 +// 0 IFEQ +// 0 IFNE +// 0 IFGE +// 0 IFGT +// 0 IFLE +// 0 IFLT diff --git a/compiler/testData/codegen/bytecodeText/constants/comparisonTrue.kt b/compiler/testData/codegen/bytecodeText/constants/comparisonTrue.kt new file mode 100644 index 00000000000..ded42b3a9d8 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/constants/comparisonTrue.kt @@ -0,0 +1,29 @@ +// TARGET_BACKEND: JVM_IR + +fun foo(): Array { + return arrayOf( + 19 < 20.0, + 12 > 11, + 3.0F <= 4.0, + 4.0F >= 4, + 0.0 / 0 != 0.0 / 0, + 0.0 == -0.0, + 123 == 123, + 123L == 123L, + 0.0F == -0.0F, + 0.0.compareTo(-0.0) > 0, + (0.0 / 0.0).compareTo(1.0 / 0.0) > 0 + ) +} + +// Disabled because the current backend doesn't fold them. +// 11 INVOKESTATIC +// 11 INVOKESTATIC java/lang/Boolean.valueOf +// 1 ICONST_0 +// 12 ICONST_1 +// 0 IFEQ +// 0 IFNE +// 0 IFGE +// 0 IFGT +// 0 IFLE +// 0 IFLT diff --git a/compiler/testData/codegen/bytecodeText/constants/floatingPoints.kt b/compiler/testData/codegen/bytecodeText/constants/floatingPoints.kt new file mode 100644 index 00000000000..e6457a43fb1 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/constants/floatingPoints.kt @@ -0,0 +1,16 @@ +val a = 1.0 + 10 +val b = 2 + 10.0 +val c = 3.0F + 10 +val d = 4 + 10.0F +val e = 1.0 / 0 +val f = 1 / 0.0 +val g = 0.0 / 0 +val h = 0 / 0.0 +val i = 0.0 / 0.0 + +// 1 LDC 11.0 +// 1 LDC 12.0 +// 1 LDC 13.0 +// 1 LDC 14.0 +// 2 LDC Infinity +// 3 LDC NaN diff --git a/compiler/testData/codegen/bytecodeText/constants/partialString.kt b/compiler/testData/codegen/bytecodeText/constants/partialString.kt index 015fa4b8bf6..783f5870f5d 100644 --- a/compiler/testData/codegen/bytecodeText/constants/partialString.kt +++ b/compiler/testData/codegen/bytecodeText/constants/partialString.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR fun box(): String { val z = 1; return "O" + "K".toString() + z diff --git a/compiler/testData/codegen/bytecodeText/constants/short.kt b/compiler/testData/codegen/bytecodeText/constants/short.kt index 1e688864dce..bf041dae18e 100644 --- a/compiler/testData/codegen/bytecodeText/constants/short.kt +++ b/compiler/testData/codegen/bytecodeText/constants/short.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR val a: Short = 1 + 255 // 1 SIPUSH 256 \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/constants/string.kt b/compiler/testData/codegen/bytecodeText/constants/string.kt index add29c91c4b..ea1c09b8141 100644 --- a/compiler/testData/codegen/bytecodeText/constants/string.kt +++ b/compiler/testData/codegen/bytecodeText/constants/string.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR fun box(): String { return "O" + "K".toString() + 1.toLong() } diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt index ec4628b2635..b1b5240cad7 100644 --- a/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR class A fun foo(x: Any?) {} diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxingNotOptimizable.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxingNotOptimizable.kt new file mode 100644 index 00000000000..66471397a4f --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxingNotOptimizable.kt @@ -0,0 +1,21 @@ +class A + +fun foo(x: Any?) {} + +fun box(u: Int) { + val x: Int? = 1 + x!! + + val z: Int? = if (u == 1) x else null + z!! + + foo(1 as java.lang.Integer) + + val y: Any? = if (u == 1) x else A() + y!! +} + +// 0 IFNULL +// 1 IFNONNULL +// 1 throwNpe +// 0 ATHROW diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt index b175e4e2f06..f160e4c4969 100644 --- a/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR class A fun box() { val x: A? = A() diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundantNotOptimizable.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundantNotOptimizable.kt new file mode 100644 index 00000000000..1c929f8220c --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundantNotOptimizable.kt @@ -0,0 +1,18 @@ +class A +fun box(u: Int) { + val x: A? = A() + val y: A? + if (u == 0) { + y = x + } + else { + y = null + } + + y!! +} + +// 0 IFNULL +// 1 IFNONNULL +// 1 throwNpe +// 0 ATHROW diff --git a/compiler/testData/codegen/bytecodeText/stringOperations/concat.kt b/compiler/testData/codegen/bytecodeText/stringOperations/concat.kt index 46e1c2b9963..013c909eb6e 100644 --- a/compiler/testData/codegen/bytecodeText/stringOperations/concat.kt +++ b/compiler/testData/codegen/bytecodeText/stringOperations/concat.kt @@ -6,9 +6,9 @@ class A() { } -fun box() : String { +fun box(a: String, b: String) : String { - val s = "1" + "2" + 3 + 4L + 5.0 + 6F + '7' + A() + val s = a + "1" + "2" + 3 + 4L + b + 5.0 + 6F + '7' + A() return "OK" } diff --git a/compiler/testData/codegen/bytecodeText/stringOperations/primitiveToString.kt b/compiler/testData/codegen/bytecodeText/stringOperations/primitiveToString.kt index b55d752919c..0949738e477 100644 --- a/compiler/testData/codegen/bytecodeText/stringOperations/primitiveToString.kt +++ b/compiler/testData/codegen/bytecodeText/stringOperations/primitiveToString.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND: JVM_IR fun main() { false.toString() 1.toByte().toString() diff --git a/compiler/testData/codegen/bytecodeText/stringOperations/primitiveToStringNotOptimizable.kt b/compiler/testData/codegen/bytecodeText/stringOperations/primitiveToStringNotOptimizable.kt new file mode 100644 index 00000000000..a7d9d263dd1 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/stringOperations/primitiveToStringNotOptimizable.kt @@ -0,0 +1,14 @@ +fun main(a: Boolean, b:Byte, c: Short, d: Int, e: Long, f: Float, g: Double, h: Char) { + a.toString() + b.toString() + c.toString() + d.toString() + e.toString() + f.toString() + g.toString() + h.toString() +} + +/*Check that all "valueOf" are String ones and there is no boxing*/ +// 8 valueOf +// 8 INVOKESTATIC java/lang/String.valueOf diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index a2771d5f12f..ac1e9ee2fef 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4379,11 +4379,26 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/constants"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("comparisonFalse.kt") + public void testComparisonFalse() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonFalse.kt"); + } + + @TestMetadata("comparisonTrue.kt") + public void testComparisonTrue() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonTrue.kt"); + } + @TestMetadata("constantsInWhen.kt") public void testConstantsInWhen() throws Exception { runTest("compiler/testData/codegen/box/constants/constantsInWhen.kt"); } + @TestMetadata("divisionByZero.kt") + public void testDivisionByZero() throws Exception { + runTest("compiler/testData/codegen/box/constants/divisionByZero.kt"); + } + @TestMetadata("float.kt") public void testFloat() throws Exception { runTest("compiler/testData/codegen/box/constants/float.kt"); @@ -17176,6 +17191,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/primitiveTypes/kt2269.kt"); } + @TestMetadata("kt2269NotOptimizable.kt") + public void testKt2269NotOptimizable() throws Exception { + runTest("compiler/testData/codegen/box/primitiveTypes/kt2269NotOptimizable.kt"); + } + @TestMetadata("kt2275.kt") public void testKt2275() throws Exception { runTest("compiler/testData/codegen/box/primitiveTypes/kt2275.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index ad5514dfa1b..204a27dcce2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1118,6 +1118,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/constants/byte.kt"); } + @TestMetadata("floatingPoints.kt") + public void testFloatingPoints() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/constants/floatingPoints.kt"); + } + @TestMetadata("inlineUnsignedIntConstant.kt") public void testInlineUnsignedIntConstant() throws Exception { runTest("compiler/testData/codegen/bytecodeText/constants/inlineUnsignedIntConstant.kt"); @@ -1472,6 +1477,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt"); } + @TestMetadata("boxingNotOptimizable.kt") + public void testBoxingNotOptimizable() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/boxingNotOptimizable.kt"); + } + @TestMetadata("emptyVariableRange.kt") public void testEmptyVariableRange() throws Exception { runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/emptyVariableRange.kt"); @@ -1501,6 +1511,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { public void testSimpleConstructorNotRedundant() throws Exception { runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt"); } + + @TestMetadata("simpleConstructorNotRedundantNotOptimizable.kt") + public void testSimpleConstructorNotRedundantNotOptimizable() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundantNotOptimizable.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/defaultArguments") @@ -3377,6 +3392,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/stringOperations/primitiveToString.kt"); } + @TestMetadata("primitiveToStringNotOptimizable.kt") + public void testPrimitiveToStringNotOptimizable() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/stringOperations/primitiveToStringNotOptimizable.kt"); + } + @TestMetadata("primitivesAsStringTemplates.kt") public void testPrimitivesAsStringTemplates() throws Exception { runTest("compiler/testData/codegen/bytecodeText/stringOperations/primitivesAsStringTemplates.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index bef3783edd7..d81c3475d7b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -4379,11 +4379,26 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/constants"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("comparisonFalse.kt") + public void testComparisonFalse() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonFalse.kt"); + } + + @TestMetadata("comparisonTrue.kt") + public void testComparisonTrue() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonTrue.kt"); + } + @TestMetadata("constantsInWhen.kt") public void testConstantsInWhen() throws Exception { runTest("compiler/testData/codegen/box/constants/constantsInWhen.kt"); } + @TestMetadata("divisionByZero.kt") + public void testDivisionByZero() throws Exception { + runTest("compiler/testData/codegen/box/constants/divisionByZero.kt"); + } + @TestMetadata("float.kt") public void testFloat() throws Exception { runTest("compiler/testData/codegen/box/constants/float.kt"); @@ -17176,6 +17191,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/primitiveTypes/kt2269.kt"); } + @TestMetadata("kt2269NotOptimizable.kt") + public void testKt2269NotOptimizable() throws Exception { + runTest("compiler/testData/codegen/box/primitiveTypes/kt2269NotOptimizable.kt"); + } + @TestMetadata("kt2275.kt") public void testKt2275() throws Exception { runTest("compiler/testData/codegen/box/primitiveTypes/kt2275.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 6e7e0a8e3f5..4509ec6a461 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -4379,11 +4379,26 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/constants"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("comparisonFalse.kt") + public void testComparisonFalse() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonFalse.kt"); + } + + @TestMetadata("comparisonTrue.kt") + public void testComparisonTrue() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonTrue.kt"); + } + @TestMetadata("constantsInWhen.kt") public void testConstantsInWhen() throws Exception { runTest("compiler/testData/codegen/box/constants/constantsInWhen.kt"); } + @TestMetadata("divisionByZero.kt") + public void testDivisionByZero() throws Exception { + runTest("compiler/testData/codegen/box/constants/divisionByZero.kt"); + } + @TestMetadata("float.kt") public void testFloat() throws Exception { runTest("compiler/testData/codegen/box/constants/float.kt"); @@ -17181,6 +17196,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/primitiveTypes/kt2269.kt"); } + @TestMetadata("kt2269NotOptimizable.kt") + public void testKt2269NotOptimizable() throws Exception { + runTest("compiler/testData/codegen/box/primitiveTypes/kt2269NotOptimizable.kt"); + } + @TestMetadata("kt2275.kt") public void testKt2275() throws Exception { runTest("compiler/testData/codegen/box/primitiveTypes/kt2275.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index 6f015391fea..e4843df190e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -1118,6 +1118,21 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/constants/byte.kt"); } + @TestMetadata("comparisonFalse.kt") + public void testComparisonFalse() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/constants/comparisonFalse.kt"); + } + + @TestMetadata("comparisonTrue.kt") + public void testComparisonTrue() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/constants/comparisonTrue.kt"); + } + + @TestMetadata("floatingPoints.kt") + public void testFloatingPoints() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/constants/floatingPoints.kt"); + } + @TestMetadata("inlineUnsignedIntConstant.kt") public void testInlineUnsignedIntConstant() throws Exception { runTest("compiler/testData/codegen/bytecodeText/constants/inlineUnsignedIntConstant.kt"); @@ -1472,6 +1487,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt"); } + @TestMetadata("boxingNotOptimizable.kt") + public void testBoxingNotOptimizable() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/boxingNotOptimizable.kt"); + } + @TestMetadata("emptyVariableRange.kt") public void testEmptyVariableRange() throws Exception { runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/emptyVariableRange.kt"); @@ -1501,6 +1521,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { public void testSimpleConstructorNotRedundant() throws Exception { runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt"); } + + @TestMetadata("simpleConstructorNotRedundantNotOptimizable.kt") + public void testSimpleConstructorNotRedundantNotOptimizable() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundantNotOptimizable.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/defaultArguments") @@ -3377,6 +3402,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/stringOperations/primitiveToString.kt"); } + @TestMetadata("primitiveToStringNotOptimizable.kt") + public void testPrimitiveToStringNotOptimizable() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/stringOperations/primitiveToStringNotOptimizable.kt"); + } + @TestMetadata("primitivesAsStringTemplates.kt") public void testPrimitivesAsStringTemplates() throws Exception { runTest("compiler/testData/codegen/bytecodeText/stringOperations/primitivesAsStringTemplates.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index ce72e8a8867..33a6dbb2172 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -3649,11 +3649,26 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/constants"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true); } + @TestMetadata("comparisonFalse.kt") + public void testComparisonFalse() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonFalse.kt"); + } + + @TestMetadata("comparisonTrue.kt") + public void testComparisonTrue() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonTrue.kt"); + } + @TestMetadata("constantsInWhen.kt") public void testConstantsInWhen() throws Exception { runTest("compiler/testData/codegen/box/constants/constantsInWhen.kt"); } + @TestMetadata("divisionByZero.kt") + public void testDivisionByZero() throws Exception { + runTest("compiler/testData/codegen/box/constants/divisionByZero.kt"); + } + @TestMetadata("float.kt") public void testFloat() throws Exception { runTest("compiler/testData/codegen/box/constants/float.kt"); @@ -13426,6 +13441,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/primitiveTypes/kt2269.kt"); } + @TestMetadata("kt2269NotOptimizable.kt") + public void testKt2269NotOptimizable() throws Exception { + runTest("compiler/testData/codegen/box/primitiveTypes/kt2269NotOptimizable.kt"); + } + @TestMetadata("kt2275.kt") public void testKt2275() throws Exception { runTest("compiler/testData/codegen/box/primitiveTypes/kt2275.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 794040c0975..c508367ac89 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -3659,11 +3659,26 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/constants"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("comparisonFalse.kt") + public void testComparisonFalse() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonFalse.kt"); + } + + @TestMetadata("comparisonTrue.kt") + public void testComparisonTrue() throws Exception { + runTest("compiler/testData/codegen/box/constants/comparisonTrue.kt"); + } + @TestMetadata("constantsInWhen.kt") public void testConstantsInWhen() throws Exception { runTest("compiler/testData/codegen/box/constants/constantsInWhen.kt"); } + @TestMetadata("divisionByZero.kt") + public void testDivisionByZero() throws Exception { + runTest("compiler/testData/codegen/box/constants/divisionByZero.kt"); + } + @TestMetadata("float.kt") public void testFloat() throws Exception { runTest("compiler/testData/codegen/box/constants/float.kt"); @@ -14526,6 +14541,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/primitiveTypes/kt2269.kt"); } + @TestMetadata("kt2269NotOptimizable.kt") + public void testKt2269NotOptimizable() throws Exception { + runTest("compiler/testData/codegen/box/primitiveTypes/kt2269NotOptimizable.kt"); + } + @TestMetadata("kt2275.kt") public void testKt2275() throws Exception { runTest("compiler/testData/codegen/box/primitiveTypes/kt2275.kt");