diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt index 359112514f9..f70e6300ec1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.ir.simpleFunctions 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.cgen.isCEnumType 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.IrProperty 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.IrConst 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.util.* import org.jetbrains.kotlin.utils.addToStdlib.cast @@ -68,6 +71,8 @@ private class InteropCallContext( || classOrNull == symbols.mutableList || classOrNull == symbols.set || classOrNull == symbols.map + + val irBuiltIns: IrBuiltIns = builder.context.irBuiltIns } private inline fun generateInteropCall( @@ -137,10 +142,13 @@ private fun InteropCallContext.writeValueToMemory( private fun InteropCallContext.determineInMemoryType(type: IrType): IrType { val classifier = type.classOrNull!! - return if (classifier in symbols.unsignedIntegerClasses) { - symbols.unsignedToSignedOfSameBitWidth.getValue(classifier).owner.defaultType - } else { - type + return when (classifier) { + in symbols.unsignedIntegerClasses -> { + symbols.unsignedToSignedOfSameBitWidth.getValue(classifier).owner.defaultType + } + // 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 targetClass = toType.classOrNull!! return if (sourceClass != targetClass) { - val conversion = symbols.integerConversions.getValue(sourceClass to targetClass) - builder.irCall(conversion.owner).apply { - if (conversion.owner.dispatchReceiverParameter != null) { - dispatchReceiver = value - } else { - extensionReceiver = value + when { + targetClass == irBuiltIns.booleanClass -> castToBoolean(sourceClass, value) + sourceClass == irBuiltIns.booleanClass -> castFromBoolean(targetClass, value) + else -> { + val conversion = symbols.integerConversions.getValue(sourceClass to targetClass) + builder.irCall(conversion.owner).apply { + if (conversion.owner.dispatchReceiverParameter != null) { + dispatchReceiver = value + } else { + extensionReceiver = value + } + } } } } 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 { val enumClass = targetEnumType.getClass()!! val valueProperty = enumClass.properties.single { it.name.asString() == "value" } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt index a180d18d5be..d79afe36f46 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt @@ -401,3 +401,6 @@ fun IrFunction.isTypeOfIntrinsic(): Boolean = this.name.asString() == "typeOf" && this.valueParameters.isEmpty() && (this.parent as? IrPackageFragment)?.fqName == KOTLIN_REFLECT_FQ_NAME + +fun IrBuilderWithScope.irByte(value: Byte) = + IrConstImpl.byte(startOffset, endOffset, context.irBuiltIns.byteType, value)