Generate intrinsic-based numeric comparison only for FP types
This commit is contained in:
@@ -3373,31 +3373,33 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
TypeAndNullability left754Type = calcTypeForIeee754ArithmeticIfNeeded(left, getLeftOperandType(primitiveNumericComparisonInfo));
|
||||
TypeAndNullability right754Type = calcTypeForIeee754ArithmeticIfNeeded(right, getRightOperandType(primitiveNumericComparisonInfo));
|
||||
|
||||
if (left754Type != null && right754Type != null) {
|
||||
if (left754Type.type.equals(right754Type.type)) {
|
||||
//check nullability cause there is some optimizations in codegen for non-nullable case
|
||||
if (left754Type.isNullable || right754Type.isNullable) {
|
||||
if (state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_1) >= 0) {
|
||||
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
|
||||
generate754EqualsForNullableTypesViaIntrinsic(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
Type comparisonType = comparisonOperandType(left754Type.type, right754Type.type);
|
||||
if (comparisonType == Type.FLOAT_TYPE || comparisonType == Type.DOUBLE_TYPE) {
|
||||
if (left754Type.type.equals(right754Type.type)) {
|
||||
//check nullability cause there is some optimizations in codegen for non-nullable case
|
||||
if (left754Type.isNullable || right754Type.isNullable) {
|
||||
if (state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_1) >= 0) {
|
||||
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
|
||||
generate754EqualsForNullableTypesViaIntrinsic(v, opToken, pregeneratedLeft, left, left754Type, right,
|
||||
right754Type);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
else {
|
||||
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
|
||||
generate754EqualsForNullableTypes(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
|
||||
generate754EqualsForNullableTypes(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
leftType = left754Type.type;
|
||||
rightType = right754Type.type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
leftType = left754Type.type;
|
||||
rightType = right754Type.type;
|
||||
}
|
||||
}
|
||||
else if (shouldUseProperIeee754Comparisons()) {
|
||||
Type comparisonType = comparisonOperandType(left754Type.type, right754Type.type);
|
||||
if (comparisonType == Type.FLOAT_TYPE || comparisonType == Type.DOUBLE_TYPE) {
|
||||
else if (shouldUseProperIeee754Comparisons()) {
|
||||
return Ieee754Equality.create(
|
||||
myFrameMap,
|
||||
genLazy(left, boxIfNullable(left754Type)),
|
||||
|
||||
@@ -35,6 +35,9 @@ fun calcProperTypeForIeee754ArithmeticIfNeeded(
|
||||
return TypeAndNullability(asmType, isNullable)
|
||||
}
|
||||
|
||||
private fun KotlinType.isFloatingPointOrNullable() =
|
||||
KotlinBuiltIns.isDoubleOrNullableDouble(this) || KotlinBuiltIns.isFloatOrNullableFloat(this)
|
||||
|
||||
private fun KtExpression.getKotlinTypeForComparison(bindingContext: BindingContext): KotlinType? =
|
||||
when {
|
||||
this is KtProperty -> bindingContext[BindingContext.VARIABLE, this]?.type
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// !LANGUAGE: +ProperIeee754Comparisons
|
||||
|
||||
fun eq1(a: Int?, b: Int) = a == b
|
||||
|
||||
fun eq2(a: Int, b: Int?) = a == b
|
||||
|
||||
fun eq3(a: Int?, b: Int?) = a == b
|
||||
|
||||
fun box(): String =
|
||||
when {
|
||||
!eq1(1, 1) -> "Fail 1"
|
||||
!eq2(1, 1) -> "Fail 2"
|
||||
!eq3(1, 1) -> "Fail 3"
|
||||
else -> "OK"
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// !LANGUAGE: +ProperIeee754Comparisons
|
||||
|
||||
fun eq1(a: Any?, b: Any?) =
|
||||
a is Int? && b is Int && a == b
|
||||
|
||||
fun eq2(a: Any?, b: Any?) =
|
||||
a is Int && b is Int? && a == b
|
||||
|
||||
fun eq3(a: Any?, b: Any?) =
|
||||
a is Int && b is Int && a == b
|
||||
|
||||
fun eq4(a: Any?, b: Any?) =
|
||||
a is Int? && b is Int? && a == b
|
||||
|
||||
fun box(): String =
|
||||
when {
|
||||
!eq1(1, 1) -> "Fail 1"
|
||||
!eq2(1, 1) -> "Fail 2"
|
||||
!eq3(1, 1) -> "Fail 3"
|
||||
!eq4(1, 1) -> "Fail 4"
|
||||
else -> "OK"
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// !LANGUAGE: +ProperIeee754Comparisons
|
||||
|
||||
fun test(x: Any?): String {
|
||||
if (x !is Int) return "Fail 1"
|
||||
when (x) {
|
||||
0 -> return "OK"
|
||||
else -> return "Fail 2"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String = test(0)
|
||||
+8
-13
@@ -1,11 +1,7 @@
|
||||
FILE fqName:<root> fileName:/builtinMap.kt
|
||||
FUN name:plus visibility:public modality:FINAL <K1, V1> ($receiver:kotlin.collections.Map<out K1, V1>, pair:kotlin.Pair<K1, V1>) returnType:Map<K1, V1> flags:
|
||||
TYPE_PARAMETER name:K1 index:0 variance: upperBounds:[kotlin.Any?]
|
||||
superClassifiers:
|
||||
CLASS IR_EXTERNAL_DECLARATION_STUB CLASS name:Any modality:OPEN visibility:public flags:
|
||||
TYPE_PARAMETER name:V1 index:1 variance: upperBounds:[kotlin.Any?]
|
||||
superClassifiers:
|
||||
CLASS IR_EXTERNAL_DECLARATION_STUB CLASS name:Any modality:OPEN visibility:public flags:
|
||||
FUN name:plus visibility:public modality:FINAL <K1, V1> ($receiver:kotlin.collections.Map<out K1, V1>, pair:kotlin.Pair<K1, V1>) returnType:kotlin.collections.Map<K1, V1> flags:
|
||||
TYPE_PARAMETER name:K1 index:0 variance: superTypes:[kotlin.Any?]
|
||||
TYPE_PARAMETER name:V1 index:1 variance: superTypes:[kotlin.Any?]
|
||||
$receiver: VALUE_PARAMETER name:<this> type:kotlin.collections.Map<out K1, V1> flags:
|
||||
VALUE_PARAMETER name:pair index:0 type:kotlin.Pair<K1, V1> flags:
|
||||
BLOCK_BODY
|
||||
@@ -21,18 +17,18 @@ FILE fqName:<root> fileName:/builtinMap.kt
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CALL 'apply(LinkedHashMap<K1!, V1!> /* = LinkedHashMap<K1!, V1!> */.() -> Unit) on LinkedHashMap<K1!, V1!> /* = LinkedHashMap<K1!, V1!> */: LinkedHashMap<K1!, V1!> /* = LinkedHashMap<K1!, V1!> */' type=kotlin.collections.LinkedHashMap<K1!, V1!> /* = java.util.LinkedHashMap<K1!, V1!> */ origin=null
|
||||
<T>: LinkedHashMap<K1!, V1!> /* = LinkedHashMap<K1!, V1!> */
|
||||
<T>: kotlin.collections.LinkedHashMap<K1!, V1!> /* = java.util.LinkedHashMap<K1!, V1!> */
|
||||
$receiver: CALL 'constructor LinkedHashMap((MutableMap<out K1!, out V1!>..Map<out K1!, V1!>?))' type=java.util.LinkedHashMap<K1!, V1!> origin=null
|
||||
<K : Any!>: K1!
|
||||
<V : Any!>: V1!
|
||||
<K : Any!>: K1?
|
||||
<V : Any!>: V1?
|
||||
p0: GET_VAR 'this@plus: Map<out K1, V1>' type=kotlin.collections.Map<out K1, V1> origin=null
|
||||
block: BLOCK type=kotlin.collections.LinkedHashMap<K1!, V1!> /* = java.util.LinkedHashMap<K1!, V1!> */.() -> kotlin.Unit origin=LAMBDA
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> ($receiver:kotlin.collections.LinkedHashMap<K1!, V1!> /* = java.util.LinkedHashMap<K1!, V1!> */) returnType:Unit flags:
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> ($receiver:kotlin.collections.LinkedHashMap<K1!, V1!> /* = java.util.LinkedHashMap<K1!, V1!> */) returnType:kotlin.Unit flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:kotlin.collections.LinkedHashMap<K1!, V1!> /* = java.util.LinkedHashMap<K1!, V1!> */ flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='<anonymous>() on LinkedHashMap<K1!, V1!> /* = LinkedHashMap<K1!, V1!> */: Unit'
|
||||
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public flags:
|
||||
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
|
||||
CALL 'put(K1!, V1!): V1?' type=V1? origin=null
|
||||
$this: GET_VAR 'this@<anonymous>: LinkedHashMap<(K1..K1?), (V1..V1?)>' type=kotlin.collections.LinkedHashMap<K1!, V1!> /* = java.util.LinkedHashMap<K1!, V1!> */ origin=null
|
||||
key: CALL '<get-first>(): K1' type=K1 origin=GET_PROPERTY
|
||||
@@ -40,4 +36,3 @@ FILE fqName:<root> fileName:/builtinMap.kt
|
||||
value: CALL '<get-second>(): V1' type=V1 origin=GET_PROPERTY
|
||||
$this: GET_VAR 'value-parameter pair: Pair<K1, V1>' type=kotlin.Pair<K1, V1> origin=null
|
||||
FUNCTION_REFERENCE '<anonymous>() on LinkedHashMap<K1!, V1!> /* = LinkedHashMap<K1!, V1!> */: Unit' type=kotlin.collections.LinkedHashMap<K1!, V1!> /* = java.util.LinkedHashMap<K1!, V1!> */.() -> kotlin.Unit origin=LAMBDA
|
||||
|
||||
|
||||
Generated
+15
@@ -15014,11 +15014,26 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/boxedLongEqualsLong.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableInt.kt")
|
||||
public void testIntEqualsNullableInt() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableInt.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableIntWithSmartCasts.kt")
|
||||
public void testIntEqualsNullableIntWithSmartCasts() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableIntWithSmartCasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("objectWithAsymmetricEqualsEqPrimitive.kt")
|
||||
public void testObjectWithAsymmetricEqualsEqPrimitive() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/objectWithAsymmetricEqualsEqPrimitive.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenIntAsNullableAny.kt")
|
||||
public void testWhenIntAsNullableAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenIntAsNullableAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenNullableBoxed.kt")
|
||||
public void testWhenNullableBoxed() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenNullableBoxed.kt");
|
||||
|
||||
+15
@@ -15014,11 +15014,26 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/boxedLongEqualsLong.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableInt.kt")
|
||||
public void testIntEqualsNullableInt() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableInt.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableIntWithSmartCasts.kt")
|
||||
public void testIntEqualsNullableIntWithSmartCasts() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableIntWithSmartCasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("objectWithAsymmetricEqualsEqPrimitive.kt")
|
||||
public void testObjectWithAsymmetricEqualsEqPrimitive() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/objectWithAsymmetricEqualsEqPrimitive.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenIntAsNullableAny.kt")
|
||||
public void testWhenIntAsNullableAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenIntAsNullableAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenNullableBoxed.kt")
|
||||
public void testWhenNullableBoxed() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenNullableBoxed.kt");
|
||||
|
||||
+15
@@ -15014,11 +15014,26 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/boxedLongEqualsLong.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableInt.kt")
|
||||
public void testIntEqualsNullableInt() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableInt.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableIntWithSmartCasts.kt")
|
||||
public void testIntEqualsNullableIntWithSmartCasts() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableIntWithSmartCasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("objectWithAsymmetricEqualsEqPrimitive.kt")
|
||||
public void testObjectWithAsymmetricEqualsEqPrimitive() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/objectWithAsymmetricEqualsEqPrimitive.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenIntAsNullableAny.kt")
|
||||
public void testWhenIntAsNullableAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenIntAsNullableAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenNullableBoxed.kt")
|
||||
public void testWhenNullableBoxed() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenNullableBoxed.kt");
|
||||
|
||||
+15
@@ -13279,11 +13279,26 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/boxedLongEqualsLong.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableInt.kt")
|
||||
public void testIntEqualsNullableInt() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableInt.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableIntWithSmartCasts.kt")
|
||||
public void testIntEqualsNullableIntWithSmartCasts() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableIntWithSmartCasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("objectWithAsymmetricEqualsEqPrimitive.kt")
|
||||
public void testObjectWithAsymmetricEqualsEqPrimitive() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/objectWithAsymmetricEqualsEqPrimitive.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenIntAsNullableAny.kt")
|
||||
public void testWhenIntAsNullableAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenIntAsNullableAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenNullableBoxed.kt")
|
||||
public void testWhenNullableBoxed() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenNullableBoxed.kt");
|
||||
|
||||
+15
@@ -14274,11 +14274,26 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/boxedLongEqualsLong.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableInt.kt")
|
||||
public void testIntEqualsNullableInt() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableInt.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intEqualsNullableIntWithSmartCasts.kt")
|
||||
public void testIntEqualsNullableIntWithSmartCasts() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/intEqualsNullableIntWithSmartCasts.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("objectWithAsymmetricEqualsEqPrimitive.kt")
|
||||
public void testObjectWithAsymmetricEqualsEqPrimitive() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/objectWithAsymmetricEqualsEqPrimitive.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenIntAsNullableAny.kt")
|
||||
public void testWhenIntAsNullableAny() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenIntAsNullableAny.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenNullableBoxed.kt")
|
||||
public void testWhenNullableBoxed() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/primitiveTypes/equalityWithObject/whenNullableBoxed.kt");
|
||||
|
||||
Reference in New Issue
Block a user