Implemented devirtualization of monomorphic callsites
This commit is contained in:
+2
-2
@@ -31,8 +31,8 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
@@ -258,4 +258,4 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
|
|||||||
kind.runtimeKindName, NoLookupLocation.FROM_BACKEND
|
kind.runtimeKindName, NoLookupLocation.FROM_BACKEND
|
||||||
) as ClassDescriptor)
|
) as ClassDescriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+34
-1
@@ -16,16 +16,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan.ir
|
package org.jetbrains.kotlin.backend.konan.ir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.ir.SourceManager
|
import org.jetbrains.kotlin.ir.SourceManager
|
||||||
import org.jetbrains.kotlin.ir.SourceRangeInfo
|
import org.jetbrains.kotlin.ir.SourceRangeInfo
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallWithIndexedArgumentsBase
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase
|
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.konan.file.File
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
@@ -177,3 +181,32 @@ class IrSuspendableExpressionImpl(startOffset: Int, endOffset: Int, type: Kotlin
|
|||||||
result = result.transform(transformer, data)
|
result = result.transform(transformer, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal interface IrPrivateFunctionCall : IrCall {
|
||||||
|
val moduleDescriptor: ModuleDescriptor
|
||||||
|
val totalFunctions: Int
|
||||||
|
val functionIndex: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class IrPrivateFunctionCallImpl(startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType,
|
||||||
|
override val symbol: IrFunctionSymbol,
|
||||||
|
override val descriptor: FunctionDescriptor,
|
||||||
|
typeArguments: Map<TypeParameterDescriptor, KotlinType>?,
|
||||||
|
override val moduleDescriptor: ModuleDescriptor,
|
||||||
|
override val totalFunctions: Int,
|
||||||
|
override val functionIndex: Int
|
||||||
|
) : IrPrivateFunctionCall,
|
||||||
|
IrCallWithIndexedArgumentsBase(startOffset, endOffset, type, symbol.descriptor.valueParameters.size, typeArguments) {
|
||||||
|
|
||||||
|
override val superQualifierSymbol: IrClassSymbol?
|
||||||
|
get() = null
|
||||||
|
|
||||||
|
override val superQualifier: ClassDescriptor?
|
||||||
|
get() = null
|
||||||
|
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
|
visitor.visitCall(this, data)
|
||||||
|
|
||||||
|
}
|
||||||
+2
@@ -272,3 +272,5 @@ internal val ClassDescriptor.objectInstanceFieldSymbolName: String
|
|||||||
|
|
||||||
internal val ClassDescriptor.typeInfoHasVtableAttached: Boolean
|
internal val ClassDescriptor.typeInfoHasVtableAttached: Boolean
|
||||||
get() = !this.isAbstract() && !this.isExternalObjCClass()
|
get() = !this.isAbstract() && !this.isExternalObjCClass()
|
||||||
|
|
||||||
|
internal val ModuleDescriptor.privateFunctionsTableSymbolName get() = "private_functions_${name.asString()}"
|
||||||
|
|||||||
+36
-6
@@ -79,9 +79,8 @@ internal fun emitLLVM(context: Context) {
|
|||||||
moduleDFG = ModuleDFGBuilder(context, irModule).build()
|
moduleDFG = ModuleDFGBuilder(context, irModule).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
phaser.phase(KonanPhase.SERIALIZE_DFG) {
|
val lifetimes = mutableMapOf<IrElement, Lifetime>()
|
||||||
DFGSerializer.serialize(context, moduleDFG!!)
|
val codegenVisitor = CodeGeneratorVisitor(context, lifetimes)
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||||
var externalModulesDFG: ExternalModulesDFG? = null
|
var externalModulesDFG: ExternalModulesDFG? = null
|
||||||
@@ -89,12 +88,17 @@ internal fun emitLLVM(context: Context) {
|
|||||||
externalModulesDFG = DFGSerializer.deserialize(context, moduleDFG!!.symbolTable.privateTypeIndex, moduleDFG!!.symbolTable.privateFunIndex)
|
externalModulesDFG = DFGSerializer.deserialize(context, moduleDFG!!.symbolTable.privateTypeIndex, moduleDFG!!.symbolTable.privateFunIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
val lifetimes = mutableMapOf<IrElement, Lifetime>()
|
|
||||||
val codegenVisitor = CodeGeneratorVisitor(context, lifetimes)
|
|
||||||
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
|
||||||
var devirtualizationAnalysisResult: Map<DataFlowIR.Node.VirtualCall, Devirtualization.DevirtualizedCallSite>? = null
|
var devirtualizationAnalysisResult: Map<DataFlowIR.Node.VirtualCall, Devirtualization.DevirtualizedCallSite>? = null
|
||||||
phaser.phase(KonanPhase.DEVIRTUALIZATION) {
|
phaser.phase(KonanPhase.DEVIRTUALIZATION) {
|
||||||
devirtualizationAnalysisResult = Devirtualization.analyze(context, moduleDFG!!, externalModulesDFG!!)
|
devirtualizationAnalysisResult = Devirtualization.run(irModule, context, moduleDFG!!, externalModulesDFG!!)
|
||||||
|
|
||||||
|
val privateFunctions = moduleDFG!!.symbolTable.getPrivateFunctionsTableForExport()
|
||||||
|
|
||||||
|
codegenVisitor.codegen.staticData.placeGlobalConstArray(irModule.descriptor.privateFunctionsTableSymbolName, int8TypePtr,
|
||||||
|
privateFunctions.map { constPointer(codegenVisitor.codegen.functionLlvmValue(it)).bitcast(int8TypePtr) },
|
||||||
|
isExported = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
phaser.phase(KonanPhase.ESCAPE_ANALYSIS) {
|
phaser.phase(KonanPhase.ESCAPE_ANALYSIS) {
|
||||||
@@ -102,6 +106,10 @@ internal fun emitLLVM(context: Context) {
|
|||||||
EscapeAnalysis.computeLifetimes(moduleDFG!!, externalModulesDFG!!, callGraph, lifetimes)
|
EscapeAnalysis.computeLifetimes(moduleDFG!!, externalModulesDFG!!, callGraph, lifetimes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
phaser.phase(KonanPhase.SERIALIZE_DFG) {
|
||||||
|
DFGSerializer.serialize(context, moduleDFG!!)
|
||||||
|
}
|
||||||
|
|
||||||
phaser.phase(KonanPhase.CODEGEN) {
|
phaser.phase(KonanPhase.CODEGEN) {
|
||||||
irModule.acceptVoid(codegenVisitor)
|
irModule.acceptVoid(codegenVisitor)
|
||||||
}
|
}
|
||||||
@@ -1945,6 +1953,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
return evaluateIntrinsicCall(callee, argsWithContinuationIfNeeded)
|
return evaluateIntrinsicCall(callee, argsWithContinuationIfNeeded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (callee is IrPrivateFunctionCall)
|
||||||
|
return evaluatePrivateFunctionCall(callee, argsWithContinuationIfNeeded, resultLifetime)
|
||||||
|
|
||||||
when (descriptor) {
|
when (descriptor) {
|
||||||
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (callee, argsWithContinuationIfNeeded)
|
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (callee, argsWithContinuationIfNeeded)
|
||||||
is ConstructorDescriptor -> return evaluateConstructorCall (callee, argsWithContinuationIfNeeded)
|
is ConstructorDescriptor -> return evaluateConstructorCall (callee, argsWithContinuationIfNeeded)
|
||||||
@@ -1955,6 +1966,25 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun evaluatePrivateFunctionCall(callee: IrPrivateFunctionCall, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef {
|
||||||
|
val functionsListName = callee.moduleDescriptor.privateFunctionsTableSymbolName
|
||||||
|
// LLVM inlines access to this global array (with -opt option on).
|
||||||
|
val functionsList =
|
||||||
|
if (callee.moduleDescriptor == context.irModule!!.descriptor)
|
||||||
|
LLVMGetNamedGlobal(context.llvmModule, functionsListName)
|
||||||
|
else
|
||||||
|
codegen.importGlobal(functionsListName, LLVMArrayType(int8TypePtr, callee.totalFunctions)!!, callee.moduleDescriptor.llvmSymbolOrigin)
|
||||||
|
val functionIndex = Int32(callee.functionIndex).llvm
|
||||||
|
val functionPlacePtr = LLVMBuildGEP(functionGenerationContext.builder, functionsList, cValuesOf(kImmZero, functionIndex), 2, "")!!
|
||||||
|
val functionPtr = functionGenerationContext.load(functionPlacePtr)
|
||||||
|
|
||||||
|
val functionPtrType = pointerType(codegen.getLlvmFunctionType(callee.descriptor))
|
||||||
|
val function = functionGenerationContext.bitcast(functionPtrType, functionPtr)
|
||||||
|
return call(callee.descriptor, function, args, resultLifetime)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun evaluateSimpleFunctionCall(
|
private fun evaluateSimpleFunctionCall(
|
||||||
descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
|
descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
|
||||||
resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef {
|
resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef {
|
||||||
|
|||||||
+2
-2
@@ -162,9 +162,9 @@ internal class StaticData(override val context: Context): ContextUtils {
|
|||||||
/**
|
/**
|
||||||
* Creates array-typed global with given name and value.
|
* Creates array-typed global with given name and value.
|
||||||
*/
|
*/
|
||||||
fun placeGlobalArray(name: String, elemType: LLVMTypeRef?, elements: List<ConstValue>): Global {
|
fun placeGlobalArray(name: String, elemType: LLVMTypeRef?, elements: List<ConstValue>, isExported: Boolean = false): Global {
|
||||||
val initializer = ConstArray(elemType, elements)
|
val initializer = ConstArray(elemType, elements)
|
||||||
val global = placeGlobal(name, initializer)
|
val global = placeGlobal(name, initializer, isExported)
|
||||||
|
|
||||||
return global
|
return global
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -27,9 +27,10 @@ import llvm.*
|
|||||||
*/
|
*/
|
||||||
internal fun StaticData.placeGlobalConstArray(name: String,
|
internal fun StaticData.placeGlobalConstArray(name: String,
|
||||||
elemType: LLVMTypeRef,
|
elemType: LLVMTypeRef,
|
||||||
elements: List<ConstValue>): ConstPointer {
|
elements: List<ConstValue>,
|
||||||
if (elements.isNotEmpty()) {
|
isExported: Boolean = false): ConstPointer {
|
||||||
val global = this.placeGlobalArray(name, elemType, elements)
|
if (elements.isNotEmpty() || isExported) {
|
||||||
|
val global = this.placeGlobalArray(name, elemType, elements, isExported)
|
||||||
global.setConstant(true)
|
global.setConstant(true)
|
||||||
return global.pointer.getElementPtr(0)
|
return global.pointer.getElementPtr(0)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+54
-2
@@ -16,11 +16,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan.optimizations
|
package org.jetbrains.kotlin.backend.konan.optimizations
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
|
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
|
||||||
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.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.konan.*
|
import org.jetbrains.kotlin.backend.konan.*
|
||||||
|
import org.jetbrains.kotlin.backend.konan.ir.IrPrivateFunctionCallImpl
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.getValueArgument
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
// TODO: Exceptions.
|
// TODO: Exceptions.
|
||||||
@@ -845,8 +854,51 @@ internal object Devirtualization {
|
|||||||
|
|
||||||
class DevirtualizedCallSite(val possibleCallees: List<DevirtualizedCallee>)
|
class DevirtualizedCallSite(val possibleCallees: List<DevirtualizedCallee>)
|
||||||
|
|
||||||
fun analyze(context: Context, moduleDFG: ModuleDFG, externalModulesDFG: ExternalModulesDFG)
|
fun run(irModule: IrModuleFragment, context: Context, moduleDFG: ModuleDFG, externalModulesDFG: ExternalModulesDFG)
|
||||||
: Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite> {
|
: Map<DataFlowIR.Node.VirtualCall, DevirtualizedCallSite> {
|
||||||
return DevirtualizationAnalysis(context, moduleDFG, externalModulesDFG).analyze()
|
val devirtualizationAnalysisResult = DevirtualizationAnalysis(context, moduleDFG, externalModulesDFG).analyze()
|
||||||
|
val devirtualizedCallSites =
|
||||||
|
devirtualizationAnalysisResult
|
||||||
|
.asSequence()
|
||||||
|
.filter { it.key.callSite != null }
|
||||||
|
.associate { it.key.callSite!! to it.value }
|
||||||
|
Devirtualization.devirtualize(irModule, context, devirtualizedCallSites)
|
||||||
|
return devirtualizationAnalysisResult
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun devirtualize(irModule: IrModuleFragment, context: Context,
|
||||||
|
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
|
||||||
|
irModule.transformChildrenVoid(object: IrElementTransformerVoidWithContext() {
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
|
val devirtualizedCallSite = devirtualizedCallSites[expression]
|
||||||
|
val actualCallee = devirtualizedCallSite?.possibleCallees?.singleOrNull()?.callee as? DataFlowIR.FunctionSymbol.Declared
|
||||||
|
?: return expression
|
||||||
|
val startOffset = expression.startOffset
|
||||||
|
val endOffset = expression.endOffset
|
||||||
|
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset)
|
||||||
|
irBuilder.run {
|
||||||
|
val dispatchReceiver = expression.dispatchReceiver!!
|
||||||
|
return IrPrivateFunctionCallImpl(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
expression.type,
|
||||||
|
expression.symbol,
|
||||||
|
expression.descriptor,
|
||||||
|
(expression as? IrCallImpl)?.typeArguments,
|
||||||
|
actualCallee.module.descriptor,
|
||||||
|
actualCallee.module.numberOfFunctions,
|
||||||
|
actualCallee.symbolTableIndex
|
||||||
|
).apply {
|
||||||
|
this.dispatchReceiver = dispatchReceiver
|
||||||
|
this.extensionReceiver = expression.extensionReceiver
|
||||||
|
expression.descriptor.valueParameters.forEach {
|
||||||
|
this.putValueArgument(it.index, expression.getValueArgument(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user