diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLoweringPhases.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLoweringPhases.kt index 06c2c2f079a..49e18ca5629 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLoweringPhases.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLoweringPhases.kt @@ -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 { 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), diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index f373df8214e..829bc6764ed 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -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) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/NegatedExpressionLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/NegatedExpressionLowering.kt new file mode 100644 index 00000000000..bd28b1b55ee --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/NegatedExpressionLowering.kt @@ -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 + } + }) + } + +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/lazyCodegen/negateVarChain.kt b/compiler/testData/codegen/bytecodeText/lazyCodegen/negateVarChain.kt index 12a68c1e1f2..a618b0b1b23 100644 --- a/compiler/testData/codegen/bytecodeText/lazyCodegen/negateVarChain.kt +++ b/compiler/testData/codegen/bytecodeText/lazyCodegen/negateVarChain.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR val two = 2 fun test2() {