[Interop][Lowering] Fix access to struct members of Boolean type

This commit is contained in:
Sergey Bogolepov
2020-07-08 20:52:06 +07:00
committed by Sergey Bogolepov
parent 6c45bb416b
commit ba52a437b1
2 changed files with 62 additions and 10 deletions
@@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ir.simpleFunctions import org.jetbrains.kotlin.backend.common.ir.simpleFunctions
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
import org.jetbrains.kotlin.backend.konan.PrimitiveBinaryType
import org.jetbrains.kotlin.backend.konan.RuntimeNames import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.cgen.isCEnumType import org.jetbrains.kotlin.backend.konan.cgen.isCEnumType
import org.jetbrains.kotlin.backend.konan.cgen.isVector import org.jetbrains.kotlin.backend.konan.cgen.isVector
@@ -20,9 +21,11 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.isPropertyAccessor import org.jetbrains.kotlin.ir.declarations.isPropertyAccessor
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
@@ -68,6 +71,8 @@ private class InteropCallContext(
|| classOrNull == symbols.mutableList || classOrNull == symbols.mutableList
|| classOrNull == symbols.set || classOrNull == symbols.set
|| classOrNull == symbols.map || classOrNull == symbols.map
val irBuiltIns: IrBuiltIns = builder.context.irBuiltIns
} }
private inline fun <T> generateInteropCall( private inline fun <T> generateInteropCall(
@@ -137,10 +142,13 @@ private fun InteropCallContext.writeValueToMemory(
private fun InteropCallContext.determineInMemoryType(type: IrType): IrType { private fun InteropCallContext.determineInMemoryType(type: IrType): IrType {
val classifier = type.classOrNull!! val classifier = type.classOrNull!!
return if (classifier in symbols.unsignedIntegerClasses) { return when (classifier) {
symbols.unsignedToSignedOfSameBitWidth.getValue(classifier).owner.defaultType in symbols.unsignedIntegerClasses -> {
} else { symbols.unsignedToSignedOfSameBitWidth.getValue(classifier).owner.defaultType
type }
// Assuming that _Bool is stored as single byte.
irBuiltIns.booleanClass -> symbols.byte.defaultType
else -> type
} }
} }
@@ -152,12 +160,18 @@ private fun InteropCallContext.castPrimitiveIfNeeded(
val sourceClass = fromType.classOrNull!! val sourceClass = fromType.classOrNull!!
val targetClass = toType.classOrNull!! val targetClass = toType.classOrNull!!
return if (sourceClass != targetClass) { return if (sourceClass != targetClass) {
val conversion = symbols.integerConversions.getValue(sourceClass to targetClass) when {
builder.irCall(conversion.owner).apply { targetClass == irBuiltIns.booleanClass -> castToBoolean(sourceClass, value)
if (conversion.owner.dispatchReceiverParameter != null) { sourceClass == irBuiltIns.booleanClass -> castFromBoolean(targetClass, value)
dispatchReceiver = value else -> {
} else { val conversion = symbols.integerConversions.getValue(sourceClass to targetClass)
extensionReceiver = value builder.irCall(conversion.owner).apply {
if (conversion.owner.dispatchReceiverParameter != null) {
dispatchReceiver = value
} else {
extensionReceiver = value
}
}
} }
} }
} else { } else {
@@ -165,6 +179,41 @@ private fun InteropCallContext.castPrimitiveIfNeeded(
} }
} }
/**
* Perform (value != 0)
*/
private fun InteropCallContext.castToBoolean(sourceClass: IrClassSymbol, value: IrExpression): IrExpression {
val (primitiveBinaryType, immZero) = when (sourceClass) {
// Case of regular struct field.
symbols.byte -> PrimitiveBinaryType.BYTE to builder.irByte(0)
// Case of bitfield.
symbols.long -> PrimitiveBinaryType.LONG to builder.irLong(0)
else -> error("Unsupported cast to boolean from ${sourceClass.owner.name}")
}
val areEqualByValuesBytes = symbols.areEqualByValue.getValue(primitiveBinaryType)
val compareToZero = builder.irCall(areEqualByValuesBytes).apply {
putValueArgument(0, value)
putValueArgument(1, immZero)
}
return builder.irCall(irBuiltIns.booleanNotSymbol).apply {
dispatchReceiver = compareToZero
}
}
/**
* Perform if (value) 1 else 0
*/
private fun InteropCallContext.castFromBoolean(targetClass: IrClassSymbol, value: IrExpression): IrExpression {
val (thenPart, elsePart) = when (targetClass) {
// Case of regular struct field.
symbols.byte -> builder.irByte(1) to builder.irByte(0)
// Case of bitfield.
symbols.long -> builder.irLong(1) to builder.irLong(0)
else -> error("Unsupported cast from boolean to ${targetClass.owner.name}")
}
return builder.irIfThenElse(targetClass.defaultType, value, thenPart, elsePart)
}
private fun InteropCallContext.convertEnumToIntegral(enumValue: IrExpression, targetEnumType: IrType): IrExpression { private fun InteropCallContext.convertEnumToIntegral(enumValue: IrExpression, targetEnumType: IrType): IrExpression {
val enumClass = targetEnumType.getClass()!! val enumClass = targetEnumType.getClass()!!
val valueProperty = enumClass.properties.single { it.name.asString() == "value" } val valueProperty = enumClass.properties.single { it.name.asString() == "value" }
@@ -401,3 +401,6 @@ fun IrFunction.isTypeOfIntrinsic(): Boolean =
this.name.asString() == "typeOf" && this.name.asString() == "typeOf" &&
this.valueParameters.isEmpty() && this.valueParameters.isEmpty() &&
(this.parent as? IrPackageFragment)?.fqName == KOTLIN_REFLECT_FQ_NAME (this.parent as? IrPackageFragment)?.fqName == KOTLIN_REFLECT_FQ_NAME
fun IrBuilderWithScope.irByte(value: Byte) =
IrConstImpl.byte(startOffset, endOffset, context.irBuiltIns.byteType, value)