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"
|
||||
)
|
||||
|
||||
|
||||
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),
|
||||
|
||||
|
||||
+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.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)
|
||||
|
||||
+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
|
||||
|
||||
fun test2() {
|
||||
|
||||
Reference in New Issue
Block a user