From 05ff2b12923960374d79d0ffa4bda8195cd63c6c Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Fri, 12 Feb 2021 12:45:48 +0100 Subject: [PATCH] [JVM_IR] Extend when to switch translation to deal with nested ors. FIR translates: ``` when (x) { 1, 2, 3 -> action else -> other_action } ``` to an IR structure with nested ors: ``` if ((x == 1 || x == 2) || (x == 3)) action else other_action ``` This change allows that to turn into switch instructions in the JVM backend. --- .../codegen/FirBytecodeTextTestGenerated.java | 6 ++++++ .../backend/jvm/codegen/SwitchGenerator.kt | 17 ++++++++++++++--- .../when/switchOptimizationDuplicates.kt | 1 - .../whenEnumOptimization/bigEnum.kt | 1 - .../whenEnumOptimization/duplicatingItems.kt | 1 - .../whenEnumOptimization/expression.kt | 1 - .../manyWhensWithinClass.kt | 1 - .../whenEnumOptimization/nullability.kt | 1 - .../bytecodeText/whenEnumOptimization/whenOr.kt | 11 +++++++++++ .../whenEnumOptimization/withoutElse.kt | 1 - .../whenStringOptimization/duplicatingItems.kt | 1 - .../whenStringOptimization/expression.kt | 1 - .../inlineStringConstInsideWhen.kt | 1 - .../whenStringOptimization/nullability.kt | 1 - .../whenStringOptimization/sameHashCode.kt | 1 - .../whenStringOptimization/statement.kt | 1 - .../codegen/BytecodeTextTestGenerated.java | 6 ++++++ .../codegen/IrBytecodeTextTestGenerated.java | 6 ++++++ 18 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeText/whenEnumOptimization/whenOr.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index 8dc66fd9614..2c1a4d39e5c 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -5574,6 +5574,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/subjectAny.kt"); } + @Test + @TestMetadata("whenOr.kt") + public void testWhenOr() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/whenOr.kt"); + } + @Test @TestMetadata("withoutElse.kt") public void testWithoutElse() throws Exception { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/SwitchGenerator.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/SwitchGenerator.kt index c7daf2809d6..9b39d0dc7e7 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/SwitchGenerator.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/SwitchGenerator.kt @@ -237,11 +237,13 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf // action // } // + // fir2ir lowers the same to an or sequence: + // + // if (((subject == a) || (subject == b)) || (subject = c)) action + // // @return true if the conditions are equality checks of constants. private fun matchConditions(condition: IrExpression): ArrayList? { - if (condition is IrCall) { - return arrayListOf(condition) - } else if (condition is IrWhen && condition.origin == IrStatementOrigin.WHEN_COMMA) { + if (condition is IrWhen && condition.origin == IrStatementOrigin.WHEN_COMMA) { assert(condition.type.isBoolean()) { "WHEN_COMMA should always be a Boolean: ${condition.dump()}" } val candidates = ArrayList() @@ -268,6 +270,15 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf } return if (candidates.isNotEmpty()) candidates else return null + } else if (condition is IrCall && condition.symbol == codegen.context.irBuiltIns.ororSymbol) { + val candidates = ArrayList() + for (i in 0 until condition.valueArgumentsCount) { + val argument = condition.getValueArgument(i)!! + candidates += matchConditions(argument) ?: return null + } + return if (candidates.isNotEmpty()) candidates else return null + } else if (condition is IrCall) { + return arrayListOf(condition) } return null diff --git a/compiler/testData/codegen/bytecodeText/when/switchOptimizationDuplicates.kt b/compiler/testData/codegen/bytecodeText/when/switchOptimizationDuplicates.kt index 34f6596cb38..a6438315fb7 100644 --- a/compiler/testData/codegen/bytecodeText/when/switchOptimizationDuplicates.kt +++ b/compiler/testData/codegen/bytecodeText/when/switchOptimizationDuplicates.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun foo(x: Int): Int { return when (x) { 1, 1, 2 -> 1001 diff --git a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/bigEnum.kt b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/bigEnum.kt index 0af7d4df73c..230eae422bb 100644 --- a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/bigEnum.kt +++ b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/bigEnum.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR import kotlin.test.assertEquals enum class BigEnum { diff --git a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/duplicatingItems.kt b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/duplicatingItems.kt index a2131007dc3..87e9d97c05a 100644 --- a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/duplicatingItems.kt +++ b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/duplicatingItems.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR import kotlin.test.assertEquals enum class Season { diff --git a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/expression.kt b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/expression.kt index 39424a42746..a1c4bc676c5 100644 --- a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/expression.kt +++ b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/expression.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR import kotlin.test.assertEquals enum class Season { diff --git a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/manyWhensWithinClass.kt b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/manyWhensWithinClass.kt index 07dcac76ee5..34dad145a32 100644 --- a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/manyWhensWithinClass.kt +++ b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/manyWhensWithinClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR package abc.foo enum class Season { diff --git a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/nullability.kt b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/nullability.kt index 47dbc05e968..4a4a6cc6340 100644 --- a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/nullability.kt +++ b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/nullability.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR enum class Season { WINTER, SPRING, diff --git a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/whenOr.kt b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/whenOr.kt new file mode 100644 index 00000000000..7814ae5c799 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/whenOr.kt @@ -0,0 +1,11 @@ +// IGNORE_BACKEND: JVM + +fun test(x: Int): String { + when { + x == 1 || x == 3 || x == 5 -> "135" + x == 2 || x == 4 || x == 6 -> "246" + else -> "other" + } +} + +// 1 TABLESWITCH diff --git a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/withoutElse.kt b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/withoutElse.kt index c89597748a1..09e8377c0b4 100644 --- a/compiler/testData/codegen/bytecodeText/whenEnumOptimization/withoutElse.kt +++ b/compiler/testData/codegen/bytecodeText/whenEnumOptimization/withoutElse.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR import kotlin.test.assertEquals enum class Season { diff --git a/compiler/testData/codegen/bytecodeText/whenStringOptimization/duplicatingItems.kt b/compiler/testData/codegen/bytecodeText/whenStringOptimization/duplicatingItems.kt index 21d45ba9699..15a2ebde392 100644 --- a/compiler/testData/codegen/bytecodeText/whenStringOptimization/duplicatingItems.kt +++ b/compiler/testData/codegen/bytecodeText/whenStringOptimization/duplicatingItems.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR import kotlin.test.assertEquals fun foo(x : String) : String { diff --git a/compiler/testData/codegen/bytecodeText/whenStringOptimization/expression.kt b/compiler/testData/codegen/bytecodeText/whenStringOptimization/expression.kt index 083d03e5351..4831cfb6df9 100644 --- a/compiler/testData/codegen/bytecodeText/whenStringOptimization/expression.kt +++ b/compiler/testData/codegen/bytecodeText/whenStringOptimization/expression.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun foo(x : String) : String { return when (x) { "abc", "cde" -> "abc_cde" diff --git a/compiler/testData/codegen/bytecodeText/whenStringOptimization/inlineStringConstInsideWhen.kt b/compiler/testData/codegen/bytecodeText/whenStringOptimization/inlineStringConstInsideWhen.kt index d55753d04cc..8563b273642 100644 --- a/compiler/testData/codegen/bytecodeText/whenStringOptimization/inlineStringConstInsideWhen.kt +++ b/compiler/testData/codegen/bytecodeText/whenStringOptimization/inlineStringConstInsideWhen.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR const val y = "cde" fun foo(x : String) : String { diff --git a/compiler/testData/codegen/bytecodeText/whenStringOptimization/nullability.kt b/compiler/testData/codegen/bytecodeText/whenStringOptimization/nullability.kt index 3461ba0bb80..52905d3a900 100644 --- a/compiler/testData/codegen/bytecodeText/whenStringOptimization/nullability.kt +++ b/compiler/testData/codegen/bytecodeText/whenStringOptimization/nullability.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun foo1(x : String?) : String { when (x) { "abc", "cde" -> return "abc_cde" diff --git a/compiler/testData/codegen/bytecodeText/whenStringOptimization/sameHashCode.kt b/compiler/testData/codegen/bytecodeText/whenStringOptimization/sameHashCode.kt index 2f4e7a773b8..f5f0d55b265 100644 --- a/compiler/testData/codegen/bytecodeText/whenStringOptimization/sameHashCode.kt +++ b/compiler/testData/codegen/bytecodeText/whenStringOptimization/sameHashCode.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun foo(x : String) : String { assert("abz]".hashCode() == "aby|".hashCode()) diff --git a/compiler/testData/codegen/bytecodeText/whenStringOptimization/statement.kt b/compiler/testData/codegen/bytecodeText/whenStringOptimization/statement.kt index bf3aa834ba4..7e07e9961d7 100644 --- a/compiler/testData/codegen/bytecodeText/whenStringOptimization/statement.kt +++ b/compiler/testData/codegen/bytecodeText/whenStringOptimization/statement.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun foo1(x : String) : String { when (x) { "abc", "cde" -> return "abc_cde" diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java index 2f284b56585..ae3c56d5cfd 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java @@ -5442,6 +5442,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/subjectAny.kt"); } + @Test + @TestMetadata("whenOr.kt") + public void testWhenOr() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/whenOr.kt"); + } + @Test @TestMetadata("withoutElse.kt") public void testWithoutElse() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index db61e2845a4..05696042ddd 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -5574,6 +5574,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/subjectAny.kt"); } + @Test + @TestMetadata("whenOr.kt") + public void testWhenOr() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/whenEnumOptimization/whenOr.kt"); + } + @Test @TestMetadata("withoutElse.kt") public void testWithoutElse() throws Exception {