JVM_IR move increment intrinsic handling to JvmOptimizationLowering
This commit is contained in:
+27
-86
@@ -780,80 +780,17 @@ class ExpressionCodegen(
|
|||||||
throw AssertionError("Non-mapped local declaration: ${irSymbol.owner.dump()}\n in ${irFunction.dump()}")
|
throw AssertionError("Non-mapped local declaration: ${irSymbol.owner.dump()}\n in ${irFunction.dump()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handlePlusMinus(expression: IrSetValue, value: IrExpression?, isMinus: Boolean): Boolean {
|
|
||||||
if (value is IrConst<*> && value.kind == IrConstKind.Int) {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
val delta = (value as IrConst<Int>).value
|
|
||||||
val upperBound = Byte.MAX_VALUE.toInt() + (if (isMinus) 1 else 0)
|
|
||||||
val lowerBound = Byte.MIN_VALUE.toInt() + (if (isMinus) 1 else 0)
|
|
||||||
if (delta in lowerBound..upperBound) {
|
|
||||||
expression.markLineNumber(startOffset = true)
|
|
||||||
mv.iinc(findLocalIndex(expression.symbol), if (isMinus) -delta else delta)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hasSameLineNumber(element0: IrElement, element1: IrElement): Boolean =
|
|
||||||
getLineNumberForOffset(element0.startOffset) == getLineNumberForOffset(element1.startOffset)
|
|
||||||
|
|
||||||
// Use iinc for all for the set var int special cases where we can.
|
|
||||||
// Be careful to make sure that debugging behavior does not change and
|
|
||||||
// only perform the optimization if that can be done without losing
|
|
||||||
// line number information.
|
|
||||||
private fun handleIntVariableSpecialCases(expression: IrSetValue): Boolean {
|
|
||||||
if (expression.symbol.owner.type.isInt()) {
|
|
||||||
when (expression.origin) {
|
|
||||||
IrStatementOrigin.PREFIX_INCR, IrStatementOrigin.PREFIX_DECR -> {
|
|
||||||
expression.markLineNumber(startOffset = true)
|
|
||||||
mv.iinc(findLocalIndex(expression.symbol), if (expression.origin == IrStatementOrigin.PREFIX_INCR) 1 else -1)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
IrStatementOrigin.PLUSEQ, IrStatementOrigin.MINUSEQ -> {
|
|
||||||
val argument = (expression.value as IrCall).getValueArgument(0)!!
|
|
||||||
if (!hasSameLineNumber(argument, expression)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return handlePlusMinus(expression, argument, expression.origin is IrStatementOrigin.MINUSEQ)
|
|
||||||
}
|
|
||||||
IrStatementOrigin.EQ -> {
|
|
||||||
val value = expression.value
|
|
||||||
if (!hasSameLineNumber(value, expression)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (value is IrCall) {
|
|
||||||
val receiver = value.dispatchReceiver ?: return false
|
|
||||||
val symbol = expression.symbol
|
|
||||||
if (!hasSameLineNumber(receiver, expression)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (value.origin == IrStatementOrigin.PLUS || value.origin == IrStatementOrigin.MINUS) {
|
|
||||||
val argument = value.getValueArgument(0)!!
|
|
||||||
if (receiver is IrGetValue && receiver.symbol == symbol && hasSameLineNumber(argument, expression)) {
|
|
||||||
return handlePlusMinus(expression, argument, value.origin == IrStatementOrigin.MINUS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitSetValue(expression: IrSetValue, data: BlockInfo): PromisedValue {
|
override fun visitSetValue(expression: IrSetValue, data: BlockInfo): PromisedValue {
|
||||||
if (!handleIntVariableSpecialCases(expression)) {
|
expression.value.markLineNumber(startOffset = true)
|
||||||
expression.value.markLineNumber(startOffset = true)
|
expression.value.accept(this, data).materializeAt(expression.symbol.owner.type)
|
||||||
expression.value.accept(this, data).materializeAt(expression.symbol.owner.type)
|
// We set the value of parameters only for default values. The inliner accepts only
|
||||||
// We set the value of parameters only for default values. The inliner accepts only
|
// a very specific bytecode pattern for default arguments and does not tolerate a
|
||||||
// a very specific bytecode pattern for default arguments and does not tolerate a
|
// line number on the store. Therefore, if we are storing to a parameter, we do not
|
||||||
// line number on the store. Therefore, if we are storing to a parameter, we do not
|
// output a line number for the store.
|
||||||
// output a line number for the store.
|
if (expression.symbol !is IrValueParameterSymbol) {
|
||||||
if (expression.symbol !is IrValueParameterSymbol) {
|
expression.markLineNumber(startOffset = true)
|
||||||
expression.markLineNumber(startOffset = true)
|
|
||||||
}
|
|
||||||
mv.store(findLocalIndex(expression.symbol), expression.symbol.owner.asmType)
|
|
||||||
}
|
}
|
||||||
|
mv.store(findLocalIndex(expression.symbol), expression.symbol.owner.asmType)
|
||||||
return unitValue
|
return unitValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1414,22 +1351,26 @@ class ExpressionCodegen(
|
|||||||
wrapIntoKClass: Boolean,
|
wrapIntoKClass: Boolean,
|
||||||
data: BlockInfo
|
data: BlockInfo
|
||||||
): PromisedValue {
|
): PromisedValue {
|
||||||
if (classReference is IrGetClass) {
|
when (classReference) {
|
||||||
// TODO transform one sort of access into the other?
|
is IrGetClass -> {
|
||||||
JavaClassProperty.invokeWith(classReference.argument.accept(this, data))
|
// TODO transform one sort of access into the other?
|
||||||
} else if (classReference is IrClassReference) {
|
JavaClassProperty.invokeWith(classReference.argument.accept(this, data))
|
||||||
val classType = classReference.classType
|
|
||||||
val classifier = classType.classifierOrNull
|
|
||||||
if (classifier is IrTypeParameterSymbol) {
|
|
||||||
val success = putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS)
|
|
||||||
assert(success) {
|
|
||||||
"Non-reified type parameter under ::class should be rejected by type checker: ${classType.render()}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
is IrClassReference -> {
|
||||||
|
val classType = classReference.classType
|
||||||
|
val classifier = classType.classifierOrNull
|
||||||
|
if (classifier is IrTypeParameterSymbol) {
|
||||||
|
val success = putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS)
|
||||||
|
assert(success) {
|
||||||
|
"Non-reified type parameter under ::class should be rejected by type checker: ${classType.render()}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generateClassInstance(mv, classType, typeMapper)
|
generateClassInstance(mv, classType, typeMapper)
|
||||||
} else {
|
}
|
||||||
throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}")
|
else -> {
|
||||||
|
throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wrapIntoKClass) {
|
if (wrapIntoKClass) {
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
|
import org.jetbrains.kotlin.ir.util.render
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
|
class IntIncr(private val isPrefix: Boolean) : IntrinsicMethod() {
|
||||||
|
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue {
|
||||||
|
val irGetValue = expression.getValueArgument(0) as? IrGetValue
|
||||||
|
?: error("IrGetValue expected as valueArgument #0: ${expression.dump()}")
|
||||||
|
val irDelta = expression.getValueArgument(1) as? IrConst<*>
|
||||||
|
?: error("IrConst expected as valueArgument #1: ${expression.dump()}")
|
||||||
|
if (irDelta.kind != IrConstKind.Int)
|
||||||
|
error("Int const expected: ${irDelta.dump()}")
|
||||||
|
val delta = IrConstKind.Int.valueOf(irDelta)
|
||||||
|
if (delta > Byte.MAX_VALUE || delta < Byte.MIN_VALUE)
|
||||||
|
error("Int const should be in (Byte.MIN_VALUE .. Byte.MAX_VALUE): ${irDelta.dump()}")
|
||||||
|
val varIndex = codegen.frameMap.getIndex(irGetValue.symbol)
|
||||||
|
if (varIndex == -1)
|
||||||
|
error("Unmapped variable: ${irGetValue.render()}")
|
||||||
|
if (isPrefix) {
|
||||||
|
codegen.mv.iinc(varIndex, delta)
|
||||||
|
irGetValue.accept(codegen, data).materialize()
|
||||||
|
} else {
|
||||||
|
irGetValue.accept(codegen, data).materialize()
|
||||||
|
codegen.mv.iinc(varIndex, delta)
|
||||||
|
}
|
||||||
|
return MaterialValue(codegen, Type.INT_TYPE, irGetValue.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -90,8 +90,8 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
|||||||
symbols.throwKotlinNothingValueException.toKey()!! to ThrowKotlinNothingValueException,
|
symbols.throwKotlinNothingValueException.toKey()!! to ThrowKotlinNothingValueException,
|
||||||
symbols.jvmIndyIntrinsic.toKey()!! to JvmInvokeDynamic,
|
symbols.jvmIndyIntrinsic.toKey()!! to JvmInvokeDynamic,
|
||||||
symbols.jvmDebuggerInvokeSpecialIntrinsic.toKey()!! to JvmDebuggerInvokeSpecial,
|
symbols.jvmDebuggerInvokeSpecialIntrinsic.toKey()!! to JvmDebuggerInvokeSpecial,
|
||||||
symbols.intPostfixIncr.toKey()!! to PostfixIinc(1),
|
symbols.intPostfixIncrDecr.toKey()!! to IntIncr(isPrefix = false),
|
||||||
symbols.intPostfixDecr.toKey()!! to PostfixIinc(-1)
|
symbols.intPrefixIncrDecr.toKey()!! to IntIncr(isPrefix = true)
|
||||||
) +
|
) +
|
||||||
numberConversionMethods() +
|
numberConversionMethods() +
|
||||||
unaryFunForPrimitives("plus", UnaryPlus) +
|
unaryFunForPrimitives("plus", UnaryPlus) +
|
||||||
|
|||||||
-26
@@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+106
-27
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin
|
|||||||
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineScopeResolver
|
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineScopeResolver
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.findInlineCallSites
|
import org.jetbrains.kotlin.backend.jvm.ir.findInlineCallSites
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrFileEntry
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.irGetField
|
import org.jetbrains.kotlin.ir.builders.irGetField
|
||||||
import org.jetbrains.kotlin.ir.builders.irSetField
|
import org.jetbrains.kotlin.ir.builders.irSetField
|
||||||
@@ -25,6 +27,7 @@ import org.jetbrains.kotlin.ir.expressions.*
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
|
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
@@ -72,10 +75,14 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
irFile.transformChildren(Transformer(irFile.findInlineCallSites(context)), null)
|
irFile.transformChildren(Transformer(irFile.fileEntry, irFile.findInlineCallSites(context)), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class Transformer(private val inlineScopeResolver: IrInlineScopeResolver) : IrElementTransformer<IrDeclaration?> {
|
private inner class Transformer(
|
||||||
|
private val fileEntry: IrFileEntry,
|
||||||
|
private val inlineScopeResolver: IrInlineScopeResolver
|
||||||
|
) : IrElementTransformer<IrDeclaration?> {
|
||||||
|
|
||||||
private val dontTouchTemporaryVals = HashSet<IrVariable>()
|
private val dontTouchTemporaryVals = HashSet<IrVariable>()
|
||||||
|
|
||||||
override fun visitDeclaration(declaration: IrDeclarationBase, data: IrDeclaration?): IrStatement =
|
override fun visitDeclaration(declaration: IrDeclarationBase, data: IrDeclaration?): IrStatement =
|
||||||
@@ -373,34 +380,31 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass
|
|||||||
this is IrVariable && origin == IrDeclarationOrigin.FOR_LOOP_VARIABLE
|
this is IrVariable && origin == IrDeclarationOrigin.FOR_LOOP_VARIABLE
|
||||||
|
|
||||||
private fun IrContainerExpression.rewritePostfixIncrDecr(): IrCall? {
|
private fun IrContainerExpression.rewritePostfixIncrDecr(): IrCall? {
|
||||||
return when (origin) {
|
if (origin != IrStatementOrigin.POSTFIX_INCR && origin != IrStatementOrigin.POSTFIX_DECR) return null
|
||||||
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
|
val tmpVar = this.statements[0] as? IrVariable ?: return null
|
||||||
if (setVar.symbol != getIncrVar.symbol) return null
|
val getIncrVar = tmpVar.initializer as? IrGetValue ?: return null
|
||||||
val setVarValue = setVar.value as? IrCall ?: return null
|
if (!getIncrVar.type.isInt()) 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
|
val setVar = this.statements[1] as? IrSetValue ?: return null
|
||||||
if (getTmpVar.symbol != tmpVar.symbol) 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 intrinsicSymbol =
|
val getTmpVar = this.statements[2] as? IrGetValue ?: return null
|
||||||
if (calleeName == OperatorNameConventions.INC)
|
if (getTmpVar.symbol != tmpVar.symbol) return null
|
||||||
context.ir.symbols.intPostfixIncr
|
|
||||||
else
|
|
||||||
context.ir.symbols.intPostfixDecr
|
|
||||||
|
|
||||||
return IrCallImpl.fromSymbolOwner(this.startOffset, this.endOffset, intrinsicSymbol)
|
val delta = if (calleeName == OperatorNameConventions.INC)
|
||||||
.apply { putValueArgument(0, getIncrVar) }
|
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, 1)
|
||||||
}
|
else
|
||||||
else ->
|
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, -1)
|
||||||
null
|
|
||||||
|
return IrCallImpl.fromSymbolOwner(this.startOffset, this.endOffset, context.ir.symbols.intPostfixIncrDecr).apply {
|
||||||
|
putValueArgument(0, getIncrVar)
|
||||||
|
putValueArgument(1, delta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,6 +421,81 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass
|
|||||||
expression
|
expression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitSetValue(expression: IrSetValue, data: IrDeclaration?): IrExpression {
|
||||||
|
expression.transformChildren(this, data)
|
||||||
|
return rewritePrefixIncrDecr(expression) ?: expression
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rewritePrefixIncrDecr(expression: IrSetValue): IrExpression? {
|
||||||
|
if (!expression.symbol.owner.type.isInt())
|
||||||
|
return null
|
||||||
|
when (expression.origin) {
|
||||||
|
IrStatementOrigin.PREFIX_INCR, IrStatementOrigin.PREFIX_DECR -> {
|
||||||
|
return prefixIncr(expression, if (expression.origin == IrStatementOrigin.PREFIX_INCR) 1 else -1)
|
||||||
|
}
|
||||||
|
IrStatementOrigin.PLUSEQ, IrStatementOrigin.MINUSEQ -> {
|
||||||
|
val argument = (expression.value as IrCall).getValueArgument(0)!!
|
||||||
|
if (!hasSameLineNumber(argument, expression)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return rewriteCompoundAssignmentAsPrefixIncrDecr(expression, argument, expression.origin is IrStatementOrigin.MINUSEQ)
|
||||||
|
}
|
||||||
|
IrStatementOrigin.EQ -> {
|
||||||
|
val value = expression.value
|
||||||
|
if (!hasSameLineNumber(value, expression)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (value is IrCall) {
|
||||||
|
val receiver = value.dispatchReceiver
|
||||||
|
?: return null
|
||||||
|
val symbol = expression.symbol
|
||||||
|
if (!hasSameLineNumber(receiver, expression)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (value.origin == IrStatementOrigin.PLUS || value.origin == IrStatementOrigin.MINUS) {
|
||||||
|
val argument = value.getValueArgument(0)!!
|
||||||
|
if (receiver is IrGetValue && receiver.symbol == symbol && hasSameLineNumber(argument, expression)) {
|
||||||
|
return rewriteCompoundAssignmentAsPrefixIncrDecr(
|
||||||
|
expression, argument, value.origin == IrStatementOrigin.MINUS
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rewriteCompoundAssignmentAsPrefixIncrDecr(
|
||||||
|
expression: IrSetValue,
|
||||||
|
value: IrExpression?,
|
||||||
|
isMinus: Boolean
|
||||||
|
): IrExpression? {
|
||||||
|
if (value is IrConst<*> && value.kind == IrConstKind.Int) {
|
||||||
|
val delta = IrConstKind.Int.valueOf(value)
|
||||||
|
val upperBound = Byte.MAX_VALUE.toInt() + (if (isMinus) 1 else 0)
|
||||||
|
val lowerBound = Byte.MIN_VALUE.toInt() + (if (isMinus) 1 else 0)
|
||||||
|
if (delta in lowerBound..upperBound) {
|
||||||
|
return prefixIncr(expression, if (isMinus) -delta else delta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prefixIncr(expression: IrSetValue, delta: Int): IrExpression {
|
||||||
|
val startOffset = expression.startOffset
|
||||||
|
val endOffset = expression.endOffset
|
||||||
|
return IrCallImpl.fromSymbolOwner(startOffset, endOffset, context.ir.symbols.intPrefixIncrDecr).apply {
|
||||||
|
putValueArgument(0, IrGetValueImpl(startOffset, endOffset, expression.symbol))
|
||||||
|
putValueArgument(1, IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, delta))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hasSameLineNumber(e1: IrElement, e2: IrElement) =
|
||||||
|
getLineNumberForOffset(e1.startOffset) == getLineNumberForOffset(e2.startOffset)
|
||||||
|
|
||||||
|
private fun getLineNumberForOffset(offset: Int): Int =
|
||||||
|
fileEntry.getLineNumber(offset) + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -922,17 +922,18 @@ class JvmSymbols(
|
|||||||
val remainderUnsignedLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("remainderUnsigned")
|
val remainderUnsignedLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("remainderUnsigned")
|
||||||
val toUnsignedStringLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("toUnsignedString")
|
val toUnsignedStringLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("toUnsignedString")
|
||||||
|
|
||||||
val intPostfixIncr = createPostfixIncrDecrFun("<int++>", irBuiltIns.intType)
|
val intPostfixIncrDecr = createIncrDecrFun("<int-postfix-incr-decr>")
|
||||||
val intPostfixDecr = createPostfixIncrDecrFun("<int-->", irBuiltIns.intType)
|
val intPrefixIncrDecr = createIncrDecrFun("<int-prefix-incr-decr>")
|
||||||
|
|
||||||
private fun createPostfixIncrDecrFun(intrinsicName: String, type: IrType): IrSimpleFunctionSymbol =
|
private fun createIncrDecrFun(intrinsicName: String): IrSimpleFunctionSymbol =
|
||||||
irFactory.buildFun {
|
irFactory.buildFun {
|
||||||
name = Name.special(intrinsicName)
|
name = Name.special(intrinsicName)
|
||||||
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = kotlinJvmInternalPackage
|
parent = kotlinJvmInternalPackage
|
||||||
addValueParameter("value", type)
|
addValueParameter("value", irBuiltIns.intType)
|
||||||
returnType = type
|
addValueParameter("delta", irBuiltIns.intType)
|
||||||
|
returnType = irBuiltIns.intType
|
||||||
}.symbol
|
}.symbol
|
||||||
|
|
||||||
private fun createJavaPrimitiveClass(fqName: FqName, type: IrType): IrClassSymbol = createClass(fqName) { klass ->
|
private fun createJavaPrimitiveClass(fqName: FqName, type: IrType): IrClassSymbol = createClass(fqName) { klass ->
|
||||||
|
|||||||
Reference in New Issue
Block a user