[K/N] Support ConstantValue in global analyses
This commit is contained in:
+1
-1
@@ -111,7 +111,7 @@ internal class CallGraphBuilder(
|
|||||||
is DataFlowIR.Node.Call -> block(node)
|
is DataFlowIR.Node.Call -> block(node)
|
||||||
|
|
||||||
is DataFlowIR.Node.Singleton ->
|
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 ->
|
is DataFlowIR.Node.ArrayRead ->
|
||||||
block(DataFlowIR.Node.Call(
|
block(DataFlowIR.Node.Call(
|
||||||
|
|||||||
+61
-29
@@ -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.peek
|
||||||
import org.jetbrains.kotlin.backend.common.pop
|
import org.jetbrains.kotlin.backend.common.pop
|
||||||
import org.jetbrains.kotlin.backend.common.push
|
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.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.IrElement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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 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 -> {
|
is IrTypeOperatorCall -> {
|
||||||
if (!expression.operator.isCast())
|
if (!expression.operator.isCast())
|
||||||
block(expression)
|
block(expression)
|
||||||
@@ -155,11 +139,10 @@ private class ExpressionValuesExtractor(val context: Context,
|
|||||||
expression.catches.forEach { forEachValue(it.result, block) }
|
expression.catches.forEach { forEachValue(it.result, block) }
|
||||||
}
|
}
|
||||||
|
|
||||||
is IrGetObjectValue -> block(expression)
|
is IrVararg, /* Sometimes, we keep vararg till codegen phase (for constant arrays). */
|
||||||
|
is IrMemberAccessExpression<*>, is IrGetValue, is IrGetField, is IrConst<*>,
|
||||||
is IrFunctionReference -> block(expression)
|
is IrGetObjectValue, is IrFunctionReference, is IrSetField,
|
||||||
|
is IrConstantValue -> block(expression)
|
||||||
is IrSetField -> block(expression)
|
|
||||||
|
|
||||||
else -> when {
|
else -> when {
|
||||||
expression.type.isUnit() -> unit
|
expression.type.isUnit() -> unit
|
||||||
@@ -324,7 +307,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
|||||||
is IrGetObjectValue,
|
is IrGetObjectValue,
|
||||||
is IrVararg,
|
is IrVararg,
|
||||||
is IrConst<*>,
|
is IrConst<*>,
|
||||||
is IrTypeOperatorCall ->
|
is IrTypeOperatorCall,
|
||||||
|
is IrConstantPrimitive ->
|
||||||
expressions += expression to currentLoop
|
expressions += expression to currentLoop
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,6 +410,36 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
|||||||
super.visitVariable(declaration)
|
super.visitVariable(declaration)
|
||||||
declaration.initializer?.let { assignValue(declaration, it) }
|
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
|
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 {
|
private fun mapWrappedType(actualType: IrType, wrapperType: IrType): DataFlowIR.Type {
|
||||||
val returnedInlinedClass = returnType.getInlinedClassNative()
|
val wrapperInlinedClass = wrapperType.getInlinedClassNative()
|
||||||
val actualInlinedClass = actualType.getInlinedClassNative()
|
val actualInlinedClass = actualType.getInlinedClassNative()
|
||||||
|
|
||||||
return if (returnedInlinedClass == null) {
|
return if (wrapperInlinedClass == null) {
|
||||||
if (actualInlinedClass == null) symbolTable.mapType(actualType) else symbolTable.mapClassReferenceType(actualInlinedClass)
|
if (actualInlinedClass == null) symbolTable.mapType(actualType) else symbolTable.mapClassReferenceType(actualInlinedClass)
|
||||||
} else {
|
} 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> {
|
private fun getNode(expression: IrExpression): Scoped<DataFlowIR.Node> {
|
||||||
if (expression is IrGetValue) {
|
if (expression is IrGetValue) {
|
||||||
val valueDeclaration = expression.symbol.owner
|
val valueDeclaration = expression.symbol.owner
|
||||||
@@ -664,6 +681,12 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
|
|||||||
else
|
else
|
||||||
DataFlowIR.Node.SimpleConst(symbolTable.mapType(value.type), value.value!!)
|
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 -> {
|
is IrGetObjectValue -> {
|
||||||
val constructor = if (value.type.isNothing()) {
|
val constructor = if (value.type.isNothing()) {
|
||||||
// <Nothing> is not a singleton though its instance is get with <IrGetObject> operation.
|
// <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())
|
symbolTable.mapFunction(objectClass.constructors.single())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataFlowIR.Node.Singleton(symbolTable.mapType(value.type), constructor)
|
DataFlowIR.Node.Singleton(symbolTable.mapType(value.type), constructor, emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
is IrConstructorCall -> {
|
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.
|
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)}")
|
else -> TODO("Unknown expression: ${ir2stringWhole(value)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -258,7 +258,7 @@ internal object DataFlowIR {
|
|||||||
arguments: List<Edge>, returnType: Type, irCallSite: IrCall?)
|
arguments: List<Edge>, returnType: Type, irCallSite: IrCall?)
|
||||||
: VirtualCall(callee, arguments, receiverType, returnType, irCallSite)
|
: 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()
|
class AllocInstance(val type: Type, val irCallSite: IrCall?) : Node()
|
||||||
|
|
||||||
|
|||||||
+10
-1
@@ -1194,7 +1194,16 @@ internal object DevirtualizationAnalysis {
|
|||||||
val type = node.type.resolved()
|
val type = node.type.resolved()
|
||||||
addInstantiatingClass(type)
|
addInstantiatingClass(type)
|
||||||
val instanceNode = concreteClass(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
|
instanceNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user