JVM IR: simplify chains of negations in if conditions.
Introduce lowering phase that turns !!exp -> exp for the boolean
'not' builtin. This makes sure that code such as
```
if (!!!!!booleanValue) {
doStuff()
}
```
generates only one branch.
This commit is contained in:
@@ -211,13 +211,18 @@ private val TailrecPhase = makeJvmPhase(
|
|||||||
description = "Handle tailrec calls"
|
description = "Handle tailrec calls"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
private val ToArrayPhase = makeJvmPhase(
|
private val ToArrayPhase = makeJvmPhase(
|
||||||
{ context, file -> ToArrayLowering(context).lower(file) },
|
{ context, file -> ToArrayLowering(context).lower(file) },
|
||||||
name = "ToArray",
|
name = "ToArray",
|
||||||
description = "Handle toArray functions"
|
description = "Handle toArray functions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val NegatedExpressionLowering = makeJvmPhase(
|
||||||
|
{ context, file -> NegatedExpressionLowering(context).lower(file) },
|
||||||
|
name = "NegatedExpression",
|
||||||
|
description = "Handle negated expressions"
|
||||||
|
)
|
||||||
|
|
||||||
object IrFileEndPhase : CompilerPhase<BackendContext, IrFile> {
|
object IrFileEndPhase : CompilerPhase<BackendContext, IrFile> {
|
||||||
override val name = "IrFileEnd"
|
override val name = "IrFileEnd"
|
||||||
override val description = "State at end of IrFile lowering"
|
override val description = "State at end of IrFile lowering"
|
||||||
@@ -268,6 +273,7 @@ val jvmPhases = listOf(
|
|||||||
|
|
||||||
TailrecPhase,
|
TailrecPhase,
|
||||||
ToArrayPhase,
|
ToArrayPhase,
|
||||||
|
NegatedExpressionLowering,
|
||||||
|
|
||||||
makePatchParentsPhase(3),
|
makePatchParentsPhase(3),
|
||||||
|
|
||||||
|
|||||||
+4
-8
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
|||||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicFunction
|
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicFunction
|
||||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.CrIrType
|
import org.jetbrains.kotlin.backend.jvm.lower.CrIrType
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.lower.NegatedExpressionLowering.Companion.isNegation
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.lower.NegatedExpressionLowering.Companion.negationArgument
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil.*
|
import org.jetbrains.kotlin.codegen.AsmUtil.*
|
||||||
@@ -19,7 +21,6 @@ import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
|
|||||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages
|
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages
|
||||||
import org.jetbrains.kotlin.codegen.inline.TypeParameterMappings
|
import org.jetbrains.kotlin.codegen.inline.TypeParameterMappings
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty
|
import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.Not
|
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq
|
import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump
|
import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump
|
||||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
|
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
|
||||||
@@ -645,16 +646,11 @@ class ExpressionCodegen(
|
|||||||
val elseBranch = branch is IrElseBranch
|
val elseBranch = branch is IrElseBranch
|
||||||
if (!elseBranch) {
|
if (!elseBranch) {
|
||||||
var jumpIfFalse = true
|
var jumpIfFalse = true
|
||||||
// TODO: there should be only one representation of the 'not' operator.
|
if (isNegation(condition, classCodegen.context)) {
|
||||||
if (condition is IrCall && (
|
|
||||||
condition.symbol == classCodegen.context.irBuiltIns.booleanNotSymbol ||
|
|
||||||
classCodegen.state.intrinsics.getIntrinsic(condition.symbol.descriptor) is Not
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
// Instead of materializing a negated value when used for control flow, flip the branch
|
// Instead of materializing a negated value when used for control flow, flip the branch
|
||||||
// targets instead. This significantly cuts down the amount of branches and loads of
|
// targets instead. This significantly cuts down the amount of branches and loads of
|
||||||
// const_0 and const_1 in the generated java bytecode.
|
// const_0 and const_1 in the generated java bytecode.
|
||||||
condition = condition.dispatchReceiver ?: condition.getValueArgument(0)!!
|
condition = negationArgument(condition as IrCall)
|
||||||
jumpIfFalse = false
|
jumpIfFalse = false
|
||||||
}
|
}
|
||||||
gen(condition, data).put(condition.asmType, mv)
|
gen(condition, data).put(condition.asmType, mv)
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
|
import org.jetbrains.kotlin.codegen.intrinsics.Not
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
|
// TODO: This lowering is currently JvmBackend specific because there are multiple
|
||||||
|
// definitions of the boolean 'not' operator. Once there is only the irBuiltins
|
||||||
|
// definition this lowering could be shared with other backends.
|
||||||
|
class NegatedExpressionLowering(val context: JvmBackendContext) : FileLoweringPass {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun isNegation(expression: IrExpression, context: JvmBackendContext) : Boolean {
|
||||||
|
// TODO: there should be only one representation of the 'not' operator.
|
||||||
|
return expression is IrCall &&
|
||||||
|
(expression.symbol == context.irBuiltIns.booleanNotSymbol ||
|
||||||
|
context.state.intrinsics.getIntrinsic(expression.symbol.descriptor) is Not)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun negationArgument(call: IrCall) : IrExpression {
|
||||||
|
// TODO: there should be only one representation of the 'not' operator.
|
||||||
|
// Once there is only the IR definition the negation argument will
|
||||||
|
// always be a value argument and this method can be removed.
|
||||||
|
return call.dispatchReceiver ?: call.getValueArgument(0)!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return if (isNegation(expression, context) && isNegation(negationArgument(expression), context))
|
||||||
|
negationArgument(negationArgument(expression) as IrCall)
|
||||||
|
else
|
||||||
|
expression
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val two = 2
|
val two = 2
|
||||||
|
|
||||||
fun test2() {
|
fun test2() {
|
||||||
|
|||||||
Reference in New Issue
Block a user