backend: lower interop

This commit is contained in:
Svyatoslav Scherbina
2017-01-31 13:27:26 +07:00
committed by SvyatoslavScherbina
parent 7f90ce3d8a
commit 3892820052
3 changed files with 206 additions and 0 deletions
@@ -51,5 +51,9 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_INLINE) {
//FunctionInlining(context).inline(irFile)
}
phaser.phase(KonanPhase.LOWER_INTEROP) {
InteropLowering(context).runOnFilePostfix(irFile)
}
}
}
@@ -18,6 +18,7 @@ enum class KonanPhase(val description: String,
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering"),
/* ... ... */ LOWER_CALLABLES("Callable references Lowering"),
/* ... ... */ LOWER_INLINE("Functions inlining"),
/* ... ... */ LOWER_INTEROP("Interop lowering"),
/* ... ... */ AUTOBOX("Autoboxing of primitive types"),
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering"),
@@ -0,0 +1,201 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.IrBuilder
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
/**
* Lowers some interop intrinsic calls.
*/
internal class InteropLowering(val context: Context) : FunctionLoweringPass {
override fun lower(irFunction: IrFunction) {
val transformer = InteropTransformer(context, irFunction.descriptor)
irFunction.transformChildrenVoid(transformer)
}
}
private class InteropTransformer(val context: Context, val function: FunctionDescriptor) : IrElementTransformerVoid() {
val builder = context.createFunctionIrBuilder(function)
val interop = context.interopBuiltIns
private fun MemberScope.getSingleContributedFunction(name: String,
predicate: (SimpleFunctionDescriptor) -> Boolean) =
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single(predicate)
private fun IrBuilder.irGetObject(descriptor: ClassDescriptor): IrExpression {
return IrGetObjectValueImpl(startOffset, endOffset, descriptor.defaultType, descriptor)
}
private fun IrBuilder.typeOf(descriptor: ClassDescriptor): IrExpression {
val companionObject = descriptor.companionObjectDescriptor ?:
error("native variable class $descriptor must have the companion object")
// TODO: add more checks and produce the compile error instead of exception.
return irGetObject(companionObject)
}
private fun IrBuilder.typeOf(type: KotlinType): IrExpression? {
val descriptor = TypeUtils.getClassDescriptor(type) ?: return null
return typeOf(descriptor)
}
private fun KotlinType.findOverride(property: PropertyDescriptor): PropertyDescriptor {
val result = this.memberScope.getContributedVariables(property.name, NoLookupLocation.FROM_BACKEND).single()
assert (OverridingUtil.overrides(result, property))
return result
}
private fun IrBuilderWithScope.sizeOf(typeObject: IrExpression): IrExpression {
val sizeProperty = typeObject.type.findOverride(interop.variableTypeSize)
return irGet(typeObject, sizeProperty)
}
private fun IrBuilderWithScope.sizeOf(type: KotlinType): IrExpression? {
val typeObject = typeOf(type) ?: return null
return sizeOf(typeObject)
}
private fun IrBuilderWithScope.alignOf(typeObject: IrExpression): IrExpression {
val alignProperty = typeObject.type.findOverride(interop.variableTypeAlign)
return irGet(typeObject, alignProperty)
}
private fun IrBuilderWithScope.alignOf(type: KotlinType): IrExpression? {
val typeObject = typeOf(type) ?: return null
return alignOf(typeObject)
}
private fun IrBuilderWithScope.arrayGet(array: IrExpression, index: IrExpression): IrExpression? {
val elementSize = sizeOf(array.type.arguments.single().type) ?: return null
val offset = times(elementSize, index)
return irCall(interop.memberAt).apply {
extensionReceiver = array
putValueArgument(0, offset)
}
}
private fun IrBuilderWithScope.times(left: IrExpression, right: IrExpression): IrCall {
val times = left.type.memberScope.getSingleContributedFunction("times") {
right.type.isSubtypeOf(it.valueParameters.single().type)
}
return irCall(times).apply {
dispatchReceiver = left
putValueArgument(0, right)
}
}
private fun IrBuilderWithScope.alloc(placement: IrExpression, size: IrExpression, align: IrExpression): IrExpression {
val alloc = placement.type.memberScope.getSingleContributedFunction("alloc") {
size.type.isSubtypeOf(it.valueParameters[0]!!.type) &&
align.type.isSubtypeOf(it.valueParameters[1]!!.type)
}
return irCall(alloc).apply {
dispatchReceiver = placement
putValueArgument(0, size)
putValueArgument(1, align)
}
}
private fun IrBuilderWithScope.allocArray(placement: IrExpression,
elementType: KotlinType,
length: IrExpression
): IrExpression? {
val elementSize = sizeOf(elementType) ?: return null
val size = times(elementSize, length)
val align = alignOf(elementType) ?: return null
return alloc(placement, size, align)
}
private fun IrBuilderWithScope.alloc(placement: IrExpression, type: KotlinType): IrExpression? {
val size = sizeOf(type) ?: return null
val align = alignOf(type) ?: return null
return alloc(placement, size, align)
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
builder.at(expression)
val descriptor = expression.descriptor.original
if (descriptor is ClassConstructorDescriptor) {
val type = descriptor.constructedClass.defaultType
if (type.isRepresentedAs(ValueType.C_POINTER) || type.isRepresentedAs(ValueType.NATIVE_POINTED)) {
return expression.getValueArgument(0)!!
}
}
if (descriptor == interop.nativePointedRawPtrGetter ||
OverridingUtil.overrides(descriptor, interop.nativePointedRawPtrGetter)) {
return expression.dispatchReceiver!!
}
return when (descriptor) {
interop.cPointerRawValue.getter -> expression.dispatchReceiver!!
interop.interpretPointed -> expression.getValueArgument(0)!!
interop.arrayGetByIntIndex, interop.arrayGetByLongIndex -> {
val array = expression.extensionReceiver!!
val index = expression.getValueArgument(0)!!
builder.arrayGet(array, index) ?: expression
}
interop.allocUninitializedArrayWithIntLength, interop.allocUninitializedArrayWithLongLength -> {
val placement = expression.extensionReceiver!!
val elementType = expression.type.arguments.single().type
val length = expression.getValueArgument(0)!!
builder.allocArray(placement, elementType, length) ?: expression
}
interop.allocVariable -> {
val placement = expression.extensionReceiver!!
val type = expression.getSingleTypeArgument()
builder.alloc(placement, type) ?: expression
}
interop.typeOf -> {
val type = expression.getSingleTypeArgument()
builder.typeOf(type) ?: expression
}
else -> expression
}
}
private fun IrCall.getSingleTypeArgument(): KotlinType {
val typeParameter = descriptor.original.typeParameters.single()
return getTypeArgument(typeParameter)!!
}
}