JVM_IR more aggressive if-null expressions fusion
Assume that changing a return type from T to T? is not a binary-compatible change.
This commit is contained in:
committed by
teamcityserver
parent
6f0bf766f2
commit
02d8c7527e
+12
@@ -1850,6 +1850,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallWithElvisAndEnhancedNullability.kt")
|
||||
public void testSafeCallWithElvisAndEnhancedNullability() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisAndEnhancedNullability.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
|
||||
+6
@@ -730,6 +730,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("severalInlines.kt")
|
||||
public void testSeveralInlines() throws Exception {
|
||||
|
||||
+21
-18
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.util.fileOrNull
|
||||
import org.jetbrains.kotlin.ir.util.isTrivial
|
||||
import org.jetbrains.kotlin.ir.util.shallowCopy
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
@@ -33,10 +32,10 @@ val ifNullExpressionsFusionPhase =
|
||||
|
||||
class IfNullExpressionsFusionLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(Transformer(irFile))
|
||||
irFile.transformChildrenVoid(Transformer())
|
||||
}
|
||||
|
||||
private inner class Transformer(private val currentFile: IrFile) : IrElementTransformerVoid() {
|
||||
private inner class Transformer : IrElementTransformerVoid() {
|
||||
override fun visitBlock(expression: IrBlock): IrExpression =
|
||||
visitExpression(expression.fuseIfNull())
|
||||
|
||||
@@ -131,30 +130,34 @@ class IfNullExpressionsFusionLowering(val context: CommonBackendContext) : FileL
|
||||
|
||||
private fun IrExpression.isNull(knownVariableSymbol: IrVariableSymbol, knownVariableIsNull: Boolean): Boolean? =
|
||||
when (this) {
|
||||
is IrConst<*> -> value == null
|
||||
is IrGetValue -> when {
|
||||
symbol == knownVariableSymbol -> knownVariableIsNull
|
||||
!type.isNullable() -> false
|
||||
else -> null
|
||||
}
|
||||
is IrConst<*> ->
|
||||
value == null
|
||||
is IrGetValue ->
|
||||
when {
|
||||
symbol == knownVariableSymbol -> knownVariableIsNull
|
||||
!type.isNullable() -> false
|
||||
else -> null
|
||||
}
|
||||
is IrConstructorCall,
|
||||
is IrGetSingletonValue,
|
||||
is IrFunctionExpression,
|
||||
is IrCallableReference<*>,
|
||||
is IrClassReference,
|
||||
is IrGetClass -> false
|
||||
is IrGetClass ->
|
||||
false
|
||||
is IrCall ->
|
||||
if (!type.isNullable() && symbol.owner.isStable()) false else null
|
||||
if (!type.isNullable()) false else null
|
||||
is IrGetField ->
|
||||
if (!type.isNullable() && symbol.owner.isStable()) false else null
|
||||
is IrBlock ->
|
||||
(statements.singleOrNull() as IrExpression?)?.takeIf { it.type == type }?.isNull(knownVariableSymbol, knownVariableIsNull)
|
||||
if (!type.isNullable()) false else null
|
||||
is IrBlock -> {
|
||||
val singleExpr = statements.singleOrNull()
|
||||
if (singleExpr is IrExpression && singleExpr.type == type)
|
||||
singleExpr.isNull(knownVariableSymbol, knownVariableIsNull)
|
||||
else
|
||||
null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
// TODO make calls to the declarations within the same module "stable"
|
||||
private fun IrDeclaration.isStable() =
|
||||
fileOrNull == currentFile
|
||||
}
|
||||
|
||||
private class IfNullExpr(
|
||||
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
// FILE: safeCallWithElvisAndEnhancedNullability.kt
|
||||
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun check(a : A?) : Int {
|
||||
return a?.y?.x ?: (a?.x ?: 3)
|
||||
}
|
||||
|
||||
fun checkLeftAssoc(a : A?) : Int {
|
||||
return (a?.y?.x ?: a?.x) ?: 3
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
val a1 = A(2, A(1, null))
|
||||
val a2 = A(2, null)
|
||||
val a3 = null
|
||||
|
||||
assertEquals(1, check(a1))
|
||||
assertEquals(2, check(a2))
|
||||
assertEquals(3, check(a3))
|
||||
|
||||
assertEquals(1, checkLeftAssoc(a1))
|
||||
assertEquals(2, checkLeftAssoc(a2))
|
||||
assertEquals(3, checkLeftAssoc(a3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
// FILE: A.java
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class A {
|
||||
private Integer x;
|
||||
private A y;
|
||||
|
||||
public A(Integer x, A y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Integer getX() { return x; }
|
||||
|
||||
@Nullable
|
||||
public A getY() { return y; }
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
// MODULE: lib
|
||||
// FILE: a.kt
|
||||
class A(val x : Int, val y : A?)
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: safeCallWithElvisMultipleFiles.kt
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun check(a : A?) : Int {
|
||||
return a?.y?.x ?: (a?.x ?: 3)
|
||||
}
|
||||
|
||||
fun checkLeftAssoc(a : A?) : Int {
|
||||
return (a?.y?.x ?: a?.x) ?: 3
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
val a1 = A(2, A(1, null))
|
||||
val a2 = A(2, null)
|
||||
val a3 = null
|
||||
|
||||
assertEquals(1, check(a1))
|
||||
assertEquals(2, check(a2))
|
||||
assertEquals(3, check(a3))
|
||||
|
||||
assertEquals(1, checkLeftAssoc(a1))
|
||||
assertEquals(2, checkLeftAssoc(a2))
|
||||
assertEquals(3, checkLeftAssoc(a3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
// MODULE: lib
|
||||
// FILE: a.kt
|
||||
class A(val x : Int, val y : A?)
|
||||
|
||||
// MODULE: main(lib)
|
||||
// FILE: main.kt
|
||||
fun check(a : A?) : Int {
|
||||
return a?.y?.x ?: (a?.x ?: 3)
|
||||
}
|
||||
|
||||
// 0 valueOf
|
||||
// 0 Value\s\(\)
|
||||
|
||||
// JVM_TEMPLATES:
|
||||
// 0 ACONST_NULL
|
||||
|
||||
// JVM_IR_TEMPLATES:
|
||||
// 1 ACONST_NULL
|
||||
+12
@@ -1760,6 +1760,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallWithElvisAndEnhancedNullability.kt")
|
||||
public void testSafeCallWithElvisAndEnhancedNullability() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisAndEnhancedNullability.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
|
||||
+6
@@ -724,6 +724,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("severalInlines.kt")
|
||||
public void testSeveralInlines() throws Exception {
|
||||
|
||||
+12
@@ -1850,6 +1850,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallWithElvisAndEnhancedNullability.kt")
|
||||
public void testSafeCallWithElvisAndEnhancedNullability() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisAndEnhancedNullability.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
|
||||
+6
@@ -730,6 +730,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
|
||||
runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("severalInlines.kt")
|
||||
public void testSeveralInlines() throws Exception {
|
||||
|
||||
+10
@@ -1555,6 +1555,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallWithElvisAndEnhancedNullability.kt")
|
||||
public void testSafeCallWithElvisAndEnhancedNullability() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisAndEnhancedNullability.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/simple.kt");
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+5
@@ -1030,6 +1030,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/simple.kt");
|
||||
|
||||
Generated
+5
@@ -1030,6 +1030,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/simple.kt");
|
||||
|
||||
Generated
+5
@@ -1030,6 +1030,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/simple.kt");
|
||||
|
||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+5
@@ -900,6 +900,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvis.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCallWithElvisMultipleFiles.kt")
|
||||
public void testSafeCallWithElvisMultipleFiles() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/safeCallWithElvisMultipleFiles.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/boxingOptimization/simple.kt");
|
||||
|
||||
Reference in New Issue
Block a user