+1
-1
@@ -22,7 +22,7 @@ internal class KonanLower(val context: Context) {
|
|||||||
StringConcatenationLowering(context).lower(irFile)
|
StringConcatenationLowering(context).lower(irFile)
|
||||||
}
|
}
|
||||||
phaser.phase(KonanPhase.LOWER_INLINE) {
|
phaser.phase(KonanPhase.LOWER_INLINE) {
|
||||||
//FunctionInlining(context).inline(irFile)
|
FunctionInlining(context).inline(irFile)
|
||||||
}
|
}
|
||||||
phaser.phase(KonanPhase.LOWER_ENUMS) {
|
phaser.phase(KonanPhase.LOWER_ENUMS) {
|
||||||
EnumClassLowering(context).run(irFile)
|
EnumClassLowering(context).run(irFile)
|
||||||
|
|||||||
+4
-3
@@ -238,7 +238,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
override fun visitModuleFragment(module: IrModuleFragment) {
|
override fun visitModuleFragment(module: IrModuleFragment) {
|
||||||
context.log("visitModule : ${ir2string(module)}")
|
context.log("visitModule : ${ir2string(module)}")
|
||||||
|
|
||||||
computeLifetimes(module, this.codegen, resultLifetimes)
|
// computeLifetimes(module, this.codegen, resultLifetimes)
|
||||||
|
|
||||||
module.acceptChildrenVoid(this)
|
module.acceptChildrenVoid(this)
|
||||||
appendLlvmUsed(context.llvm.usedFunctions)
|
appendLlvmUsed(context.llvm.usedFunctions)
|
||||||
@@ -489,8 +489,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
context.log("visitFunction : ${ir2string(declaration)}")
|
context.log("visitFunction : ${ir2string(declaration)}")
|
||||||
val body = declaration.body
|
val body = declaration.body
|
||||||
|
|
||||||
if (declaration.descriptor.modality == Modality.ABSTRACT || declaration.descriptor.isExternal || body == null)
|
if (declaration.descriptor.modality == Modality.ABSTRACT) return
|
||||||
return
|
if (declaration.descriptor.isExternal) return
|
||||||
|
if (body == null) return
|
||||||
|
|
||||||
codegen.prologue(declaration.descriptor)
|
codegen.prologue(declaration.descriptor)
|
||||||
|
|
||||||
|
|||||||
+135
-71
@@ -6,6 +6,7 @@ import org.jetbrains.kotlin.backend.konan.ir.IrInlineFunctionBody
|
|||||||
import org.jetbrains.kotlin.backend.konan.ir.getArguments
|
import org.jetbrains.kotlin.backend.konan.ir.getArguments
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.Scope
|
import org.jetbrains.kotlin.ir.builders.Scope
|
||||||
@@ -14,10 +15,13 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
|
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrMemberAccessExpressionBase
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
|
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
internal class FunctionInlining(val context: Context): IrElementTransformerVoid() {
|
internal class FunctionInlining(val context: Context): IrElementTransformerVoid() {
|
||||||
@@ -26,9 +30,90 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun isLambda(value: IrExpression) : Boolean {
|
fun isLambdaExpression(expression: IrExpression) : Boolean {
|
||||||
if (value !is IrContainerExpressionBase) return false
|
if (expression !is IrContainerExpressionBase) return false
|
||||||
if (value.origin != IrStatementOrigin.LAMBDA) return false
|
if (expression.origin != IrStatementOrigin.LAMBDA) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun evaluateParameters(irCall: IrCall,
|
||||||
|
statements: MutableList<IrStatement>): List<Pair<ParameterDescriptor, IrExpression>> {
|
||||||
|
|
||||||
|
val scope = Scope(irCall.descriptor as FunctionDescriptor)
|
||||||
|
val parametersOld = irCall.getArguments() // Create map call_site_argument -> inline_function_parameter.
|
||||||
|
val parametersNew = parametersOld.map {
|
||||||
|
val argument = it.first
|
||||||
|
val parameter = it.second
|
||||||
|
if (parameter is IrGetValue) return@map it // Parameter is already GetValue - nothing to evaluate.
|
||||||
|
if (parameter is IrConst<*>) return@map it // Parameter is constant - nothing to evaluate.
|
||||||
|
if (isLambdaExpression(parameter)) return@map it // Parameter is lambda - will be inlined.
|
||||||
|
|
||||||
|
val newVar = scope.createTemporaryVariable(parameter, "inline", false) // Create new variable and init it with the parameter expression.
|
||||||
|
statements.add(0, newVar) // Add initialization of the new variable in statement list.
|
||||||
|
|
||||||
|
val getVal = IrGetValueImpl(0, 0, newVar.descriptor) // Create new IR element representing access the new variable.
|
||||||
|
argument to getVal // Parameter will be replaced with the new variable.
|
||||||
|
}
|
||||||
|
return parametersNew
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun inlineFunction(irCall: IrCall): IrExpression {
|
||||||
|
|
||||||
|
val functionDescriptor = irCall.descriptor as FunctionDescriptor
|
||||||
|
val functionDeclaration = context.ir.originalModuleIndex
|
||||||
|
.functions[functionDescriptor.original] // Get FunctionDeclaration by FunctionDescriptor.
|
||||||
|
|
||||||
|
if (functionDeclaration == null) return super.visitCall(irCall) // Function is declared in another module.
|
||||||
|
|
||||||
|
val copyFuncDeclaration = functionDeclaration.accept(DeepCopyIrTree(), // Create copy of the function.
|
||||||
|
null) as IrFunction
|
||||||
|
|
||||||
|
val startOffset = copyFuncDeclaration.startOffset
|
||||||
|
val endOffset = copyFuncDeclaration.endOffset
|
||||||
|
val returnType = copyFuncDeclaration.descriptor.returnType!!
|
||||||
|
val blockBody = copyFuncDeclaration.body!! as IrBlockBody
|
||||||
|
val statements = blockBody.statements
|
||||||
|
val parameters = evaluateParameters(irCall, statements) // Evaluate parameters representing expression.
|
||||||
|
val inlineBody = IrInlineFunctionBody(startOffset, endOffset, returnType, null, statements)
|
||||||
|
|
||||||
|
val lambdaInliner = LambdaInliner(parameters)
|
||||||
|
inlineBody.accept(lambdaInliner, null)
|
||||||
|
val transformer = ParametersTransformer(parameters, irCall)
|
||||||
|
inlineBody.accept(transformer, null) // Replace parameters with expression.
|
||||||
|
return inlineBody
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
val functionDescriptor = expression.descriptor as FunctionDescriptor
|
||||||
|
if (!functionDescriptor.name.asString().contains("foo")) return super.visitCall(expression)
|
||||||
|
|
||||||
|
if (functionDescriptor.isInline) return inlineFunction(expression) // Return newly created IrInlineBody instead of IrCall.
|
||||||
|
return super.visitCall(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) = element.accept(this, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
internal class LambdaInliner(val parameterToArgument:
|
||||||
|
List<Pair<ParameterDescriptor, IrExpression>>): IrElementTransformerVoid() {
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) = element.accept(this, null)
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun isLambdaCall(irCall: IrCall) : Boolean {
|
||||||
|
if (!(irCall.descriptor as FunctionDescriptor).isFunctionInvoke) return false // If it is lambda call.
|
||||||
|
if (irCall.dispatchReceiver !is IrGetValue) return false // Do not process such dispatch receiver.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,95 +136,74 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun evaluateParameters(irCall: IrCall,
|
fun getLambdaFunction(lambdaArgument: IrBlock): IrFunction {
|
||||||
statements: MutableList<IrStatement>): List<Pair<ParameterDescriptor, IrExpression>> {
|
val statements = (lambdaArgument as IrContainerExpressionBase).statements
|
||||||
|
val lambdaFunction = statements[0] as IrFunction
|
||||||
|
return lambdaFunction
|
||||||
|
}
|
||||||
|
|
||||||
val scope = Scope(irCall.descriptor as FunctionDescriptor)
|
//-------------------------------------------------------------------------//
|
||||||
val parametersOld = irCall.getArguments() // Create map inline_function_parameter -> containing_function_expression.
|
|
||||||
val parametersNew = parametersOld.map {
|
|
||||||
val parameter = it.first
|
|
||||||
val expression = it.second
|
|
||||||
if (expression is IrGetValue) return@map it // There is nothing to evaluate.
|
|
||||||
if (isLambda(expression)) { // The expression is lambda.
|
|
||||||
val inlineFunctionBody = inlineLambda(expression) // Create IrInlineFunctionBody to replace this parameter.
|
|
||||||
return@map parameter to inlineFunctionBody
|
|
||||||
}
|
|
||||||
|
|
||||||
val newVar = scope.createTemporaryVariable(expression, "inline", false) // Create new variable and init it with the expression.
|
fun inlineLambda(irCall: IrCall): IrExpression {
|
||||||
statements.add(0, newVar) // Add initialization of the new variable in statement list.
|
|
||||||
|
|
||||||
val getVal = IrGetValueImpl(0, 0, newVar.descriptor) // Create new IR element representing access the new variable.
|
val dispatchReceiver = irCall.dispatchReceiver as IrGetValue //
|
||||||
parameter to getVal // Parameter will be replaced with the new variable.
|
val parameterArgument = parameterToArgument.find { // Find expression to replace this parameter.
|
||||||
|
it.first == dispatchReceiver.descriptor
|
||||||
}
|
}
|
||||||
return parametersNew
|
if (parameterArgument == null) return super.visitCall(irCall) // It is not function parameter.
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
val lambdaArgument = parameterArgument.second
|
||||||
|
val lambdaFunction = getLambdaFunction(lambdaArgument as IrBlock)
|
||||||
|
|
||||||
fun inlineFunction(irCall: IrCall): IrBlock {
|
val parameters = lambdaFunction.descriptor.valueParameters // Lambda function parameters
|
||||||
|
val res = parameters.map {
|
||||||
|
val argument = irCall.getValueArgument(it.index)
|
||||||
|
val parameter = it
|
||||||
|
parameter to argument!!
|
||||||
|
}
|
||||||
|
|
||||||
val functionDescriptor = irCall.descriptor as FunctionDescriptor
|
val lambdaStatements = getLambdaStatements(lambdaArgument)
|
||||||
val functionDeclaration = context.ir.originalModuleIndex
|
val lambdaReturnType = getLambdaReturnType(lambdaArgument)
|
||||||
.functions[functionDescriptor] // Get FunctionDeclaration by FunctionDescriptor.
|
val inlineBody = IrInlineFunctionBody(0, 0, lambdaReturnType, null, lambdaStatements)
|
||||||
val copyFuncDeclaration = functionDeclaration!!.accept(DeepCopyIrTree(), null) as IrFunction // Create copy of the function.
|
|
||||||
|
|
||||||
val startOffset = copyFuncDeclaration.startOffset
|
val transformer = ParametersTransformer(res, irCall)
|
||||||
val endOffset = copyFuncDeclaration.endOffset
|
inlineBody.accept(transformer, null) // Replace parameters with expression.
|
||||||
val returnType = copyFuncDeclaration.descriptor.returnType!!
|
|
||||||
val inlineBody = copyFuncDeclaration.body!! as IrBlockBody
|
|
||||||
val statements = inlineBody.statements
|
|
||||||
val parameters = evaluateParameters(irCall, statements) // Evaluate parameters representing expression.
|
|
||||||
val irBlock = IrInlineFunctionBody(startOffset, endOffset, returnType, null, statements)
|
|
||||||
|
|
||||||
val transformer = ParametersTransformer(parameters)
|
return inlineBody // Replace call site with InlineFunctionBody.
|
||||||
irBlock.accept(transformer, null) // Replace parameters with expression.
|
|
||||||
return irBlock
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
fun inlineLambda(value: IrExpression): IrBlock {
|
|
||||||
|
|
||||||
val lambdaStatements = getLambdaStatements(value)
|
|
||||||
val lambdaReturnType = getLambdaReturnType(value)
|
|
||||||
val irBlock = IrInlineFunctionBody(0, 0, lambdaReturnType, null, lambdaStatements)
|
|
||||||
|
|
||||||
return irBlock
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
val functionDescriptor = expression.descriptor as FunctionDescriptor
|
if (!isLambdaCall(expression)) return super.visitCall(expression) // If call it is not lambda call - do nothing
|
||||||
if (!functionDescriptor.isInline) return super.visitCall(expression) // Function is not to be inlined - do nothing.
|
return inlineLambda(expression)
|
||||||
|
|
||||||
val functionDeclaration = context.ir.originalModuleIndex.functions[functionDescriptor] // Get FunctionDeclaration by FunctionDescriptor.
|
|
||||||
if (functionDeclaration == null) return super.visitCall(expression) // Function is declared in another module.
|
|
||||||
return inlineFunction(expression) // Return newly created IrBlock instead of IrCall.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) = element.accept(this, null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
internal class ParametersTransformer(val parameterToExpression: List <Pair<ParameterDescriptor, IrExpression>>): IrElementTransformerVoid() {
|
internal class ParametersTransformer(val parameterToArgument: List<Pair<ParameterDescriptor, IrExpression>>,
|
||||||
|
val callSite: IrCall): IrElementTransformerVoid() {
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) = element.accept(this, null)
|
override fun visitElement(element: IrElement) = element.accept(this, null)
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitTypeOperator(oldExpression: IrTypeOperatorCall): IrExpression {
|
||||||
if ((expression.descriptor as FunctionDescriptor).isFunctionInvoke) { // If it is lambda call.
|
|
||||||
if (expression.dispatchReceiver !is IrGetValue) super.visitCall(expression) // Do not process such dispatch receiver.
|
val expression = super.visitTypeOperator(oldExpression) as IrTypeOperatorCall
|
||||||
val getValue = expression.dispatchReceiver as IrGetValue //
|
|
||||||
val parameterExpression = parameterToExpression.find { it.first == getValue.descriptor } // Find expression to replace this parameter.
|
val typeArgsMap = (callSite as IrMemberAccessExpressionBase).typeArguments!!
|
||||||
if (parameterExpression == null) super.visitCall(expression) // It is not function parameter.
|
val typeConstructor = expression.typeOperand.constructor
|
||||||
return parameterExpression!!.second // Replace call site with InlineFunctionBody.
|
val typeOld = typeConstructor.declarationDescriptor as TypeParameterDescriptorImpl
|
||||||
}
|
val typeNew = typeArgsMap[typeOld]!!
|
||||||
return super.visitCall(expression) // Function is declared in another module.
|
val startOffset = expression.startOffset
|
||||||
|
val endOffset = expression.endOffset
|
||||||
|
val type = expression.type
|
||||||
|
val operator = expression.operator
|
||||||
|
val argument = expression.argument
|
||||||
|
|
||||||
|
return IrTypeOperatorCallImpl(startOffset, endOffset, type, operator, typeNew, argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
@@ -149,9 +213,9 @@ internal class ParametersTransformer(val parameterToExpression: List <Pair<Param
|
|||||||
if (descriptor !is ParameterDescriptor) { // TODO do we need this check?
|
if (descriptor !is ParameterDescriptor) { // TODO do we need this check?
|
||||||
return super.visitGetValue(expression)
|
return super.visitGetValue(expression)
|
||||||
}
|
}
|
||||||
val parameterExpression = parameterToExpression.find { it.first == descriptor } // Find expression to replace this parameter.
|
val parameterArgument = parameterToArgument.find { it.first.original == descriptor } // Find expression to replace this parameter.
|
||||||
if (parameterExpression == null) return super.visitGetValue(expression)
|
if (parameterArgument == null) return super.visitGetValue(expression)
|
||||||
|
|
||||||
return parameterExpression.second // TODO should we proceed with IR iteration here?
|
return parameterArgument.second // TODO should we proceed with IR iteration here?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1102,10 +1102,10 @@ task inline6(type: RunKonanTest) {
|
|||||||
source = "codegen/inline/inline6.kt"
|
source = "codegen/inline/inline6.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
//task inline7(type: RunKonanTest) {
|
task inline7(type: RunKonanTest) {
|
||||||
// goldValue = "1\n2\n3\n"
|
goldValue = "1\n2\n3\n"
|
||||||
// source = "codegen/inline/inline7.kt"
|
source = "codegen/inline/inline7.kt"
|
||||||
//}
|
}
|
||||||
|
|
||||||
task inline8(type: RunKonanTest) {
|
task inline8(type: RunKonanTest) {
|
||||||
goldValue = "8\n"
|
goldValue = "8\n"
|
||||||
@@ -1117,6 +1117,16 @@ task inline9(type: RunKonanTest) {
|
|||||||
source = "codegen/inline/inline9.kt"
|
source = "codegen/inline/inline9.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task inline10(type: RunKonanTest) {
|
||||||
|
goldValue = "2\n"
|
||||||
|
source = "codegen/inline/inline10.kt"
|
||||||
|
}
|
||||||
|
|
||||||
|
task inline14(type: RunKonanTest) {
|
||||||
|
goldValue = "9\n"
|
||||||
|
source = "codegen/inline/inline14.kt"
|
||||||
|
}
|
||||||
|
|
||||||
kotlinNativeInterop {
|
kotlinNativeInterop {
|
||||||
sysstat {
|
sysstat {
|
||||||
pkg 'sysstat'
|
pkg 'sysstat'
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun foo3(i3: Int): Int {
|
||||||
|
return i3 + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun foo2(i2: Int): Int {
|
||||||
|
return i2 + 2
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun foo1(i1: Int): Int {
|
||||||
|
return foo2(i1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(i0: Int): Int {
|
||||||
|
return foo1(i0) + foo3(i0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
println(bar(2).toString())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user