Extracted compile time evaluation to a separate IR lowering
This commit is contained in:
+3
@@ -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)
|
||||
}
|
||||
|
||||
+1
@@ -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),
|
||||
|
||||
+2
@@ -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())
|
||||
|
||||
|
||||
+18
-43
@@ -1613,47 +1613,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
/**
|
||||
* Tries to evaluate given expression with given (already evaluated) arguments in compile time.
|
||||
* Returns `null` on failure.
|
||||
*/
|
||||
private fun compileTimeEvaluate(expression: IrMemberAccessExpression, args: List<LLVMValueRef>): 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<T>(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<out E>`, but `createArrayList` expects `Array<E>`;
|
||||
// however `vararg` is immutable, and in current implementation it has type `Array<E>`,
|
||||
// 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<IrE
|
||||
|
||||
val args = evaluateExplicitArgs(value)
|
||||
|
||||
compileTimeEvaluate(value, args)?.let { return it }
|
||||
|
||||
updateBuilderDebugLocation(value)
|
||||
when {
|
||||
value is IrDelegatingConstructorCall ->
|
||||
@@ -2128,6 +2085,24 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
functionGenerationContext.allocInstance(enumClassDescriptor, resultLifetime(callee))
|
||||
}
|
||||
|
||||
context.ir.symbols.listOfInternal.descriptor -> {
|
||||
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<out E>`, but `createArrayList` expects `Array<E>`;
|
||||
// however `vararg` is immutable, and in current implementation it has type `Array<E>`,
|
||||
// so let's ignore this mismatch currently for simplicity.
|
||||
|
||||
return context.llvm.staticData.createArrayList(elementType, array, length).llvm
|
||||
}
|
||||
|
||||
else -> TODO(callee.descriptor.original.toString())
|
||||
}
|
||||
}
|
||||
|
||||
+45
@@ -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<T>(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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -110,15 +110,10 @@ fun <T: Enum<T>> valuesForEnum(values: Array<T>): Array<T>
|
||||
}
|
||||
|
||||
@Intrinsic
|
||||
internal fun <T> createUninitializedInstance(): T {
|
||||
throw Exception("Call to this function should've been lowered")
|
||||
}
|
||||
internal external fun <T> 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 <T> listOfInternal(vararg elements: T): List<T> {
|
||||
val result = ArrayList<T>(elements.size)
|
||||
for (i in 0 until elements.size)
|
||||
result.add(elements[i])
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user