[Interop][Lowering] Fix access to struct members of Boolean type
This commit is contained in:
committed by
Sergey Bogolepov
parent
6c45bb416b
commit
ba52a437b1
+59
-10
@@ -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 <T> 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" }
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user