Optimize JVM byte code generation for conditional conjunction
Implement an intrinsic method for boolean.and operation, and replace ANDAND condition with a call to such intrinsic method.
This commit is contained in:
committed by
max-kammerer
parent
53493657ff
commit
4b99d85322
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
|
||||
object AndAnd : IntrinsicMethod() {
|
||||
|
||||
private class BooleanConjunction(val arg0: IrExpression, val arg1: IrExpression, val codegen: ExpressionCodegen, val data: BlockInfo) : BooleanValue(codegen.mv) {
|
||||
|
||||
override fun jumpIfFalse(target: Label) {
|
||||
arg0.accept(codegen, data).coerceToBoolean().jumpIfFalse(target)
|
||||
arg1.accept(codegen, data).coerceToBoolean().jumpIfFalse(target)
|
||||
}
|
||||
|
||||
override fun jumpIfTrue(target: Label) {
|
||||
val stayLabel = Label()
|
||||
arg0.accept(codegen, data).coerceToBoolean().jumpIfFalse(stayLabel)
|
||||
arg1.accept(codegen, data).coerceToBoolean().jumpIfTrue(target)
|
||||
mv.visitLabel(stayLabel)
|
||||
}
|
||||
}
|
||||
|
||||
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
|
||||
val (left, right) = expression.receiverAndArgs()
|
||||
return BooleanConjunction(left, right, codegen, data)
|
||||
}
|
||||
}
|
||||
+10
@@ -31,6 +31,10 @@ class IrIntrinsicMethods(irBuiltIns: IrBuiltIns) {
|
||||
|
||||
val intrinsics = IntrinsicMethods()
|
||||
|
||||
val andandSymbol = irBuiltIns.run { defineOperator(OperatorNames.ANDAND, bool, listOf(bool, bool)) }
|
||||
|
||||
private val andand = andandSymbol.descriptor
|
||||
|
||||
private val irMapping = hashMapOf<CallableMemberDescriptor, IntrinsicMethod>()
|
||||
|
||||
private fun createPrimitiveComparisonIntrinsics(typeToIrFun: Map<SimpleType, IrSimpleFunctionSymbol>, operator: KtSingleValueToken) {
|
||||
@@ -55,6 +59,8 @@ class IrIntrinsicMethods(irBuiltIns: IrBuiltIns) {
|
||||
irMapping[irBuiltIns.noWhenBranchMatchedException] = IrNoWhenBranchMatchedException()
|
||||
irMapping[irBuiltIns.illegalArgumentException] = IrIllegalArgumentException()
|
||||
irMapping[irBuiltIns.throwNpe] = ThrowNPE()
|
||||
|
||||
irMapping[andand] = AndAnd
|
||||
}
|
||||
|
||||
fun getIntrinsic(descriptor: CallableMemberDescriptor): IntrinsicMethod? {
|
||||
@@ -64,4 +70,8 @@ class IrIntrinsicMethods(irBuiltIns: IrBuiltIns) {
|
||||
}
|
||||
return irMapping[descriptor.original]
|
||||
}
|
||||
|
||||
private object OperatorNames {
|
||||
const val ANDAND = "ANDAND"
|
||||
}
|
||||
}
|
||||
|
||||
+22
-4
@@ -15,13 +15,12 @@ import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.types.isBoolean
|
||||
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.coerceToUnitIfNeeded
|
||||
import org.jetbrains.kotlin.ir.util.isFalseConst
|
||||
import org.jetbrains.kotlin.ir.util.isNullConst
|
||||
import org.jetbrains.kotlin.ir.util.isTrueConst
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
@@ -102,6 +101,25 @@ class JvmBuiltinOptimizationLowering(val context: JvmBackendContext) : FileLower
|
||||
expression.branches.removeIf() {
|
||||
it.condition.isFalseConst() && isCompilerGenerated
|
||||
}
|
||||
if (expression.origin == IrStatementOrigin.ANDAND) {
|
||||
assert(expression.type.isBoolean()
|
||||
&& expression.branches.size == 2
|
||||
&& expression.branches[1].condition.isTrueConst()
|
||||
&& expression.branches[1].result.isFalseConst()) {
|
||||
"ANDAND condition should have an 'if true then false' body on its second branch. " +
|
||||
"Failing expression: ${expression.dump()}"
|
||||
}
|
||||
// Replace conjunction condition with intrinsic "and" function call
|
||||
return IrCallImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
context.irBuiltIns.booleanType,
|
||||
context.irIntrinsics.andandSymbol
|
||||
).apply {
|
||||
dispatchReceiver = expression.branches[0].condition
|
||||
putValueArgument(0, expression.branches[0].result)
|
||||
}
|
||||
}
|
||||
// If the only condition that is left has a constant true condition remove the
|
||||
// when in favor of the result. If there are no conditions left, remove the when
|
||||
// entirely and replace it with an empty block.
|
||||
|
||||
Reference in New Issue
Block a user