[K/N] Support ConstantValue in global analyses

This commit is contained in:
Pavel Kunyavskiy
2021-07-15 15:46:46 +03:00
committed by Space
parent 434d4d2d83
commit 7a0f72105f
4 changed files with 73 additions and 32 deletions
@@ -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(
@@ -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<DataFlowIR.Node> {
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()) {
// <Nothing> is not a singleton though its instance is get with <IrGetObject> 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)}")
}
}
@@ -258,7 +258,7 @@ internal object DataFlowIR {
arguments: List<Edge>, 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<Edge>?) : Node()
class AllocInstance(val type: Type, val irCallSite: IrCall?) : Node()
@@ -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
}