JVM_IR KT-42010 use IINC for postfix int increment/decrement

This commit is contained in:
Dmitry Petrov
2021-08-26 16:09:39 +03:00
parent ef72413da9
commit dd98f72fd7
8 changed files with 131 additions and 2 deletions
@@ -3941,6 +3941,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
public void testJavaPrimitiveType() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/intrinsics/javaPrimitiveType.kt");
}
@Test
@TestMetadata("postfixIncrDecr.kt")
public void testPostfixIncrDecr() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/intrinsics/postfixIncrDecr.kt");
}
}
@Nested
@@ -811,7 +811,6 @@ class JvmSymbols(
addFunction("equals", irBuiltIns.booleanType, isStatic = true).apply {
addValueParameter("a", arrayType)
addValueParameter("b", arrayType)
}
}
@@ -856,6 +855,19 @@ class JvmSymbols(
val remainderUnsignedLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("remainderUnsigned")
val toUnsignedStringLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("toUnsignedString")
val intPostfixIncr = createPostfixIncrDecrFun("<int++>", irBuiltIns.intType)
val intPostfixDecr = createPostfixIncrDecrFun("<int-->", irBuiltIns.intType)
private fun createPostfixIncrDecrFun(intrinsicName: String, type: IrType): IrSimpleFunctionSymbol =
irFactory.buildFun {
name = Name.special(intrinsicName)
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
}.apply {
parent = kotlinJvmInternalPackage
addValueParameter("value", type)
returnType = type
}.symbol
private fun createJavaPrimitiveClass(fqName: FqName, type: IrType): IrClassSymbol = createClass(fqName) { klass ->
klass.addFunction("compareUnsigned", irBuiltIns.intType, isStatic = true).apply {
addValueParameter("x", type)
@@ -87,7 +87,9 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
symbols.throwTypeCastException.toKey()!! to ThrowException(Type.getObjectType("kotlin/TypeCastException")),
symbols.throwUnsupportedOperationException.toKey()!! to ThrowException(Type.getObjectType("java/lang/UnsupportedOperationException")),
symbols.throwKotlinNothingValueException.toKey()!! to ThrowKotlinNothingValueException,
symbols.jvmIndyIntrinsic.toKey()!! to JvmInvokeDynamic
symbols.jvmIndyIntrinsic.toKey()!! to JvmInvokeDynamic,
symbols.intPostfixIncr.toKey()!! to PostfixIinc(1),
symbols.intPostfixDecr.toKey()!! to PostfixIinc(-1)
) +
numberConversionMethods() +
unaryFunForPrimitives("plus", UnaryPlus) +
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.org.objectweb.asm.Type
class PostfixIinc(private val delta: Int) : IntrinsicMethod() {
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
val argument = expression.getValueArgument(0) as? IrGetValue
?: error("IrGetValue expected: ${expression.dump()}")
val varIndex = codegen.frameMap.getIndex(argument.symbol)
if (varIndex == -1)
error("Unmapped variable: ${argument.render()}")
argument.accept(codegen, data).materialize()
codegen.mv.iinc(varIndex, delta)
return MaterialValue(codegen, Type.INT_TYPE, argument.type)
}
}
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.util.OperatorNameConventions
internal val jvmOptimizationLoweringPhase = makeIrFilePhase(
::JvmOptimizationLowering,
@@ -405,11 +406,47 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass
}
}
if (expression.origin == IrStatementOrigin.POSTFIX_DECR || expression.origin == IrStatementOrigin.POSTFIX_INCR) {
expression.rewritePostfixIncrDecr()?.let { return it }
}
expression.transformChildren(this, data)
removeUnnecessaryTemporaryVariables(expression.statements)
return expression
}
private fun IrContainerExpression.rewritePostfixIncrDecr(): IrCall? {
return when (origin) {
IrStatementOrigin.POSTFIX_INCR, IrStatementOrigin.POSTFIX_DECR -> {
val tmpVar = this.statements[0] as? IrVariable ?: return null
val getIncrVar = tmpVar.initializer as? IrGetValue ?: return null
if (!getIncrVar.type.isInt()) return null
val setVar = this.statements[1] as? IrSetValue ?: return null
if (setVar.symbol != getIncrVar.symbol) return null
val setVarValue = setVar.value as? IrCall ?: return null
val calleeName = setVarValue.symbol.owner.name
if (calleeName != OperatorNameConventions.INC && calleeName != OperatorNameConventions.DEC) return null
val calleeArg = setVarValue.dispatchReceiver as? IrGetValue ?: return null
if (calleeArg.symbol != tmpVar.symbol) return null
val getTmpVar = this.statements[2] as? IrGetValue ?: return null
if (getTmpVar.symbol != tmpVar.symbol) return null
val intrinsicSymbol =
if (calleeName == OperatorNameConventions.INC)
context.ir.symbols.intPostfixIncr
else
context.ir.symbols.intPostfixDecr
return IrCallImpl.fromSymbolOwner(this.startOffset, this.endOffset, intrinsicSymbol)
.apply { putValueArgument(0, getIncrVar) }
}
else ->
null
}
}
override fun visitGetValue(expression: IrGetValue, data: IrClass?): IrExpression {
// Replace IrGetValue of an immutable temporary variable with a constant
// initializer with the constant initializer.
@@ -0,0 +1,34 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun use(i: Int) {}
fun testPostfixIncr0() {
var k = 0
k++
use(k)
}
fun testPostfixIncr1() {
var k = 0
val t = k++
use(k)
use(t)
}
fun testPostfixDecr0() {
var k = 0
k--
use(k)
}
fun testPostfixDecr1() {
var k = 0
val t = k--
use(k)
use(t)
}
// 6 ISTORE
// 8 ILOAD
// 0 ICONST_1
// 4 IINC
@@ -3797,6 +3797,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
public void testJavaPrimitiveType() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/intrinsics/javaPrimitiveType.kt");
}
@Test
@TestMetadata("postfixIncrDecr.kt")
public void testPostfixIncrDecr() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/intrinsics/postfixIncrDecr.kt");
}
}
@Nested
@@ -3941,6 +3941,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
public void testJavaPrimitiveType() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/intrinsics/javaPrimitiveType.kt");
}
@Test
@TestMetadata("postfixIncrDecr.kt")
public void testPostfixIncrDecr() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/intrinsics/postfixIncrDecr.kt");
}
}
@Nested