backend: String concatenation lowering

This commit is contained in:
Ilya Matveev
2017-02-02 14:49:06 +03:00
committed by ilmat192
parent f251bd2b61
commit 51a63222b9
5 changed files with 117 additions and 4 deletions
@@ -17,6 +17,10 @@ internal class KonanLower(val context: Context) {
fun lower(irFile: IrFile) {
val phaser = PhaseManager(context)
// TODO: consider place of the pass.
phaser.phase(KonanPhase.LOWER_STRING_CONCAT) {
StringConcatenationLowering(context).lower(irFile)
}
phaser.phase(KonanPhase.LOWER_INLINE) {
//FunctionInlining(context).inline(irFile)
}
@@ -22,6 +22,7 @@ enum class KonanPhase(val description: String,
/* ... ... */ AUTOBOX("Autoboxing of primitive types"),
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering"),
/* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"),
/* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ CODEGEN("Code Generation"),
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.backend.konan.KonanPlatformConfigurator
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.PlatformConfigurator
@@ -31,7 +32,6 @@ class KonanBuiltIns: KotlinBuiltIns {
constructor(storageManager: StorageManager, withModule: Boolean) : this(storageManager) {
if (withModule) createBuiltInsModule()
}
}
object KonanPlatform : TargetPlatform("Konan") {
@@ -3,12 +3,18 @@ package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.types.KotlinType
inline fun IrBlockBuilder.irLetSequence(
inline fun IrBuilderWithScope.irLetSequence(
value: IrExpression,
nameHint: String? = null,
startOffset: Int = this.startOffset,
endOffset: Int = this.endOffset,
origin: IrStatementOrigin? = null,
resultType: KotlinType? = null,
body: IrBlockBuilder.(VariableDescriptor) -> Unit
): IrExpression = block {
): IrExpression = irBlock(startOffset, endOffset, origin, resultType) {
val irTemporary = defineTemporary(value, nameHint)
this.body(irTemporary)
}
}
@@ -0,0 +1,102 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.signature2Descriptor
import org.jetbrains.kotlin.backend.konan.ir.irLetSequence
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
/**
* This lowering pass replaces [IrStringConcatenation]s with StringBuilder appends.
*/
internal class StringConcatenationLowering(val context: Context) : FileLoweringPass {
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(StringConcatenationTransformer(this))
}
}
private class StringConcatenationTransformer(val lower: StringConcatenationLowering) : IrElementTransformerVoid() {
private val buildersStack = mutableListOf<IrBuilderWithScope>()
private val context = lower.context
private val builtIns = context.builtIns
private val typesWithSpecialAppendFunction =
PrimitiveType.values().map { builtIns.getPrimitiveKotlinType(it) } + builtIns.stringType
private val kotlinTextFqName = FqName.fromSegments(listOf("kotlin", "text"))
private val nameToString = Name.identifier("toString")
private val nameStringBuilder = Name.identifier("StringBuilder")
private val nameAppend = Name.identifier("append")
private val classStringBuilder = builtIns.builtInsModule.getPackage(kotlinTextFqName).
memberScope.getContributedClassifier(nameStringBuilder,
NoLookupLocation.FROM_BACKEND) as ClassDescriptor
//TODO: calculate and pass string length to the constructor.
private val constructor = classStringBuilder.constructors.firstOrNull {
it.valueParameters.size == 0
}!!
private val toStringFunction = classStringBuilder.signature2Descriptor(nameToString)!!
private val defaultAppendFunction =
classStringBuilder.signature2Descriptor(nameAppend, arrayOf(builtIns.nullableAnyType))!!
private val appendFunctions: Map<KotlinType, CallableDescriptor?> =
typesWithSpecialAppendFunction.map {
it to classStringBuilder.signature2Descriptor(nameAppend, arrayOf(it))
}.toMap()
private fun typeToAppendFunction(type : KotlinType) : CallableDescriptor {
return appendFunctions[type]?:defaultAppendFunction
}
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression {
assert(!buildersStack.isEmpty())
val blockBuilder = buildersStack.last()
return blockBuilder.irLetSequence(
value = blockBuilder.irCall(constructor),
startOffset = expression.startOffset,
endOffset = expression.endOffset,
resultType = expression.type) { stringBuilderImpl ->
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: IrDeclaration): IrStatement {
with(declaration) {
buildersStack.add(
IrBlockBuilder(IrGeneratorContext(context.irBuiltIns), Scope(descriptor), startOffset, endOffset)
)
transformChildrenVoid(this@StringConcatenationTransformer)
buildersStack.removeAt(buildersStack.lastIndex)
return this@with
}
}
}