From 2dcfe219bef53be2eccddfcc5040ab2100ccde68 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Mon, 22 Nov 2021 13:45:21 +0300 Subject: [PATCH] Move string concat folding into `FlattenStringConcatenationLowering` Originally `FoldConstantLowering` is responsible for this, but it can be removed in the future. --- .../FlattenStringConcatenationLowering.kt | 3 +- .../optimizations/FoldConstantLowering.kt | 131 +++++++++--------- 2 files changed, 71 insertions(+), 63 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FlattenStringConcatenationLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FlattenStringConcatenationLowering.kt index cec34d07309..58ee0df9c1c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FlattenStringConcatenationLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/FlattenStringConcatenationLowering.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.lower.optimizations.FoldConstantLowering.Companion.tryToFold import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.ir.IrElement @@ -181,7 +182,7 @@ class FlattenStringConcatenationLowering(val context: CommonBackendContext) : Fi endOffset, type, collectStringConcatenationArguments(this) - ) + ).tryToFold(context, floatSpecial = false) } else expression diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/FoldConstantLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/FoldConstantLowering.kt index a2a5f7552e5..edc7ee16ea6 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/FoldConstantLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/optimizations/FoldConstantLowering.kt @@ -27,6 +27,8 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.resolve.constants.evaluate.evaluateBinary import org.jetbrains.kotlin.resolve.constants.evaluate.evaluateUnary import kotlin.math.floor +import kotlin.math.max +import kotlin.math.min val foldConstantLoweringPhase = makeIrFilePhase( { ctx: CommonBackendContext -> FoldConstantLowering(ctx) }, @@ -99,6 +101,71 @@ class FoldConstantLowering( registerBuiltinBinaryOp(LONG, BuiltInOperatorNames.GREATER_OR_EQUAL) { a, b -> a >= b } registerBuiltinBinaryOp(LONG, BuiltInOperatorNames.EQEQ) { a, b -> a == b } } + + fun IrStringConcatenation.tryToFold(context: CommonBackendContext, floatSpecial: Boolean): IrExpression { + val folded = mutableListOf() + for (next in this.arguments) { + val last = folded.lastOrNull() + when { + next !is IrConst<*> -> folded += next + last !is IrConst<*> -> folded += IrConstImpl.string( + next.startOffset, next.endOffset, context.irBuiltIns.stringType, constToString(next, floatSpecial) + ) + else -> folded[folded.size - 1] = IrConstImpl.string( + // Inlined strings may have `last.startOffset > next.endOffset` + min(last.startOffset, next.startOffset), max(last.endOffset, next.endOffset), + context.irBuiltIns.stringType, + constToString(last, floatSpecial) + constToString(next, floatSpecial) + ) + } + } + return folded.singleOrNull() as? IrConst<*> + ?: IrStringConcatenationImpl(this.startOffset, this.endOffset, this.type, folded) + } + + private fun constToString(const: IrConst<*>, floatSpecial: Boolean): String { + if (floatSpecial) { + when (val kind = const.kind) { + is IrConstKind.Float -> { + val f = kind.valueOf(const) + if (!f.isInfinite()) { + if (floor(f) == f) { + return f.toInt().toString() + } + } + } + is IrConstKind.Double -> { + val d = kind.valueOf(const) + if (!d.isInfinite()) { + if (floor(d) == d) { + return d.toLong().toString() + } + } + } + else -> {} + } + } + + return normalizeUnsignedValue(const).toString() + } + + private fun normalizeUnsignedValue(const: IrConst<*>): Any? { + // Unsigned constants are represented through signed constants with a different IrType + if (const.type.isUnsigned()) { + when (val kind = const.kind) { + is IrConstKind.Byte -> + return kind.valueOf(const).toUByte() + is IrConstKind.Short -> + return kind.valueOf(const).toUShort() + is IrConstKind.Int -> + return kind.valueOf(const).toUInt() + is IrConstKind.Long -> + return kind.valueOf(const).toULong() + else -> {} + } + } + return const.value + } } private fun fromFloatConstSafe(startOffset: Int, endOffset: Int, type: IrType, v: Any?): IrConst<*> = @@ -132,7 +199,7 @@ class FoldConstantLowering( val evaluated = when { // Since there is no distinguish between signed and unsigned types a special handling for `toString` is required - operationName == "toString" -> constToString(operand) + operationName == "toString" -> constToString(operand, floatSpecial) // Disable toFloat folding on K/JS till `toFloat` is fixed (KT-35422) operationName == "toFloat" && floatSpecial -> return call operand.kind == IrConstKind.Null -> return call @@ -210,50 +277,6 @@ class FoldConstantLowering( return buildIrConstant(call.startOffset, call.endOffset, call.type, evaluated) } - private fun normalizeUnsignedValue(const: IrConst<*>): Any? { - // Unsigned constants are represented through signed constants with a different IrType - if (const.type.isUnsigned()) { - when (val kind = const.kind) { - is IrConstKind.Byte -> - return kind.valueOf(const).toUByte() - is IrConstKind.Short -> - return kind.valueOf(const).toUShort() - is IrConstKind.Int -> - return kind.valueOf(const).toUInt() - is IrConstKind.Long -> - return kind.valueOf(const).toULong() - else -> {} - } - } - return const.value - } - - private fun constToString(const: IrConst<*>): String { - if (floatSpecial) { - when (val kind = const.kind) { - is IrConstKind.Float -> { - val f = kind.valueOf(const) - if (!f.isInfinite()) { - if (floor(f) == f) { - return f.toInt().toString() - } - } - } - is IrConstKind.Double -> { - val d = kind.valueOf(const) - if (!d.isInfinite()) { - if (floor(d) == d) { - return d.toLong().toString() - } - } - } - else -> {} - } - } - - return normalizeUnsignedValue(const).toString() - } - override fun lower(irBody: IrBody, container: IrDeclaration) { irBody.transformChildrenVoid(object : IrElementTransformerVoid() { override fun visitCall(expression: IrCall): IrExpression { @@ -270,23 +293,7 @@ class FoldConstantLowering( override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression { expression.transformChildrenVoid() - val folded = mutableListOf() - for (next in expression.arguments) { - val last = folded.lastOrNull() - when { - next !is IrConst<*> -> folded += next - last !is IrConst<*> -> folded += IrConstImpl.string( - next.startOffset, next.endOffset, context.irBuiltIns.stringType, constToString(next) - ) - else -> folded[folded.size - 1] = IrConstImpl.string( - // Inlined strings may have `last.startOffset > next.endOffset` - Math.min(last.startOffset, next.startOffset), Math.max(last.endOffset, next.endOffset), context.irBuiltIns.stringType, - constToString(last) + constToString(next) - ) - } - } - return folded.singleOrNull() as? IrConst<*> - ?: IrStringConcatenationImpl(expression.startOffset, expression.endOffset, expression.type, folded) + return expression.tryToFold(context, floatSpecial) } override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {