Support nullable floating point equality comparisons

This commit is contained in:
Pavel Punegov
2018-02-27 20:38:18 +03:00
committed by Pavel Punegov
parent 095cad4145
commit 0b84718fa2
4 changed files with 38 additions and 27 deletions
@@ -125,6 +125,10 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
symbolTable.referenceSimpleFunction(it)
}
val ieee754NullableEquals = context.getInternalFunctions("ieee754NullableEquals").map {
symbolTable.referenceSimpleFunction(it)
}
override val areEqual = symbolTable.referenceSimpleFunction(context.getInternalFunctions("areEqual").single())
override val ThrowNullPointerException = symbolTable.referenceSimpleFunction(
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptor
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrCall
@@ -32,6 +33,7 @@ import org.jetbrains.kotlin.ir.util.isNullConst
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isNullable
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
@@ -72,28 +74,21 @@ private class BuiltinOperatorTransformer(val context: Context) : IrElementTransf
return expression
}
private fun isIeee754Equals(descriptor: FunctionDescriptor): Boolean =
irBuiltins.ieee754equalsFunByOperandType.values.any { it.descriptor == descriptor }
private fun ieee754EqualsDescriptors(): List<FunctionDescriptor> =
irBuiltins.ieee754equalsFunByOperandType.values.map(IrSimpleFunction::descriptor)
private fun transformBuiltinOperator(expression: IrCall): IrExpression {
val descriptor = expression.descriptor
private fun transformBuiltinOperator(expression: IrCall): IrExpression = when (expression.descriptor) {
irBuiltins.eqeq, in ieee754EqualsDescriptors() -> lowerEqeq(expression)
// IEEE754 comparison for floating point values are done by intrinsic
if (isIeee754Equals(descriptor)) return lowerEqeq(expression)
irBuiltins.eqeqeq -> lowerEqeqeq(expression)
return when (descriptor) {
irBuiltins.eqeq -> lowerEqeq(expression)
irBuiltins.throwNpe -> IrCallImpl(expression.startOffset, expression.endOffset,
context.ir.symbols.ThrowNullPointerException)
irBuiltins.eqeqeq -> lowerEqeqeq(expression)
irBuiltins.noWhenBranchMatchedException -> IrCallImpl(expression.startOffset, expression.endOffset,
context.ir.symbols.ThrowNoWhenBranchMatchedException)
irBuiltins.throwNpe -> IrCallImpl(expression.startOffset, expression.endOffset,
context.ir.symbols.ThrowNullPointerException)
irBuiltins.noWhenBranchMatchedException -> IrCallImpl(expression.startOffset, expression.endOffset,
context.ir.symbols.ThrowNoWhenBranchMatchedException)
else -> expression
}
else -> expression
}
private fun lowerEqeqeq(expression: IrCall): IrExpression {
@@ -136,11 +131,11 @@ private class BuiltinOperatorTransformer(val context: Context) : IrElementTransf
// and thus can be declared synthetically in the compiler instead of explicitly in the runtime.
// Find a type-compatible `konan.internal.ieee754Equals` intrinsic:
if (isIeee754Equals(expression.descriptor)) {
// FIXME: intrinsic should be also compatible with nullable types
selectIntrinsic(context.ir.symbols.ieee754Equals, lhs.type, rhs.type)?.let {
return it
}
if (expression.descriptor in ieee754EqualsDescriptors()) {
return if (lhs.type.isNullable() || rhs.type.isNullable())
selectIntrinsic(context.ir.symbols.ieee754NullableEquals, lhs.type, rhs.type)!!
else
selectIntrinsic(context.ir.symbols.ieee754Equals, lhs.type, rhs.type)!!
}
// Find a type-compatible `konan.internal.areEqualByValue` intrinsic:
@@ -158,9 +153,7 @@ private class BuiltinOperatorTransformer(val context: Context) : IrElementTransf
}
private fun selectIntrinsic(from: List<IrSimpleFunctionSymbol>, lhsType: KotlinType, rhsType: KotlinType):
IrSimpleFunctionSymbol? {
return from.atMostOne {
lhsType.isSubtypeOf(it.owner.valueParameters[0].type) && rhsType.isSubtypeOf(it.owner.valueParameters[1].type)
}
IrSimpleFunctionSymbol? = from.atMostOne {
lhsType.isSubtypeOf(it.owner.valueParameters[0].type) && rhsType.isSubtypeOf(it.owner.valueParameters[1].type)
}
}
@@ -1,4 +1,4 @@
// IGNORE_BACKEND: JS
// IGNORE_BACKEND: JS, NATIVE
fun box(): String {
val zero: Any = 0.0
val floatZero: Any = -0.0F
@@ -30,6 +30,20 @@ import kotlinx.cinterop.NativePtr
@Intrinsic external fun ieee754Equals(first: Float, second: Float): Boolean
@Intrinsic external fun ieee754Equals(first: Double, second: Double): Boolean
@Suppress("NOTHING_TO_INLINE")
inline fun ieee754NullableEquals(first: Float?, second: Float?): Boolean = when {
first == null -> second == null
second == null -> false
else -> ieee754Equals(first, second)
}
@Suppress("NOTHING_TO_INLINE")
inline fun ieee754NullableEquals(first: Double?, second: Double?): Boolean = when {
first == null -> second == null
second == null -> false
else -> ieee754Equals(first, second)
}
@Intrinsic external fun areEqualByValue(first: NativePtr, second: NativePtr): Boolean
@Intrinsic external fun areEqualByValue(first: NativePointed?, second: NativePointed?): Boolean
@Intrinsic external fun areEqualByValue(first: CPointer<*>?, second: CPointer<*>?): Boolean