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:
Mads Ager
2019-01-03 11:05:13 +01:00
committed by max-kammerer
parent 90c787e102
commit 57489febf0
4 changed files with 61 additions and 10 deletions
@@ -211,13 +211,18 @@ private val TailrecPhase = makeJvmPhase(
description = "Handle tailrec calls"
)
private val ToArrayPhase = makeJvmPhase(
{ context, file -> ToArrayLowering(context).lower(file) },
name = "ToArray",
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> {
override val name = "IrFileEnd"
override val description = "State at end of IrFile lowering"
@@ -268,6 +273,7 @@ val jvmPhases = listOf(
TailrecPhase,
ToArrayPhase,
NegatedExpressionLowering,
makePatchParentsPhase(3),
@@ -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.IrIntrinsicMethods
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.codegen.*
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.TypeParameterMappings
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.fixStackAndJump
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
@@ -645,16 +646,11 @@ class ExpressionCodegen(
val elseBranch = branch is IrElseBranch
if (!elseBranch) {
var jumpIfFalse = true
// TODO: there should be only one representation of the 'not' operator.
if (condition is IrCall && (
condition.symbol == classCodegen.context.irBuiltIns.booleanNotSymbol ||
classCodegen.state.intrinsics.getIntrinsic(condition.symbol.descriptor) is Not
)
) {
if (isNegation(condition, classCodegen.context)) {
// 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
// const_0 and const_1 in the generated java bytecode.
condition = condition.dispatchReceiver ?: condition.getValueArgument(0)!!
condition = negationArgument(condition as IrCall)
jumpIfFalse = false
}
gen(condition, data).put(condition.asmType, mv)
@@ -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
fun test2() {