ForLoopsLowering: Eliminate construction/boxing/unboxing of UInt/ULong.
This needs further cleanup to encapsulate more logic into ProgressionType.
This commit is contained in:
committed by
Alexander Udalov
parent
e1120f49d8
commit
177967258b
@@ -289,6 +289,8 @@ abstract class Symbols<out T : CommonBackendContext>(val context: T, irBuiltIns:
|
|||||||
|
|
||||||
abstract val returnIfSuspended: IrSimpleFunctionSymbol
|
abstract val returnIfSuspended: IrSimpleFunctionSymbol
|
||||||
|
|
||||||
|
open val unsafeCoerceIntrinsic: IrSimpleFunctionSymbol? = null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun isLateinitIsInitializedPropertyGetter(symbol: IrFunctionSymbol): Boolean =
|
fun isLateinitIsInitializedPropertyGetter(symbol: IrFunctionSymbol): Boolean =
|
||||||
symbol is IrSimpleFunctionSymbol && symbol.owner.let { function ->
|
symbol is IrSimpleFunctionSymbol && symbol.owner.let { function ->
|
||||||
|
|||||||
+80
-3
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
|||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.functions
|
import org.jetbrains.kotlin.ir.util.functions
|
||||||
|
import org.jetbrains.kotlin.ir.util.isUnsigned
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||||
@@ -32,11 +33,15 @@ internal enum class ProgressionType(
|
|||||||
INT_PROGRESSION(Name.identifier("toInt"), Name.identifier("toInt")),
|
INT_PROGRESSION(Name.identifier("toInt"), Name.identifier("toInt")),
|
||||||
LONG_PROGRESSION(Name.identifier("toLong"), Name.identifier("toLong"), isLong = true),
|
LONG_PROGRESSION(Name.identifier("toLong"), Name.identifier("toLong"), isLong = true),
|
||||||
CHAR_PROGRESSION(Name.identifier("toChar"), Name.identifier("toInt")),
|
CHAR_PROGRESSION(Name.identifier("toChar"), Name.identifier("toInt")),
|
||||||
UINT_PROGRESSION(Name.identifier("toUInt"), Name.identifier("toInt"), isUnsigned = true),
|
UINT_PROGRESSION(Name.identifier("toInt"), Name.identifier("toInt"), isUnsigned = true),
|
||||||
ULONG_PROGRESSION(Name.identifier("toULong"), Name.identifier("toLong"), isLong = true, isUnsigned = true);
|
ULONG_PROGRESSION(Name.identifier("toLong"), Name.identifier("toLong"), isLong = true, isUnsigned = true);
|
||||||
|
|
||||||
/** Returns the [IrType] of the `first`/`last` properties and elements in the progression. */
|
/** Returns the [IrType] of the `first`/`last` properties and elements in the progression. */
|
||||||
fun elementType(symbols: Symbols<CommonBackendContext>): IrType = elementClassifier(symbols).defaultType
|
fun elementType(symbols: Symbols<CommonBackendContext>): IrType = when (this) {
|
||||||
|
INT_PROGRESSION, UINT_PROGRESSION -> symbols.int
|
||||||
|
LONG_PROGRESSION, ULONG_PROGRESSION -> symbols.long
|
||||||
|
CHAR_PROGRESSION -> symbols.char
|
||||||
|
}.defaultType
|
||||||
|
|
||||||
/** Returns the [IrClassSymbol] of the `first`/`last` properties and elements in the progression. */
|
/** Returns the [IrClassSymbol] of the `first`/`last` properties and elements in the progression. */
|
||||||
fun elementClassifier(symbols: Symbols<CommonBackendContext>): IrClassSymbol = when (this) {
|
fun elementClassifier(symbols: Symbols<CommonBackendContext>): IrClassSymbol = when (this) {
|
||||||
@@ -59,6 +64,15 @@ internal enum class ProgressionType(
|
|||||||
LONG_PROGRESSION, ULONG_PROGRESSION -> builtIns.longClass
|
LONG_PROGRESSION, ULONG_PROGRESSION -> builtIns.longClass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the [IrType] used in loop conditions (`buildLoopCondition()`) and when calling `getProgressionLastElement()`. */
|
||||||
|
fun compareType(symbols: Symbols<CommonBackendContext>): IrType = when (this) {
|
||||||
|
INT_PROGRESSION -> symbols.int
|
||||||
|
LONG_PROGRESSION -> symbols.long
|
||||||
|
CHAR_PROGRESSION -> symbols.char
|
||||||
|
UINT_PROGRESSION -> symbols.uInt!!
|
||||||
|
ULONG_PROGRESSION -> symbols.uLong!!
|
||||||
|
}.defaultType
|
||||||
|
|
||||||
fun castElementIfNecessary(element: IrExpression, context: CommonBackendContext) =
|
fun castElementIfNecessary(element: IrExpression, context: CommonBackendContext) =
|
||||||
element.castIfNecessary(elementType(context.ir.symbols), elementCastFunctionName)
|
element.castIfNecessary(elementType(context.ir.symbols), elementCastFunctionName)
|
||||||
|
|
||||||
@@ -78,6 +92,69 @@ internal enum class ProgressionType(
|
|||||||
.apply { dispatchReceiver = this@castIfNecessary }
|
.apply { dispatchReceiver = this@castIfNecessary }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun coerceToUnsigned(value: IrExpression, symbols: Symbols<CommonBackendContext>): IrExpression {
|
||||||
|
if (!isUnsigned || value.type.isUnsigned()) return value
|
||||||
|
|
||||||
|
val unsafeCoerceIntrinsic = symbols.unsafeCoerceIntrinsic
|
||||||
|
return if (unsafeCoerceIntrinsic != null) {
|
||||||
|
val from = when (this) {
|
||||||
|
UINT_PROGRESSION -> symbols.int.defaultType
|
||||||
|
ULONG_PROGRESSION -> symbols.long.defaultType
|
||||||
|
else -> error("Unexpected progression type")
|
||||||
|
}
|
||||||
|
val to = when (this) {
|
||||||
|
UINT_PROGRESSION -> symbols.uInt!!.defaultType
|
||||||
|
ULONG_PROGRESSION -> symbols.uLong!!.defaultType
|
||||||
|
else -> error("Unexpected progression type")
|
||||||
|
}
|
||||||
|
IrCallImpl(value.startOffset, value.endOffset, to, unsafeCoerceIntrinsic).apply {
|
||||||
|
putTypeArgument(0, from)
|
||||||
|
putTypeArgument(1, to)
|
||||||
|
putValueArgument(0, value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val conversionFunctionMap = when (this) {
|
||||||
|
UINT_PROGRESSION -> symbols.toUIntByExtensionReceiver
|
||||||
|
ULONG_PROGRESSION -> symbols.toULongByExtensionReceiver
|
||||||
|
else -> error("Unexpected progression type")
|
||||||
|
}
|
||||||
|
val from = when (this) {
|
||||||
|
UINT_PROGRESSION -> symbols.int.defaultType
|
||||||
|
ULONG_PROGRESSION -> symbols.long.defaultType
|
||||||
|
else -> error("Unexpected progression type")
|
||||||
|
}.toKotlinType()
|
||||||
|
val castFun = conversionFunctionMap.getValue(from)
|
||||||
|
IrCallImpl(value.startOffset, value.endOffset, castFun.owner.returnType, castFun).apply {
|
||||||
|
extensionReceiver = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun coerceToSigned(value: IrExpression, symbols: Symbols<CommonBackendContext>): IrExpression {
|
||||||
|
if (!isUnsigned || !value.type.isUnsigned()) return value
|
||||||
|
|
||||||
|
val unsafeCoerceIntrinsic = symbols.unsafeCoerceIntrinsic
|
||||||
|
return if (unsafeCoerceIntrinsic != null) {
|
||||||
|
val from = when (this) {
|
||||||
|
UINT_PROGRESSION -> symbols.uInt!!.defaultType
|
||||||
|
ULONG_PROGRESSION -> symbols.uLong!!.defaultType
|
||||||
|
else -> error("Unexpected progression type")
|
||||||
|
}
|
||||||
|
val to = when (this) {
|
||||||
|
UINT_PROGRESSION -> symbols.int.defaultType
|
||||||
|
ULONG_PROGRESSION -> symbols.long.defaultType
|
||||||
|
else -> error("Unexpected progression type")
|
||||||
|
}
|
||||||
|
IrCallImpl(value.startOffset, value.endOffset, to, unsafeCoerceIntrinsic).apply {
|
||||||
|
putTypeArgument(0, from)
|
||||||
|
putTypeArgument(1, to)
|
||||||
|
putValueArgument(0, value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
castElementIfNecessary(value, symbols.context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromIrType(irType: IrType, symbols: Symbols<CommonBackendContext>): ProgressionType? = when {
|
fun fromIrType(irType: IrType, symbols: Symbols<CommonBackendContext>): ProgressionType? = when {
|
||||||
irType.isSubtypeOfClass(symbols.charProgression) -> CHAR_PROGRESSION
|
irType.isSubtypeOfClass(symbols.charProgression) -> CHAR_PROGRESSION
|
||||||
|
|||||||
+18
-38
@@ -68,7 +68,6 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
val inductionVariable: IrVariable
|
val inductionVariable: IrVariable
|
||||||
|
|
||||||
protected val stepVariable: IrVariable?
|
protected val stepVariable: IrVariable?
|
||||||
protected val stepVariableForIncrement: IrVariable?
|
|
||||||
val stepExpression: IrExpression
|
val stepExpression: IrExpression
|
||||||
// Always copy `stepExpression` is it may be used multiple times.
|
// Always copy `stepExpression` is it may be used multiple times.
|
||||||
get() = field.deepCopyWithSymbols()
|
get() = field.deepCopyWithSymbols()
|
||||||
@@ -78,7 +77,7 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
// Always copy `lastExpression` is it may be used in multiple conditions.
|
// Always copy `lastExpression` is it may be used in multiple conditions.
|
||||||
get() = field.deepCopyWithSymbols()
|
get() = field.deepCopyWithSymbols()
|
||||||
|
|
||||||
private val symbols = context.ir.symbols
|
protected val symbols = context.ir.symbols
|
||||||
private val elementType: IrType
|
private val elementType: IrType
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -124,24 +123,6 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
)
|
)
|
||||||
stepVariable = tmpStepVar
|
stepVariable = tmpStepVar
|
||||||
stepExpression = tmpStepExpression
|
stepExpression = tmpStepExpression
|
||||||
|
|
||||||
stepVariableForIncrement = when (headerInfo.progressionType) {
|
|
||||||
ProgressionType.UINT_PROGRESSION -> {
|
|
||||||
val castFun = context.ir.symbols.toUIntByExtensionReceiver.getValue(stepType.toKotlinType())
|
|
||||||
scope.createTmpVariable(
|
|
||||||
irCall(castFun).apply { extensionReceiver = stepExpression },
|
|
||||||
nameHint = "stepForIncrement"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ProgressionType.ULONG_PROGRESSION -> {
|
|
||||||
val castFun = context.ir.symbols.toULongByExtensionReceiver.getValue(stepType.toKotlinType())
|
|
||||||
scope.createTmpVariable(
|
|
||||||
irCall(castFun).apply { extensionReceiver = stepExpression },
|
|
||||||
nameHint = "stepForIncrement"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,10 +136,9 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
/** Statement used to increment the induction variable. */
|
/** Statement used to increment the induction variable. */
|
||||||
protected fun incrementInductionVariable(builder: DeclarationIrBuilder): IrStatement = with(builder) {
|
protected fun incrementInductionVariable(builder: DeclarationIrBuilder): IrStatement = with(builder) {
|
||||||
// inductionVariable = inductionVariable + step
|
// inductionVariable = inductionVariable + step
|
||||||
val stepExpressionToUse = stepVariableForIncrement?.let { irGet(stepVariableForIncrement) } ?: stepExpression
|
// NOTE: We cannot use `stepExpression.type` to match the value parameter type because it may be of type `Nothing`.
|
||||||
// NOTE: We cannot use `stepExpression.type` below because it may be of type `Nothing`. This happens in the case of an illegal step
|
// This happens in the case of an illegal step where the "step" is actually a `throw IllegalArgumentException(...)`.
|
||||||
// where the "step" is actually a `throw IllegalArgumentException(...)`.
|
val stepType = headerInfo.progressionType.stepType(context.irBuiltIns)
|
||||||
val stepType = stepVariableForIncrement?.type ?: headerInfo.progressionType.stepType(context.irBuiltIns)
|
|
||||||
val plusFun = elementType.getClass()!!.functions.single {
|
val plusFun = elementType.getClass()!!.functions.single {
|
||||||
it.name == OperatorNameConventions.PLUS &&
|
it.name == OperatorNameConventions.PLUS &&
|
||||||
it.valueParameters.size == 1 &&
|
it.valueParameters.size == 1 &&
|
||||||
@@ -168,7 +148,7 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
inductionVariable.symbol, irCallOp(
|
inductionVariable.symbol, irCallOp(
|
||||||
plusFun.symbol, plusFun.returnType,
|
plusFun.symbol, plusFun.returnType,
|
||||||
irGet(inductionVariable),
|
irGet(inductionVariable),
|
||||||
stepExpressionToUse
|
stepExpression
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -177,7 +157,7 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
with(builder) {
|
with(builder) {
|
||||||
val builtIns = context.irBuiltIns
|
val builtIns = context.irBuiltIns
|
||||||
val progressionType = headerInfo.progressionType
|
val progressionType = headerInfo.progressionType
|
||||||
val progressionElementType = progressionType.elementType(symbols)
|
val progressionCompareType = progressionType.compareType(symbols)
|
||||||
|
|
||||||
// `compareTo` must be used for UInt/ULong; they don't have intrinsic comparison operators.
|
// `compareTo` must be used for UInt/ULong; they don't have intrinsic comparison operators.
|
||||||
val intCompFun = if (isLastInclusive) {
|
val intCompFun = if (isLastInclusive) {
|
||||||
@@ -185,17 +165,17 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
} else {
|
} else {
|
||||||
builtIns.lessFunByOperandType.getValue(builtIns.intClass)
|
builtIns.lessFunByOperandType.getValue(builtIns.intClass)
|
||||||
}
|
}
|
||||||
val elementCompareToFun = progressionElementType.getClass()!!.functions.single {
|
val elementCompareToFun = progressionCompareType.getClass()!!.functions.single {
|
||||||
it.name == OperatorNameConventions.COMPARE_TO &&
|
it.name == OperatorNameConventions.COMPARE_TO &&
|
||||||
it.dispatchReceiverParameter != null && it.extensionReceiverParameter == null &&
|
it.dispatchReceiverParameter != null && it.extensionReceiverParameter == null &&
|
||||||
it.valueParameters.size == 1 && it.valueParameters[0].type == progressionElementType
|
it.valueParameters.size == 1 && it.valueParameters[0].type == progressionCompareType
|
||||||
}
|
}
|
||||||
|
|
||||||
val elementCompFun =
|
val elementCompFun =
|
||||||
if (isLastInclusive) {
|
if (isLastInclusive) {
|
||||||
builtIns.lessOrEqualFunByOperandType[progressionElementType.classifierOrFail]
|
builtIns.lessOrEqualFunByOperandType[progressionCompareType.classifierOrFail]
|
||||||
} else {
|
} else {
|
||||||
builtIns.lessFunByOperandType[progressionElementType.classifierOrFail]
|
builtIns.lessFunByOperandType[progressionCompareType.classifierOrFail]
|
||||||
}
|
}
|
||||||
|
|
||||||
fun conditionForDecreasing(): IrExpression =
|
fun conditionForDecreasing(): IrExpression =
|
||||||
@@ -203,8 +183,8 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
if (progressionType.isUnsigned) {
|
if (progressionType.isUnsigned) {
|
||||||
irCall(intCompFun).apply {
|
irCall(intCompFun).apply {
|
||||||
putValueArgument(0, irCall(elementCompareToFun).apply {
|
putValueArgument(0, irCall(elementCompareToFun).apply {
|
||||||
dispatchReceiver = lastExpression
|
dispatchReceiver = progressionType.coerceToUnsigned(lastExpression, symbols)
|
||||||
putValueArgument(0, irGet(inductionVariable))
|
putValueArgument(0, progressionType.coerceToUnsigned(irGet(inductionVariable), symbols))
|
||||||
})
|
})
|
||||||
putValueArgument(1, irInt(0))
|
putValueArgument(1, irInt(0))
|
||||||
}
|
}
|
||||||
@@ -220,8 +200,8 @@ internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
|||||||
if (progressionType.isUnsigned) {
|
if (progressionType.isUnsigned) {
|
||||||
irCall(intCompFun).apply {
|
irCall(intCompFun).apply {
|
||||||
putValueArgument(0, irCall(elementCompareToFun).apply {
|
putValueArgument(0, irCall(elementCompareToFun).apply {
|
||||||
dispatchReceiver = irGet(inductionVariable)
|
dispatchReceiver = progressionType.coerceToUnsigned(irGet(inductionVariable), symbols)
|
||||||
putValueArgument(0, lastExpression)
|
putValueArgument(0, progressionType.coerceToUnsigned(lastExpression, symbols))
|
||||||
})
|
})
|
||||||
putValueArgument(1, irInt(0))
|
putValueArgument(1, irInt(0))
|
||||||
}
|
}
|
||||||
@@ -284,7 +264,7 @@ internal class ProgressionLoopHeader(
|
|||||||
else
|
else
|
||||||
listOfNotNull(inductionVariable, lastVariableIfCanCacheLast)
|
listOfNotNull(inductionVariable, lastVariableIfCanCacheLast)
|
||||||
) +
|
) +
|
||||||
listOfNotNull(stepVariable, stepVariableForIncrement)
|
listOfNotNull(stepVariable)
|
||||||
|
|
||||||
private var loopVariable: IrVariable? = null
|
private var loopVariable: IrVariable? = null
|
||||||
|
|
||||||
@@ -303,7 +283,7 @@ internal class ProgressionLoopHeader(
|
|||||||
isMutable = true
|
isMutable = true
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
loopVariable?.initializer = irGet(inductionVariable)
|
loopVariable?.initializer = headerInfo.progressionType.coerceToUnsigned(irGet(inductionVariable), symbols)
|
||||||
loopVariable
|
loopVariable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +308,7 @@ internal class ProgressionLoopHeader(
|
|||||||
// }
|
// }
|
||||||
IrDoWhileLoopImpl(oldLoop.startOffset, oldLoop.endOffset, oldLoop.type, oldLoop.origin).apply {
|
IrDoWhileLoopImpl(oldLoop.startOffset, oldLoop.endOffset, oldLoop.type, oldLoop.origin).apply {
|
||||||
label = oldLoop.label
|
label = oldLoop.label
|
||||||
condition = irNotEquals(irGet(loopVariable!!), lastExpression)
|
condition = irNotEquals(headerInfo.progressionType.coerceToSigned(irGet(loopVariable!!), symbols), lastExpression)
|
||||||
body = newBody
|
body = newBody
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -382,7 +362,7 @@ internal class IndexedGetLoopHeader(
|
|||||||
) : NumericForLoopHeader<IndexedGetHeaderInfo>(headerInfo, builder, context, isLastInclusive = false) {
|
) : NumericForLoopHeader<IndexedGetHeaderInfo>(headerInfo, builder, context, isLastInclusive = false) {
|
||||||
|
|
||||||
override val loopInitStatements =
|
override val loopInitStatements =
|
||||||
listOfNotNull(headerInfo.objectVariable, inductionVariable, lastVariableIfCanCacheLast, stepVariable, stepVariableForIncrement)
|
listOfNotNull(headerInfo.objectVariable, inductionVariable, lastVariableIfCanCacheLast, stepVariable)
|
||||||
|
|
||||||
override fun initializeIteration(
|
override fun initializeIteration(
|
||||||
loopVariable: IrVariable?,
|
loopVariable: IrVariable?,
|
||||||
|
|||||||
+38
-34
@@ -17,12 +17,10 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.types.asSimpleType
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
@@ -148,29 +146,14 @@ internal class UntilHandler(private val context: CommonBackendContext, private v
|
|||||||
val untilArgExpression = if (untilArgVar == null) untilArgCasted else irGet(untilArgVar)
|
val untilArgExpression = if (untilArgVar == null) untilArgCasted else irGet(untilArgVar)
|
||||||
val last = untilArgExpression.decrement()
|
val last = untilArgExpression.decrement()
|
||||||
|
|
||||||
|
// Type of MIN_VALUE constant is signed even for unsigned progressions since the bounds are signed.
|
||||||
val (minValueAsLong, minValueIrConst) =
|
val (minValueAsLong, minValueIrConst) =
|
||||||
when (data) {
|
when (data) {
|
||||||
ProgressionType.INT_PROGRESSION -> Pair(Int.MIN_VALUE.toLong(), irInt(Int.MIN_VALUE))
|
ProgressionType.INT_PROGRESSION -> Pair(Int.MIN_VALUE.toLong(), irInt(Int.MIN_VALUE))
|
||||||
ProgressionType.CHAR_PROGRESSION -> Pair(Char.MIN_VALUE.toLong(), irChar(Char.MIN_VALUE))
|
ProgressionType.CHAR_PROGRESSION -> Pair(Char.MIN_VALUE.toLong(), irChar(Char.MIN_VALUE))
|
||||||
ProgressionType.LONG_PROGRESSION -> Pair(Long.MIN_VALUE, irLong(Long.MIN_VALUE))
|
ProgressionType.LONG_PROGRESSION -> Pair(Long.MIN_VALUE, irLong(Long.MIN_VALUE))
|
||||||
ProgressionType.UINT_PROGRESSION -> Pair(
|
ProgressionType.UINT_PROGRESSION -> Pair(UInt.MIN_VALUE.toLong(), irInt(UInt.MIN_VALUE.toInt()))
|
||||||
UInt.MIN_VALUE.toLong(),
|
ProgressionType.ULONG_PROGRESSION -> Pair(ULong.MIN_VALUE.toLong(), irLong(ULong.MIN_VALUE.toLong()))
|
||||||
IrConstImpl.int(
|
|
||||||
startOffset,
|
|
||||||
endOffset,
|
|
||||||
symbols.uInt!!.defaultType,
|
|
||||||
UInt.MIN_VALUE.toInt()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
ProgressionType.ULONG_PROGRESSION -> Pair(
|
|
||||||
ULong.MIN_VALUE.toLong(),
|
|
||||||
IrConstImpl.long(
|
|
||||||
startOffset,
|
|
||||||
endOffset,
|
|
||||||
symbols.uLong!!.defaultType,
|
|
||||||
ULong.MIN_VALUE.toLong()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
val additionalNotEmptyCondition = untilArg.constLongValue.let {
|
val additionalNotEmptyCondition = untilArg.constLongValue.let {
|
||||||
when {
|
when {
|
||||||
@@ -496,22 +479,43 @@ internal class StepHandler(
|
|||||||
// - getProgressionLastElement(ULong, ULong, Long): ULong // Used by ULongProgression (uses Long step)
|
// - getProgressionLastElement(ULong, ULong, Long): ULong // Used by ULongProgression (uses Long step)
|
||||||
//
|
//
|
||||||
// We make sure to retrieve the correct symbol and use the correct argument types.
|
// We make sure to retrieve the correct symbol and use the correct argument types.
|
||||||
val returnTypeClassifier = if (progressionType.isUnsigned) {
|
return with(progressionType) {
|
||||||
progressionType.elementClassifier(symbols)
|
val returnTypeClassifier = if (progressionType.isUnsigned) {
|
||||||
} else {
|
progressionType.elementClassifier(symbols)
|
||||||
progressionType.stepClassifier(context.irBuiltIns)
|
|
||||||
}
|
|
||||||
val getProgressionLastElementFun = symbols.getProgressionLastElementByReturnType[returnTypeClassifier]
|
|
||||||
?: throw IllegalArgumentException("No `getProgressionLastElement` for return type ${returnTypeClassifier.defaultType}")
|
|
||||||
return irCall(getProgressionLastElementFun).apply {
|
|
||||||
if (progressionType.isUnsigned) {
|
|
||||||
putValueArgument(0, progressionType.castElementIfNecessary(first.deepCopyWithSymbols(), this@StepHandler.context))
|
|
||||||
putValueArgument(1, progressionType.castElementIfNecessary(last.deepCopyWithSymbols(), this@StepHandler.context))
|
|
||||||
} else {
|
} else {
|
||||||
putValueArgument(0, progressionType.castStepIfNecessary(first.deepCopyWithSymbols(), this@StepHandler.context))
|
progressionType.stepClassifier(context.irBuiltIns)
|
||||||
putValueArgument(1, progressionType.castStepIfNecessary(last.deepCopyWithSymbols(), this@StepHandler.context))
|
}
|
||||||
|
val getProgressionLastElementFun = symbols.getProgressionLastElementByReturnType[returnTypeClassifier]
|
||||||
|
?: throw IllegalArgumentException("No `getProgressionLastElement` for return type ${returnTypeClassifier.defaultType}")
|
||||||
|
val call = irCall(getProgressionLastElementFun).apply {
|
||||||
|
if (isUnsigned) {
|
||||||
|
putValueArgument(
|
||||||
|
0,
|
||||||
|
coerceToUnsigned(
|
||||||
|
castElementIfNecessary(first.deepCopyWithSymbols(), this@StepHandler.context),
|
||||||
|
symbols
|
||||||
|
)
|
||||||
|
)
|
||||||
|
putValueArgument(
|
||||||
|
1,
|
||||||
|
coerceToUnsigned(
|
||||||
|
castElementIfNecessary(last.deepCopyWithSymbols(), this@StepHandler.context),
|
||||||
|
symbols
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
putValueArgument(0, castStepIfNecessary(first.deepCopyWithSymbols(), this@StepHandler.context))
|
||||||
|
putValueArgument(1, castStepIfNecessary(last.deepCopyWithSymbols(), this@StepHandler.context))
|
||||||
|
}
|
||||||
|
putValueArgument(2, castStepIfNecessary(step.deepCopyWithSymbols(), this@StepHandler.context))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isUnsigned) {
|
||||||
|
// Bounds are signed for unsigned progressions.
|
||||||
|
coerceToSigned(call, symbols)
|
||||||
|
} else {
|
||||||
|
call
|
||||||
}
|
}
|
||||||
putValueArgument(2, progressionType.castStepIfNecessary(step.deepCopyWithSymbols(), this@StepHandler.context))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -507,7 +507,7 @@ class JvmSymbols(
|
|||||||
javaLangClass.functionByName("desiredAssertionStatus")
|
javaLangClass.functionByName("desiredAssertionStatus")
|
||||||
}
|
}
|
||||||
|
|
||||||
val unsafeCoerceIntrinsic: IrSimpleFunctionSymbol =
|
override val unsafeCoerceIntrinsic: IrSimpleFunctionSymbol =
|
||||||
buildFun {
|
buildFun {
|
||||||
name = Name.special("<unsafe-coerce>")
|
name = Name.special("<unsafe-coerce>")
|
||||||
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
origin = IrDeclarationOrigin.IR_BUILTINS_STUB
|
||||||
|
|||||||
+2
@@ -36,3 +36,5 @@ fun box(): String {
|
|||||||
// 0 NEW java/lang/IllegalArgumentException
|
// 0 NEW java/lang/IllegalArgumentException
|
||||||
// 0 ATHROW
|
// 0 ATHROW
|
||||||
// 0 IF
|
// 0 IF
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
+2
@@ -17,3 +17,5 @@ fun f(a: UInt): Int {
|
|||||||
// 0 getStep
|
// 0 getStep
|
||||||
// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare
|
// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare
|
||||||
// 2 IF
|
// 2 IF
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
+2
@@ -17,3 +17,5 @@ fun f(a: ULong): Int {
|
|||||||
// 0 getStep
|
// 0 getStep
|
||||||
// 1 INVOKESTATIC kotlin/UnsignedKt.ulongCompare
|
// 1 INVOKESTATIC kotlin/UnsignedKt.ulongCompare
|
||||||
// 2 IF
|
// 2 IF
|
||||||
|
// 0 INVOKESTATIC kotlin/ULong.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/ULong.(un)?box-impl
|
||||||
|
|||||||
+2
@@ -56,3 +56,5 @@ fun testULongDownTo(a: ULong, b: ULong): Int {
|
|||||||
// 0 getFirst
|
// 0 getFirst
|
||||||
// 0 getLast
|
// 0 getLast
|
||||||
// 0 getStep
|
// 0 getStep
|
||||||
|
// 0 INVOKESTATIC kotlin/U(Int|Long).constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/U(Int|Long).(un)?box-impl
|
||||||
|
|||||||
+3
@@ -1,3 +1,4 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
const val M = UInt.MAX_VALUE
|
const val M = UInt.MAX_VALUE
|
||||||
|
|
||||||
fun f(a: UInt): Int {
|
fun f(a: UInt): Int {
|
||||||
@@ -16,3 +17,5 @@ fun f(a: UInt): Int {
|
|||||||
// 0 getStep
|
// 0 getStep
|
||||||
// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare
|
// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare
|
||||||
// 2 IF
|
// 2 IF
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
+2
@@ -17,3 +17,5 @@ fun f(a: ULong): Int {
|
|||||||
// 0 getStep
|
// 0 getStep
|
||||||
// 1 INVOKESTATIC kotlin/UnsignedKt.ulongCompare
|
// 1 INVOKESTATIC kotlin/UnsignedKt.ulongCompare
|
||||||
// 2 IF
|
// 2 IF
|
||||||
|
// 0 INVOKESTATIC kotlin/ULong.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/ULong.(un)?box-impl
|
||||||
|
|||||||
+2
@@ -18,6 +18,8 @@ fun f(a: UInt): Int {
|
|||||||
// 0 getFirst
|
// 0 getFirst
|
||||||
// 0 getLast
|
// 0 getLast
|
||||||
// 0 getStep
|
// 0 getStep
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
// JVM_TEMPLATES
|
||||||
// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare
|
// 1 INVOKESTATIC kotlin/UnsignedKt.uintCompare
|
||||||
|
|||||||
+2
@@ -18,6 +18,8 @@ fun f(a: UInt): Int {
|
|||||||
// 0 getFirst
|
// 0 getFirst
|
||||||
// 0 getLast
|
// 0 getLast
|
||||||
// 0 getStep
|
// 0 getStep
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
// JVM_TEMPLATES
|
||||||
// 1 IF
|
// 1 IF
|
||||||
|
|||||||
+2
@@ -18,6 +18,8 @@ fun f(a: ULong): Int {
|
|||||||
// 0 getFirst
|
// 0 getFirst
|
||||||
// 0 getLast
|
// 0 getLast
|
||||||
// 0 getStep
|
// 0 getStep
|
||||||
|
// 0 INVOKESTATIC kotlin/ULong.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/ULong.(un)?box-impl
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
// JVM_TEMPLATES
|
||||||
// 1 INVOKESTATIC kotlin/UnsignedKt.ulongCompare
|
// 1 INVOKESTATIC kotlin/UnsignedKt.ulongCompare
|
||||||
|
|||||||
+2
@@ -18,6 +18,8 @@ fun f(a: ULong): Int {
|
|||||||
// 0 getFirst
|
// 0 getFirst
|
||||||
// 0 getLast
|
// 0 getLast
|
||||||
// 0 getStep
|
// 0 getStep
|
||||||
|
// 0 INVOKESTATIC kotlin/ULong.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/ULong.(un)?box-impl
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
// JVM_TEMPLATES
|
||||||
// 1 IF
|
// 1 IF
|
||||||
|
|||||||
+8
-6
@@ -1,17 +1,17 @@
|
|||||||
// TARGET_BACKEND: JVM_IR
|
// TARGET_BACKEND: JVM_IR
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
fun testUByteUntilUByte(a: UByte, b: UByte): UInt {
|
fun testUByteUntilUByte(a: UByte, b: UByte): Int {
|
||||||
var sum = 0u
|
var sum = 0
|
||||||
for (i in a until b) {
|
for (i in a until b) {
|
||||||
sum = sum * 10u + i
|
sum += i.toInt()
|
||||||
}
|
}
|
||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testUShortUntilUShort(a: UShort, b: UShort): UInt {
|
fun testUShortUntilUShort(a: UShort, b: UShort): Int {
|
||||||
var sum = 0u
|
var sum = 0
|
||||||
for (i in a until b) {
|
for (i in a until b) {
|
||||||
sum = sum * 10u + i
|
sum += i.toInt()
|
||||||
}
|
}
|
||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
@@ -32,3 +32,5 @@ fun testUShortUntilUShort(a: UShort, b: UShort): UInt {
|
|||||||
// 2 IFGT
|
// 2 IFGT
|
||||||
// 2 IFLE
|
// 2 IFLE
|
||||||
// 4 IF
|
// 4 IF
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
@@ -39,3 +39,5 @@ fun box(): String {
|
|||||||
// 1 ATHROW
|
// 1 ATHROW
|
||||||
// 0 IF
|
// 0 IF
|
||||||
// 0 ARETURN
|
// 0 ARETURN
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
@@ -41,3 +41,5 @@ fun box(): String {
|
|||||||
// 1 IFGT
|
// 1 IFGT
|
||||||
// 1 IF_ICMPNE
|
// 1 IF_ICMPNE
|
||||||
// 2 IF
|
// 2 IF
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
Vendored
+2
@@ -51,3 +51,5 @@ fun box(): String {
|
|||||||
// 1 IFGE
|
// 1 IFGE
|
||||||
// 6 IF
|
// 6 IF
|
||||||
// 0 INEG
|
// 0 INEG
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
Vendored
+2
@@ -55,3 +55,5 @@ fun box(): String {
|
|||||||
// 1 IFGE
|
// 1 IFGE
|
||||||
// 7 IF
|
// 7 IF
|
||||||
// 1 INEG
|
// 1 INEG
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
+2
@@ -43,3 +43,5 @@ fun box(): String {
|
|||||||
// 1 IFGT
|
// 1 IFGT
|
||||||
// 1 IF_ICMPNE
|
// 1 IF_ICMPNE
|
||||||
// 2 IF
|
// 2 IF
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
+2
@@ -43,3 +43,5 @@ fun box(): String {
|
|||||||
// 1 IFGT
|
// 1 IFGT
|
||||||
// 1 IF_ICMPNE
|
// 1 IF_ICMPNE
|
||||||
// 3 IF
|
// 3 IF
|
||||||
|
// 0 INVOKESTATIC kotlin/UInt.constructor-impl
|
||||||
|
// 0 INVOKE\w+ kotlin/UInt.(un)?box-impl
|
||||||
|
|||||||
Reference in New Issue
Block a user