diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt index 9e9b935ca0b..346f2c1f4d8 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/CallGraphBuilder.kt @@ -111,7 +111,7 @@ internal class CallGraphBuilder( is DataFlowIR.Node.Call -> block(node) is DataFlowIR.Node.Singleton -> - node.constructor?.let { block(DataFlowIR.Node.Call(it, emptyList(), node.type, null)) } + node.constructor?.let { block(DataFlowIR.Node.Call(it, node.arguments ?: emptyList(), node.type, null)) } is DataFlowIR.Node.ArrayRead -> block(DataFlowIR.Node.Call( diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt index 19149a6d669..4c1310181cc 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt @@ -11,14 +11,9 @@ import org.jetbrains.kotlin.backend.common.ir.simpleFunctions import org.jetbrains.kotlin.backend.common.peek import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.push -import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.getInlinedClassNative -import org.jetbrains.kotlin.backend.konan.ir.actualCallee -import org.jetbrains.kotlin.backend.konan.ir.isAny -import org.jetbrains.kotlin.backend.konan.ir.isObjCObjectType -import org.jetbrains.kotlin.backend.konan.ir.isVirtualCall -import org.jetbrains.kotlin.backend.konan.logMultiple import org.jetbrains.kotlin.backend.konan.lower.erasedUpperBound +import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* @@ -127,17 +122,6 @@ private class ExpressionValuesExtractor(val context: Context, is IrWhen -> expression.branches.forEach { forEachValue(it.result, block) } - is IrMemberAccessExpression<*> -> block(expression) - - is IrGetValue -> block(expression) - - is IrGetField -> block(expression) - - is IrVararg -> /* Sometimes, we keep vararg till codegen phase (for constant arrays). */ - block(expression) - - is IrConst<*> -> block(expression) - is IrTypeOperatorCall -> { if (!expression.operator.isCast()) block(expression) @@ -155,11 +139,10 @@ private class ExpressionValuesExtractor(val context: Context, expression.catches.forEach { forEachValue(it.result, block) } } - is IrGetObjectValue -> block(expression) - - is IrFunctionReference -> block(expression) - - is IrSetField -> block(expression) + is IrVararg, /* Sometimes, we keep vararg till codegen phase (for constant arrays). */ + is IrMemberAccessExpression<*>, is IrGetValue, is IrGetField, is IrConst<*>, + is IrGetObjectValue, is IrFunctionReference, is IrSetField, + is IrConstantValue -> block(expression) else -> when { expression.type.isUnit() -> unit @@ -324,7 +307,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag is IrGetObjectValue, is IrVararg, is IrConst<*>, - is IrTypeOperatorCall -> + is IrTypeOperatorCall, + is IrConstantPrimitive -> expressions += expression to currentLoop } @@ -426,6 +410,36 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag super.visitVariable(declaration) declaration.initializer?.let { assignValue(declaration, it) } } + + override fun visitConstantArray(expression: IrConstantArray) { + super.visitConstantArray(expression) + expressions += expression to currentLoop + val arrayClass = expression.type.classOrNull + val arraySetSymbol = context.ir.symbols.arraySet[arrayClass] ?: error("Unexpected array type ${expression.type.render()}") + val isGeneric = arrayClass == context.irBuiltIns.arrayClass + expression.elements.forEachIndexed { index, value -> + val call = IrCallImpl( + expression.startOffset, expression.endOffset, + context.irBuiltIns.unitType, + arraySetSymbol, + typeArgumentsCount = if (isGeneric) 1 else 0, + valueArgumentsCount = 2 + ).apply { + dispatchReceiver = expression + if (isGeneric) putTypeArgument(0, value.type) + val constInt = IrConstImpl.int(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, context.irBuiltIns.intType, index) + expressions += constInt to currentLoop + putValueArgument(0, constInt) + putValueArgument(1, value) + } + expressions += call to currentLoop + } + } + + override fun visitConstantObject(expression: IrConstantObject) { + super.visitConstantObject(expression) + expressions += expression to currentLoop + } } private val symbols = context.ir.symbols @@ -585,17 +599,20 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag } } - private fun mapReturnType(actualType: IrType, returnType: IrType): DataFlowIR.Type { - val returnedInlinedClass = returnType.getInlinedClassNative() + private fun mapWrappedType(actualType: IrType, wrapperType: IrType): DataFlowIR.Type { + val wrapperInlinedClass = wrapperType.getInlinedClassNative() val actualInlinedClass = actualType.getInlinedClassNative() - return if (returnedInlinedClass == null) { + return if (wrapperInlinedClass == null) { if (actualInlinedClass == null) symbolTable.mapType(actualType) else symbolTable.mapClassReferenceType(actualInlinedClass) } else { - symbolTable.mapType(returnType) + symbolTable.mapType(wrapperType) } } + private fun mapReturnType(actualType: IrType, returnType: IrType) = mapWrappedType(actualType, returnType) + + private fun getNode(expression: IrExpression): Scoped { if (expression is IrGetValue) { val valueDeclaration = expression.symbol.owner @@ -664,6 +681,12 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag else DataFlowIR.Node.SimpleConst(symbolTable.mapType(value.type), value.value!!) + is IrConstantPrimitive -> + if (value.value.value == null) + DataFlowIR.Node.Null + else + DataFlowIR.Node.SimpleConst(mapWrappedType(value.value.type, value.type), value.value.value!!) + is IrGetObjectValue -> { val constructor = if (value.type.isNothing()) { // is not a singleton though its instance is get with operation. @@ -677,7 +700,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag symbolTable.mapFunction(objectClass.constructors.single()) } } - DataFlowIR.Node.Singleton(symbolTable.mapType(value.type), constructor) + DataFlowIR.Node.Singleton(symbolTable.mapType(value.type), constructor, emptyList()) } is IrConstructorCall -> { @@ -847,6 +870,15 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag DataFlowIR.Node.Const(symbolTable.mapType(value.type)) // All operators except casts are basically constants. } + is IrConstantArray -> + DataFlowIR.Node.Singleton(symbolTable.mapType(value.type), null, null) + is IrConstantObject -> + DataFlowIR.Node.Singleton( + symbolTable.mapType(value.type), + symbolTable.mapFunction(value.constructor.owner), + value.valueArguments.map { expressionToEdge(it) } + ) + else -> TODO("Unknown expression: ${ir2stringWhole(value)}") } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt index 906d88a124e..7ed1fac2d42 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt @@ -258,7 +258,7 @@ internal object DataFlowIR { arguments: List, returnType: Type, irCallSite: IrCall?) : VirtualCall(callee, arguments, receiverType, returnType, irCallSite) - class Singleton(val type: Type, val constructor: FunctionSymbol?) : Node() + class Singleton(val type: Type, val constructor: FunctionSymbol?, val arguments: List?) : Node() class AllocInstance(val type: Type, val irCallSite: IrCall?) : Node() diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DevirtualizationAnalysis.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DevirtualizationAnalysis.kt index d7c17fd719a..389e88121a1 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DevirtualizationAnalysis.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DevirtualizationAnalysis.kt @@ -1194,7 +1194,16 @@ internal object DevirtualizationAnalysis { val type = node.type.resolved() addInstantiatingClass(type) val instanceNode = concreteClass(type) - node.constructor?.let { doCall(it, listOf(instanceNode), type) } + node.constructor?.let { + doCall( + it, + @OptIn(ExperimentalStdlibApi::class) buildList { + add(instanceNode) + node.arguments?.forEach { add(edgeToConstraintNode(it)) } + }, + type + ) + } instanceNode }