From 6682d8083b22709686d568a39241140b51c93b40 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Wed, 14 Feb 2018 19:09:01 +0300 Subject: [PATCH] Extracted compile time evaluation to a separate IR lowering --- .../kotlin/backend/konan/KonanLower.kt | 3 + .../kotlin/backend/konan/KonanPhases.kt | 1 + .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 2 + .../kotlin/backend/konan/llvm/IrToBitcode.kt | 61 ++++++------------- .../lower/CompileTimeEvaluateLowering.kt | 45 ++++++++++++++ .../kotlin/konan/internal/RuntimeUtils.kt | 18 +++--- 6 files changed, 80 insertions(+), 50 deletions(-) create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CompileTimeEvaluateLowering.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index a7225c220f7..aa47bcd6bdf 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -134,6 +134,9 @@ internal class KonanLower(val context: Context) { phaser.phase(KonanPhase.LOWER_VARARG) { VarargInjectionLowering(context).runOnFilePostfix(irFile) } + phaser.phase(KonanPhase.LOWER_COMPILE_TIME_EVAL) { + CompileTimeEvaluateLowering(context).lower(irFile) + } phaser.phase(KonanPhase.LOWER_COROUTINES) { SuspendFunctionsLowering(context).runOnFilePostfix(irFile) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index 4a666636958..f74cfbcd730 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -47,6 +47,7 @@ enum class KonanPhase(val description: String, /* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", LOWER_SHARED_VARIABLES, LOWER_CALLABLES), /* ... ... */ LOWER_INTEROP_PART2("Interop lowering, part 2", LOWER_LOCAL_FUNCTIONS), /* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES), + /* ... ... */ LOWER_COMPILE_TIME_EVAL("Compile time evaluation lowering", LOWER_VARARG), /* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS), /* ... ... */ LOWER_FINALLY("Finally blocks lowering", LOWER_INITIALIZERS, LOWER_LOCAL_FUNCTIONS, LOWER_TAILREC), /* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", LOWER_TAILREC, LOWER_ENUMS), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index b6775e26c3e..d9eab52cde3 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -206,6 +206,8 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym val kClassImpl = internalClass("KClassImpl") val kClassImplConstructor by lazy { kClassImpl.constructors.single() } + val listOfInternal = internalFunction("listOfInternal") + private fun internalFunction(name: String): IrSimpleFunctionSymbol = symbolTable.referenceSimpleFunction(context.getInternalFunctions(name).single()) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 5adef42bb57..9718093debf 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1613,47 +1613,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map): LLVMValueRef? { - if (!args.all { it.isConst }) { - return null - } - - val function = expression.descriptor - - if (function.fqNameSafe.asString() == "kotlin.collections.listOf" && function.valueParameters.size == 1) { - val varargExpression = expression.getValueArgument(0) as? IrVararg - - if (varargExpression != null) { - // The function is kotlin.collections.listOf(vararg args: T). - // TODO: refer functions more reliably. - - val vararg = args.single() - - if (varargExpression.elements.any { it is IrSpreadElement }) { - return null // not supported yet, see `length` calculation below. - } - val length = varargExpression.elements.size - // TODO: store length in `vararg` itself when more abstract types will be used for values. - - // `elementType` is type argument of function return type: - val elementType = function.returnType!!.arguments.single() - - val array = constPointer(vararg) - // Note: dirty hack here: `vararg` has type `Array`, but `createArrayList` expects `Array`; - // however `vararg` is immutable, and in current implementation it has type `Array`, - // so let's ignore this mismatch currently for simplicity. - - return context.llvm.staticData.createArrayList(elementType, array, length).llvm - } - } - - return null - } - private fun evaluateSpecialIntrinsicCall(expression: IrFunctionAccessExpression): LLVMValueRef? { if (expression.descriptor.isIntrinsic) { when (expression.descriptor.original) { @@ -1694,8 +1653,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map @@ -2128,6 +2085,24 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map { + val varargExpression = callee.getValueArgument(0) as IrVararg + val vararg = args.single() + + val length = varargExpression.elements.size + // TODO: store length in `vararg` itself when more abstract types will be used for values. + + // `elementType` is type argument of function return type: + val elementType = callee.descriptor.returnType!!.arguments.single() + + val array = constPointer(vararg) + // Note: dirty hack here: `vararg` has type `Array`, but `createArrayList` expects `Array`; + // however `vararg` is immutable, and in current implementation it has type `Array`, + // so let's ignore this mismatch currently for simplicity. + + return context.llvm.staticData.createArrayList(elementType, array, length).llvm + } + else -> TODO(callee.descriptor.original.toString()) } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CompileTimeEvaluateLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CompileTimeEvaluateLowering.kt new file mode 100644 index 00000000000..5c4cbf57f5d --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CompileTimeEvaluateLowering.kt @@ -0,0 +1,45 @@ +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer +import org.jetbrains.kotlin.backend.common.lower.at +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.ir.builders.irCall +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe + +internal class CompileTimeEvaluateLowering(val context: Context): FileLoweringPass { + + override fun lower(irFile: IrFile) { + irFile.transformChildrenVoid(object: IrBuildingTransformer(context) { + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + + val descriptor = expression.descriptor.original + // TODO + if (descriptor.fqNameSafe.asString() != "kotlin.collections.listOf" || descriptor.valueParameters.size != 1) + return expression + val elementsArr = expression.getValueArgument(0) as? IrVararg + ?: return expression + + // The function is kotlin.collections.listOf(vararg args: T). + // TODO: refer functions more reliably. + + if (elementsArr.elements.any { it is IrSpreadElement } + || !elementsArr.elements.all { it is IrConst<*> && KotlinBuiltIns.isString(it.type) }) + return expression + + + builder.at(expression) + + val typeArguments = descriptor.typeParameters.map { expression.getTypeArgument(it)!! } + return builder.irCall(context.ir.symbols.listOfInternal, typeArguments).apply { + putValueArgument(0, elementsArr) + } + } + }) + } +} \ No newline at end of file diff --git a/runtime/src/main/kotlin/konan/internal/RuntimeUtils.kt b/runtime/src/main/kotlin/konan/internal/RuntimeUtils.kt index 43685092dc7..1b49fb69a0f 100644 --- a/runtime/src/main/kotlin/konan/internal/RuntimeUtils.kt +++ b/runtime/src/main/kotlin/konan/internal/RuntimeUtils.kt @@ -110,15 +110,10 @@ fun > valuesForEnum(values: Array): Array } @Intrinsic -internal fun createUninitializedInstance(): T { - throw Exception("Call to this function should've been lowered") -} +internal external fun createUninitializedInstance(): T @Intrinsic -@Suppress("UNUSED_PARAMETER") -internal fun initInstance(thiz: Any, constructorCall: Any): Unit { - throw Exception("Call to this function should've been lowered") -} +internal external fun initInstance(thiz: Any, constructorCall: Any): Unit fun checkProgressionStep(step: Int) = if (step > 0) step else throw IllegalArgumentException("Step must be positive, was: $step.") fun checkProgressionStep(step: Long) = if (step > 0) step else throw IllegalArgumentException("Step must be positive, was: $step.") @@ -146,3 +141,12 @@ fun KonanObjectToUtf8Array(value: Any?): ByteArray { } return string.toUtf8() } + +@Intrinsic +@PublishedApi +internal fun listOfInternal(vararg elements: T): List { + val result = ArrayList(elements.size) + for (i in 0 until elements.size) + result.add(elements[i]) + return result +} \ No newline at end of file