+3
@@ -39,5 +39,8 @@ internal class KonanLower(val context: Context) {
|
||||
phaser.phase(KonanPhase.AUTOBOX) {
|
||||
Autoboxing(context).lower(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_INLINE) {
|
||||
FunctionInlining(context).inline(irFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -16,6 +16,7 @@ enum class KonanPhase(val description: String,
|
||||
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering"),
|
||||
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering"),
|
||||
/* ... ... */ LOWER_CALLABLES("Callable references Lowering"),
|
||||
/* ... ... */ LOWER_INLINE("Functions inlining"),
|
||||
/* ... ... */ AUTOBOX("Autoboxing of primitive types"),
|
||||
/* ... */ BITCODE("LLVM BitCode Generation"),
|
||||
/* ... ... */ RTTI("RTTI Generation"),
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package org.jetbrains.kotlin.backend.konan.ir
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlock
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBase
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
//-----------------------------------------------------------------------------//
|
||||
|
||||
class IrInlineFunctionBody(startOffset: Int, endOffset: Int, type: KotlinType, origin: IrStatementOrigin? = null):
|
||||
IrContainerExpressionBase(startOffset, endOffset, type, origin), IrBlock {
|
||||
constructor(startOffset: Int, endOffset: Int, type: KotlinType, origin: IrStatementOrigin?, statements: List<IrStatement>) :
|
||||
this(startOffset, endOffset, type, origin) {
|
||||
this.statements.addAll(statements)
|
||||
}
|
||||
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitBlock(this, data)
|
||||
|
||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
statements.forEach { it.accept(visitor, data) }
|
||||
}
|
||||
|
||||
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
|
||||
statements.forEachIndexed { i, irStatement ->
|
||||
statements[i] = irStatement.transform(transformer, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------//
|
||||
|
||||
+14
@@ -1,7 +1,9 @@
|
||||
package org.jetbrains.kotlin.backend.konan.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
@@ -16,6 +18,11 @@ class ModuleIndex(val module: IrModuleFragment) {
|
||||
*/
|
||||
val classes: Map<ClassId, IrClass>
|
||||
|
||||
/**
|
||||
* Contains all functions declared in [module]
|
||||
*/
|
||||
val functions = mutableMapOf<FunctionDescriptor, IrFunction>()
|
||||
|
||||
init {
|
||||
val map = mutableMapOf<ClassId, IrClass>()
|
||||
|
||||
@@ -33,6 +40,13 @@ class ModuleIndex(val module: IrModuleFragment) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
super.visitFunction(declaration)
|
||||
|
||||
val functionDescriptor = declaration.descriptor
|
||||
functions[functionDescriptor] = declaration
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
classes = map
|
||||
|
||||
+61
-1
@@ -629,6 +629,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
is IrThrow -> return evaluateThrow (value)
|
||||
is IrTry -> return evaluateTry (value)
|
||||
is IrStringConcatenation -> return evaluateStringConcatenation(value)
|
||||
is IrInlineFunctionBody -> return evaluateInlineFunction (value)
|
||||
is IrContainerExpression -> return evaluateContainerExpression(value)
|
||||
is IrWhileLoop -> return evaluateWhileLoop (value)
|
||||
is IrDoWhileLoop -> return evaluateDoWhileLoop (value)
|
||||
@@ -741,7 +742,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
*/
|
||||
private fun continuationBlock(type: KotlinType,
|
||||
code: (ContinuationBlock) -> Unit = {}): ContinuationBlock {
|
||||
val entry = codegen.basicBlock()
|
||||
val entry = codegen.basicBlock("continuation_block")
|
||||
|
||||
codegen.appendingTo(entry) {
|
||||
val valuePhi = if (type.isUnit()) {
|
||||
@@ -1469,6 +1470,65 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private inner class InlinedFunctionScope(val inlineBody: IrInlineFunctionBody) : InnerScopeImpl() {
|
||||
|
||||
var bbExit : LLVMBasicBlockRef? = null
|
||||
var resultPhi : LLVMValueRef? = null
|
||||
|
||||
fun getExit(): LLVMBasicBlockRef? {
|
||||
if (bbExit == null) bbExit = codegen.basicBlock("inline_body_exit")
|
||||
return bbExit
|
||||
}
|
||||
|
||||
fun getResult(): LLVMValueRef? {
|
||||
if (resultPhi == null) {
|
||||
val bbCurrent = codegen.currentBlock
|
||||
codegen.positionAtEnd(getExit()!!)
|
||||
resultPhi = codegen.phi(codegen.getLLVMType(inlineBody.type))
|
||||
codegen.positionAtEnd(bbCurrent)
|
||||
}
|
||||
return resultPhi
|
||||
}
|
||||
|
||||
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
|
||||
if (KotlinBuiltIns.isUnit(inlineBody.type) == false) {
|
||||
codegen.assignPhis(getResult()!! to value!!)
|
||||
}
|
||||
codegen.br(getExit()!!)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateInlineFunction(value: IrInlineFunctionBody): LLVMValueRef {
|
||||
context.log("evaluateInlineFunction : ${value.statements.forEach { ir2string(it) }}")
|
||||
|
||||
val inlinedFunctionScope = InlinedFunctionScope(value)
|
||||
using(inlinedFunctionScope) {
|
||||
value.statements.forEach {
|
||||
generateStatement(it)
|
||||
}
|
||||
}
|
||||
|
||||
if (!codegen.isAfterTerminator()) { // TODO should we solve this problem once and for all
|
||||
if (inlinedFunctionScope.resultPhi != null) {
|
||||
codegen.unreachable()
|
||||
}
|
||||
}
|
||||
|
||||
if (inlinedFunctionScope.bbExit != null) {
|
||||
codegen.positionAtEnd(inlinedFunctionScope.bbExit!!)
|
||||
}
|
||||
|
||||
if (inlinedFunctionScope.resultPhi != null) {
|
||||
return inlinedFunctionScope.resultPhi!!
|
||||
} else {
|
||||
return codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateContainerExpression(value: IrContainerExpression): LLVMValueRef {
|
||||
context.log("evaluateContainerExpression : ${value.statements.forEach { ir2string(it) }}")
|
||||
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.ir.IrInlineFunctionBody
|
||||
import org.jetbrains.kotlin.backend.konan.ir.getArguments
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
|
||||
//-----------------------------------------------------------------------------//
|
||||
|
||||
internal class FunctionInlining(val context: Context): IrElementTransformerVoid() {
|
||||
|
||||
fun inline(irFile: IrFile) = irFile.accept(this, null)
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val functionDescriptor = expression.descriptor as FunctionDescriptor
|
||||
if (!functionDescriptor.isInline) return super.visitCall(expression) // Function is not to be inlined - do nothing.
|
||||
|
||||
val functionDeclaration = context.ir.moduleIndex.functions[functionDescriptor] // Get FunctionDeclaration by FunctionDescriptor.
|
||||
if (functionDeclaration == null) return super.visitCall(expression) // Function is declared in another module.
|
||||
val copyFuncDeclaration = functionDeclaration.accept(DeepCopyIrTree(), null) as IrFunction // Create copy of the function.
|
||||
|
||||
val body = copyFuncDeclaration.body!! as IrBlockBody
|
||||
val startOffset = copyFuncDeclaration.startOffset
|
||||
val endOffset = copyFuncDeclaration.endOffset
|
||||
val returnType = copyFuncDeclaration.descriptor.returnType!!
|
||||
val statements = body.statements
|
||||
val irBlock = IrInlineFunctionBody(startOffset, endOffset, returnType, null, statements)
|
||||
|
||||
val parameterToExpression = expression.getArguments() // Build map parameter -> expression.
|
||||
val parametersTransformer = ParametersTransformer(parameterToExpression)
|
||||
irBlock.accept(parametersTransformer, null) // Replace parameters with expression.
|
||||
|
||||
return irBlock // 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() {
|
||||
|
||||
override fun visitElement(element: IrElement) = element.accept(this, null)
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val descriptor = expression.descriptor
|
||||
if (descriptor !is ParameterDescriptor) { // TODO do we need this check?
|
||||
return super.visitGetValue(expression)
|
||||
}
|
||||
val parExp = parameterToExpression.find { it.first == descriptor } // Find expression to replace this parameter.
|
||||
return parExp?.let { parExp.second } ?: super.visitGetValue(expression) // TODO should we proceed with IR iteration here?
|
||||
}
|
||||
}
|
||||
@@ -884,3 +884,23 @@ task unit4(type: RunKonanTest) {
|
||||
goldValue = "Done\n"
|
||||
source = "codegen/basics/unit4.kt"
|
||||
}
|
||||
|
||||
task inline0(type: RunKonanTest) {
|
||||
goldValue = "84\n"
|
||||
source = "codegen/inline/inline0.kt"
|
||||
}
|
||||
|
||||
task inline1(type: RunKonanTest) {
|
||||
goldValue = "Hello world\n"
|
||||
source = "codegen/inline/inline1.kt"
|
||||
}
|
||||
|
||||
task inline2(type: RunKonanTest) {
|
||||
goldValue = "hello 1 8\n"
|
||||
source = "codegen/inline/inline2.kt"
|
||||
}
|
||||
|
||||
task inline3(type: RunKonanTest) {
|
||||
goldValue = "5\n"
|
||||
source = "codegen/inline/inline3.kt"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun foo(i1: Int, j1: Int): Int {
|
||||
return i1 + j1
|
||||
}
|
||||
|
||||
fun bar(i: Int, j: Int): Int {
|
||||
return i + foo(i, j)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(bar(41, 2).toString())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun foo(s4: String, s5: String): String {
|
||||
return s4 + s5
|
||||
}
|
||||
|
||||
fun bar(s1: String, s2: String, s3: String): String {
|
||||
return s1 + foo(s2, s3)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(bar("Hello ", "wor", "ld"))
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun foo(i4: Int, i5: Int) {
|
||||
println("hello $i4 $i5")
|
||||
}
|
||||
|
||||
fun bar(i1: Int, i2: Int) {
|
||||
foo(i1, i2)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
bar(1, 8)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun foo(i4: Int, i5: Int): Int {
|
||||
try {
|
||||
return i4 / i5
|
||||
} catch (e: Throwable) {
|
||||
return i4
|
||||
}
|
||||
}
|
||||
|
||||
fun bar(i1: Int, i2: Int, i3: Int): Int {
|
||||
return i1 + foo(i2, i3)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(bar(1, 8, 2).toString())
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun foo(i4: Int, i5: Int): Int {
|
||||
if (i4 > 0) return i4
|
||||
return i5
|
||||
}
|
||||
|
||||
fun bar(i1: Int, i2: Int): Int {
|
||||
return foo(i1, i2)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(bar(1, 8).toString())
|
||||
}
|
||||
Reference in New Issue
Block a user