Generate intrinsic-based numeric comparison only for FP types

This commit is contained in:
Dmitry Petrov
2018-08-01 17:43:42 +03:00
parent cce9505e31
commit 1bfb75a51b
11 changed files with 156 additions and 33 deletions
@@ -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
@@ -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"
}
@@ -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"
}
@@ -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
View File
@@ -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
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");