From b27b202c28a8ce57caecbeb4137ec9ed19d65414 Mon Sep 17 00:00:00 2001 From: Sergej Jaskiewicz Date: Fri, 22 Oct 2021 14:48:46 +0300 Subject: [PATCH] [IR] Deduplicate StringConcatenationLowering in K/N The common lowering is updated based on fac1cf189c9e4d464f4900319e582e3fe090d71e --- .../lower/StringConcatenationLowering.kt | 81 ++++++------- .../backend/konan/KonanLoweringPhases.kt | 2 +- .../lower/StringConcatenationLowering.kt | 114 ------------------ 3 files changed, 39 insertions(+), 158 deletions(-) delete mode 100644 kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/StringConcatenationLowering.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/StringConcatenationLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/StringConcatenationLowering.kt index a2cb3dcca7b..258c4c09670 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/StringConcatenationLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/StringConcatenationLowering.kt @@ -19,7 +19,6 @@ 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.atMostOne -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrExpression @@ -27,41 +26,37 @@ import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.isNullable import org.jetbrains.kotlin.ir.types.isNullableAny +import org.jetbrains.kotlin.ir.types.isStringClassType import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.functions -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.util.OperatorNameConventions /** * This lowering pass replaces [IrStringConcatenation]s with StringBuilder appends. */ -class StringConcatenationLowering(val context: CommonBackendContext) : FileLoweringPass { +class StringConcatenationLowering(context: CommonBackendContext) : FileLoweringPass, IrBuildingTransformer(context) { override fun lower(irFile: IrFile) { - irFile.transformChildrenVoid(StringConcatenationTransformer(this)) + irFile.transformChildrenVoid(this) } -} -private class StringConcatenationTransformer(val lower: StringConcatenationLowering) : IrElementTransformerVoid() { - - private val buildersStack = mutableListOf() - private val context = lower.context private val irBuiltIns = context.irBuiltIns + private val symbols = context.ir.symbols private val typesWithSpecialAppendFunction = irBuiltIns.primitiveIrTypes + irBuiltIns.stringType - private val nameToString = Name.identifier("toString") private val nameAppend = Name.identifier("append") private val stringBuilder = context.ir.symbols.stringBuilder.owner //TODO: calculate and pass string length to the constructor. private val constructor = stringBuilder.constructors.single { - it.valueParameters.size == 0 + it.valueParameters.isEmpty() } private val toStringFunction = stringBuilder.functions.single { - it.valueParameters.size == 0 && it.name == nameToString + it.valueParameters.isEmpty() && it.name == OperatorNameConventions.TO_STRING } private val defaultAppendFunction = stringBuilder.functions.single { @@ -82,52 +77,52 @@ private class StringConcatenationTransformer(val lower: StringConcatenationLower } override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression { - assert(!buildersStack.isEmpty()) - expression.transformChildrenVoid(this) - val blockBuilder = buildersStack.last() + builder.at(expression) val arguments = expression.arguments - return when (arguments.size) { - 0 -> blockBuilder.irString("") - 1 -> { + return when { + arguments.isEmpty() -> builder.irString("") + + arguments.size == 1 -> { val argument = arguments[0] if (argument.type.isNullable()) - blockBuilder.irCall(context.ir.symbols.extensionToString).apply { + builder.irCall(symbols.extensionToString).apply { extensionReceiver = argument } - else blockBuilder.irCall( - context.irBuiltIns.anyClass.functions - .single { it.owner.name.asString() == "toString" }).apply { + else builder.irCall( + irBuiltIns.anyClass.functions + .single { it.owner.name == OperatorNameConventions.TO_STRING }).apply { dispatchReceiver = argument } } - else -> { - blockBuilder.irBlock(expression) { - val stringBuilderImpl = createTmpVariable(irCall(constructor)) - expression.arguments.forEach { arg -> - val appendFunction = typeToAppendFunction(arg.type) - +irCall(appendFunction).apply { - dispatchReceiver = irGet(stringBuilderImpl) - putValueArgument(0, arg) - } + + arguments.size == 2 && arguments[0].type.isStringClassType() -> + if (arguments[0].type.isNullable()) + builder.irCall(symbols.stringPlus).apply { + extensionReceiver = arguments[0] + putValueArgument(0, arguments[1]) } - +irCall(toStringFunction).apply { + else + builder.irCall(symbols.string.functions + .single { it.owner.name == OperatorNameConventions.PLUS }).apply { + dispatchReceiver = arguments[0] + putValueArgument(0, arguments[1]) + } + + else -> builder.irBlock(expression) { + val stringBuilderImpl = createTmpVariable(irCall(constructor)) + expression.arguments.forEach { arg -> + val appendFunction = typeToAppendFunction(arg.type) + +irCall(appendFunction).apply { dispatchReceiver = irGet(stringBuilderImpl) + putValueArgument(0, arg) } } + +irCall(toStringFunction).apply { + dispatchReceiver = irGet(stringBuilderImpl) + } } } } - - override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement { - with(declaration) { - buildersStack.add( - context.createIrBuilder(declaration.symbol, startOffset, endOffset) - ) - transformChildrenVoid(this@StringConcatenationTransformer) - buildersStack.removeAt(buildersStack.lastIndex) - return this@with - } - } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt index e0bf3acf994..b9cab4544ff 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt @@ -2,6 +2,7 @@ package org.jetbrains.kotlin.backend.konan import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.lower.* +import org.jetbrains.kotlin.backend.common.lower.StringConcatenationLowering import org.jetbrains.kotlin.backend.common.lower.inline.FunctionInlining import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesExtractionFromInlineFunctionsLowering import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineFunctionsLowering @@ -14,7 +15,6 @@ import org.jetbrains.kotlin.backend.konan.ir.FunctionsWithoutBoundCheckGenerator import org.jetbrains.kotlin.backend.konan.lower.* import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering -import org.jetbrains.kotlin.backend.konan.lower.StringConcatenationLowering import org.jetbrains.kotlin.backend.konan.optimizations.KonanBCEForLoopBodyTransformer import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/StringConcatenationLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/StringConcatenationLowering.kt deleted file mode 100644 index c6a3380952e..00000000000 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/StringConcatenationLowering.kt +++ /dev/null @@ -1,114 +0,0 @@ -package org.jetbrains.kotlin.backend.konan.lower - -import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.common.atMostOne -import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer -import org.jetbrains.kotlin.backend.common.lower.at -import org.jetbrains.kotlin.backend.common.lower.irBlock -import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation -import org.jetbrains.kotlin.ir.types.* -import org.jetbrains.kotlin.ir.util.constructors -import org.jetbrains.kotlin.ir.util.functions -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.util.OperatorNameConventions - -/** - * This lowering pass replaces [IrStringConcatenation]s with StringBuilder appends. - */ -internal class StringConcatenationLowering(context: Context) : FileLoweringPass, IrBuildingTransformer(context) { - override fun lower(irFile: IrFile) { - irFile.transformChildrenVoid(this) - } - - private val irBuiltIns = context.irBuiltIns - private val symbols = context.ir.symbols - - private val typesWithSpecialAppendFunction = irBuiltIns.primitiveIrTypes + irBuiltIns.stringType - - private val nameToString = Name.identifier("toString") - private val nameAppend = Name.identifier("append") - - private val stringBuilder = context.ir.symbols.stringBuilder.owner - - //TODO: calculate and pass string length to the constructor. - private val constructor = stringBuilder.constructors.single { - it.valueParameters.isEmpty() - } - - private val toStringFunction = stringBuilder.functions.single { - it.valueParameters.isEmpty() && it.name == nameToString - } - - private val defaultAppendFunction = stringBuilder.functions.single { - it.name == nameAppend && - it.valueParameters.size == 1 && - it.valueParameters.single().type.isNullableAny() - } - - private val appendFunctions: Map = - typesWithSpecialAppendFunction.map { type -> - type to stringBuilder.functions.toList().atMostOne { - it.name == nameAppend && it.valueParameters.singleOrNull()?.type == type - } - }.toMap() - - private fun typeToAppendFunction(type: IrType): IrSimpleFunction { - return appendFunctions[type] ?: defaultAppendFunction - } - - override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression { - expression.transformChildrenVoid(this) - - builder.at(expression) - val arguments = expression.arguments - return when { - arguments.isEmpty() -> builder.irString("") - - arguments.size == 1 -> { - val argument = arguments[0] - if (argument.type.isNullable()) - builder.irCall(symbols.extensionToString).apply { - extensionReceiver = argument - } - else builder.irCall( - irBuiltIns.anyClass.functions - .single { it.owner.name.asString() == "toString" }).apply { - dispatchReceiver = argument - } - } - - arguments.size == 2 && arguments[0].type.isStringClassType() -> - if (arguments[0].type.isNullable()) - builder.irCall(symbols.stringPlus).apply { - extensionReceiver = arguments[0] - putValueArgument(0, arguments[1]) - } - else - builder.irCall(symbols.string.functions - .single { it.owner.name == OperatorNameConventions.PLUS }).apply { - dispatchReceiver = arguments[0] - putValueArgument(0, arguments[1]) - } - - else -> builder.irBlock(expression) { - val stringBuilderImpl = createTmpVariable(irCall(constructor)) - expression.arguments.forEach { arg -> - val appendFunction = typeToAppendFunction(arg.type) - +irCall(appendFunction).apply { - dispatchReceiver = irGet(stringBuilderImpl) - putValueArgument(0, arg) - } - } - +irCall(toStringFunction).apply { - dispatchReceiver = irGet(stringBuilderImpl) - } - } - } - } -}