JVM_IR KT-50074 generate tableswitch for literal string subject of when expression

This commit is contained in:
Xin Wang
2022-01-19 10:25:34 +08:00
committed by TeamCityServer
parent 69bb2587eb
commit 56e5db9f0e
2 changed files with 32 additions and 9 deletions
@@ -65,7 +65,7 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
return when {
subject is IrCall && subject.isCoerceFromUIntToInt() ->
generateUIntSwitch(subject.getValueArgument(0)!! as? IrGetValue, calls, callToLabels, expressionToLabels, elseExpression)
subject is IrGetValue ->
subject is IrGetValue || subject is IrConst<*> && subject.type.isString() -> // also generate tableswitch for literal string subject
generatePrimitiveSwitch(subject, calls, callToLabels, expressionToLabels, elseExpression)
else ->
null
@@ -111,7 +111,7 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
}
private fun generatePrimitiveSwitch(
subject: IrGetValue,
subject: IrExpression,
conditions: List<IrCall>,
callToLabels: ArrayList<CallToLabel>,
expressionToLabels: ArrayList<ExpressionToLabel>,
@@ -121,7 +121,7 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
if (!areConstantComparisons(conditions)) return null
return when {
areConstIntComparisons(conditions) -> {
subject is IrGetValue && areConstIntComparisons(conditions) -> {
val cases = extractSwitchCasesAndFilterUnreachableLabels(callToLabels, expressionToLabels)
IntSwitch(
subject,
@@ -162,9 +162,23 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
}
private fun areConstantComparisons(conditions: List<IrCall>): Boolean {
fun isValidIrGetValueTypeLHS(): Boolean {
val lhs = conditions.map {
it.takeIf { it.symbol == codegen.context.irBuiltIns.eqeqSymbol }?.getValueArgument(0) as? IrGetValue
}
return lhs.all { it != null && it.symbol == lhs[0]!!.symbol }
}
fun isValidIrConstTypeLHS(): Boolean {
val lhs = conditions.map {
it.takeIf { it.symbol == codegen.context.irBuiltIns.eqeqSymbol }?.getValueArgument(0) as? IrConst<*>
}
return lhs.all { it != null && it.value == lhs[0]!!.value }
}
// All conditions are equality checks && all LHS refer to the same tmp variable.
val lhs = conditions.map { it.takeIf { it.symbol == codegen.context.irBuiltIns.eqeqSymbol }?.getValueArgument(0) as? IrGetValue }
if (lhs.any { it == null || it.symbol != lhs[0]!!.symbol })
if (!isValidIrGetValueTypeLHS() && !isValidIrConstTypeLHS())
return false
// All RHS are constants
@@ -190,7 +204,7 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
subjectTypePredicate: (IrType) -> Boolean,
irConstPredicate: (IrConst<*>) -> Boolean
): Boolean {
val lhs = conditions.map { it.getValueArgument(0) as IrGetValue }
val lhs = conditions.map { it.getValueArgument(0) as? IrGetValue ?: it.getValueArgument(0) as IrConst<*> }
if (lhs.any { !subjectTypePredicate(it.type) })
return false
@@ -286,7 +300,7 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
}
abstract inner class Switch(
val subject: IrGetValue,
val subject: IrExpression,
val elseExpression: IrExpression?,
val expressionToLabels: ArrayList<ExpressionToLabel>
) {
@@ -427,7 +441,7 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
// A tableswitch or lookupswitch is then used for the hash code lookup.
inner class StringSwitch(
subject: IrGetValue,
subject: IrExpression,
elseExpression: IrExpression?,
expressionToLabels: ArrayList<ExpressionToLabel>,
private val cases: List<ValueToLabel>
@@ -457,8 +471,12 @@ class SwitchGenerator(private val expression: IrWhen, private val data: BlockInf
// see:
// box/when/stringOptimization/enhancedNullability.kt
// box/when/stringOptimization/flexibleNullability.kt
//
// Generate "optimized" version for literal string subject to avoid performance regression
// see:
// box/unit/nullableUnitInWhen3.kt
override fun shouldOptimize() =
hashAndSwitchLabels.size > 2 ||
hashAndSwitchLabels.size > (if (subject is IrConst<*>) 0 else 2) ||
subject.type.hasAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) && hashAndSwitchLabels.isNotEmpty()
override fun genSwitch() {
@@ -10,3 +10,8 @@ fun box(): String {
return if (x == null) "OK" else "Fail"
}
// CHECK_BYTECODE_TEXT
// JVM_IR_TEMPLATES
// 0 Intrinsics.areEqual
// 1 TABLESWITCH