[JVM_IR] Avoid some boxing when comparing boxed primitives to primitives.

This commit is contained in:
Mads Ager
2020-04-30 14:42:28 +02:00
committed by Dmitry Petrov
parent f3830cb07e
commit db17184cfd
13 changed files with 128 additions and 92 deletions
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.*
import org.jetbrains.kotlin.backend.jvm.ir.isSmartcastFromHigherThanNullable
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.AsmUtil.comparisonOperandType
import org.jetbrains.kotlin.codegen.AsmUtil.unboxType
import org.jetbrains.kotlin.codegen.BranchedValue
import org.jetbrains.kotlin.codegen.NumberCompare
import org.jetbrains.kotlin.codegen.ObjectCompare
@@ -68,7 +69,7 @@ object CompareTo : IntrinsicMethod() {
}
}
class IntegerZeroComparison(val op: IElementType, val a: MaterialValue): BooleanValue(a.codegen) {
class IntegerZeroComparison(val op: IElementType, val a: MaterialValue) : BooleanValue(a.codegen) {
override fun jumpIfFalse(target: Label) {
mv.visitJumpInsn(Opcodes.IFNE, target)
}
@@ -134,6 +135,41 @@ class NonIEEE754FloatComparison(val op: IElementType, val a: MaterialValue, val
}
}
class PrimitiveToBoxedComparison(
val op: IElementType,
private val boxedValue: MaterialValue,
private val loadOther: () -> MaterialValue
) : BooleanValue(boxedValue.codegen) {
override fun jumpIfFalse(target: Label) {
val compareLabel = Label()
mv.dup()
mv.ifnonnull(compareLabel)
mv.pop()
mv.goTo(target)
mv.mark(compareLabel)
val unboxedValue = boxedValue.materializedAt(unboxType(boxedValue.type), boxedValue.irType)
BooleanComparison(op, unboxedValue, loadOther()).jumpIfFalse(target)
}
override fun jumpIfTrue(target: Label) {
val compareLabel = Label()
val endLabel = Label()
mv.dup()
mv.ifnonnull(compareLabel)
mv.pop()
mv.goTo(endLabel)
mv.mark(compareLabel)
val unboxedValue = boxedValue.materializedAt(unboxType(boxedValue.type), boxedValue.irType)
BooleanComparison(op, unboxedValue, loadOther()).jumpIfTrue(target)
mv.mark(endLabel)
}
override fun discard() {
boxedValue.discard()
}
}
class PrimitiveComparison(
private val primitiveNumberType: KotlinType,
private val operatorToken: KtSingleValueToken
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.types.classOrNull
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.ir.util.isEnumEntry
import org.jetbrains.kotlin.ir.util.isIntegerConst
import org.jetbrains.kotlin.ir.util.isNullConst
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.types.isNullable
@@ -80,6 +82,38 @@ class Equals(val operator: IElementType) : IntrinsicMethod() {
val leftType = with(codegen) { a.asmType }
val rightType = with(codegen) { b.asmType }
val opToken = expression.origin
fun loadOther(expression: IrExpression, type: Type): () -> MaterialValue {
return if (expression.hasNoSideEffects()) {
{ expression.accept(codegen, data).materializedAt(type, expression.type) }
} else {
val aValue = expression.accept(codegen, data).materializedAt(type, expression.type)
val local = codegen.frameMap.enterTemp(type)
codegen.mv.store(local, type)
({
codegen.mv.load(local, type)
codegen.frameMap.leaveTemp(type)
aValue
})
}
}
if ((opToken == IrStatementOrigin.EQEQ || opToken == IrStatementOrigin.EXCLEQ) &&
(AsmUtil.isIntOrLongPrimitive(leftType) || AsmUtil.isIntOrLongPrimitive(rightType)) &&
(AsmUtil.isBoxedTypeOf(leftType, rightType) || AsmUtil.isBoxedTypeOf(rightType, leftType))
) {
val leftIsPrimitive = AsmUtil.isIntOrLongPrimitive(leftType)
return if (leftIsPrimitive) {
val loadOther = loadOther(a, leftType)
val boxedValue = b.accept(codegen, data).materializedAt(rightType, b.type)
PrimitiveToBoxedComparison(operator, boxedValue, loadOther)
} else {
val boxedValue = a.accept(codegen, data).materializedAt(leftType, a.type)
val loadOther = loadOther(b, rightType)
PrimitiveToBoxedComparison(operator, boxedValue, loadOther)
}
}
val aIsEnum = a.type.classOrNull?.owner?.run { isEnumClass || isEnumEntry } == true
val bIsEnum = b.type.classOrNull?.owner?.run { isEnumClass || isEnumEntry } == true
val useEquals = opToken !== IrStatementOrigin.EQEQEQ && opToken !== IrStatementOrigin.EXCLEQEQ &&
@@ -408,7 +408,8 @@ fun IrExpression.hasNoSideEffects() =
this is IrFunctionExpression ||
(this is IrCallableReference && dispatchReceiver == null && extensionReceiver == null) ||
this is IrClassReference ||
this is IrConst<*>
this is IrConst<*> ||
this is IrGetValue
fun CallGenerator.generateCall(ktElement: KtElement, call: CallBuilder, origin: IrStatementOrigin? = null) =
generateCall(ktElement.startOffsetSkippingComments, ktElement.endOffset, call, origin)
@@ -45,9 +45,7 @@ import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonInfo
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.intersectTypes
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.types.typeUtil.*
class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
@@ -390,6 +388,9 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
operandType == targetType || operandNNType == targetType ->
this
targetType.isInt() && (operandNNType.isShort() || operandNNType.isByte()) ->
this
// TODO: don't rely on originalKotlinType.
type.originalKotlinType!!.containsNull() ->
safeCallOnDispatchReceiver(this@OperatorExpressionGenerator, startOffset, endOffset) { dispatchReceiver ->
@@ -1,6 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36646 Don't box primitive values in equality comparison with nullable primitive values in JVM_IR
fun testBoolean1(a: Boolean?, b: Boolean) = a == b
fun testBoolean2(a: Boolean?, b: Boolean) = a != b
@@ -1,6 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36646 Don't box primitive values in equality comparison with nullable primitive values in JVM_IR
fun testBoolean1(a: Boolean, b: Boolean?) = a == b
fun testBoolean2(a: Boolean, b: Boolean?) = a != b
@@ -11,17 +11,9 @@ fun less4(a: Byte?, b: Byte?) = if (a is Byte && b is Byte) a < b else true
fun less5(a: Any?, b: Any?) = if (a is Byte && b is Byte) a < b else true
// JVM_TEMPLATES
// 3 Intrinsics\.areEqual
// 0 Intrinsics\.compare
// 4 INVOKEVIRTUAL java/lang/Byte\.byteValue \(\)B
// 2 INVOKEVIRTUAL java/lang/Number\.intValue \(\)I
// 0 IFGE
// 3 IF_ICMPGE
// JVM_IR_TEMPLATES
// 0 Intrinsics\.areEqual
// 0 Intrinsics\.compare
// 8 INVOKEVIRTUAL java/lang/Byte\.byteValue \(\)B
// 4 INVOKEVIRTUAL java/lang/Number\.byteValue \(\)B
// 0 IFGE
// 3 IF_ICMPNE
// 3 IF_ICMPGE
@@ -19,10 +19,10 @@ fun less5(a: Any?, b: Any?) = if (a is Byte && b is Byte) a < b else true
// 0 IF_ICMPGE
// JVM_IR_TEMPLATES
// 0 Intrinsics\.areEqual
// 3 Intrinsics\.areEqual
// 0 Intrinsics\.compare
// 8 INVOKEVIRTUAL java/lang/Byte\.byteValue \(\)B
// 4 INVOKEVIRTUAL java/lang/Number\.byteValue \(\)B
// 4 INVOKEVIRTUAL java/lang/Byte\.byteValue \(\)B
// 2 INVOKEVIRTUAL java/lang/Number\.intValue \(\)I
// 0 IFGE
// 3 IF_ICMPGE
// 3 IF_ICMPNE
// 0 IF_ICMPNE
@@ -11,17 +11,10 @@ fun less4(a: Short?, b: Short?) = if (a is Short && b is Short) a < b else true
fun less5(a: Any?, b: Any?) = if (a is Short && b is Short) a < b else true
// JVM_TEMPLATES
// 3 Intrinsics\.areEqual
// 0 Intrinsics\.compare
// 4 INVOKEVIRTUAL java/lang/Short\.shortValue \(\)S
// 2 INVOKEVIRTUAL java/lang/Number\.intValue \(\)I
// 0 IFGE
// 3 IF_ICMPGE
// JVM_IR_TEMPLATES
// 0 Intrinsics\.areEqual
// 0 Intrinsics\.compare
// 8 INVOKEVIRTUAL java/lang/Short\.shortValue \(\)S
// 4 INVOKEVIRTUAL java/lang/Number\.shortValue \(\)S
// 0 IFGE
// 3 IF_ICMPGE
// 3 IF_ICMPNE
// 0 IF_ICMPNE
@@ -18,10 +18,10 @@ fun less5(a: Any?, b: Any?) = if (a is Short && b is Short) a < b else true
// 0 IF_ICMPGE
// JVM_IR_TEMPLATES
// 0 Intrinsics\.areEqual
// 3 Intrinsics\.areEqual
// 0 Intrinsics\.compare
// 8 INVOKEVIRTUAL java/lang/Short\.shortValue \(\)S
// 4 INVOKEVIRTUAL java/lang/Number\.shortValue \(\)S
// 4 INVOKEVIRTUAL java/lang/Short\.shortValue \(\)S
// 2 INVOKEVIRTUAL java/lang/Number\.intValue \(\)I
// 0 IFGE
// 3 IF_ICMPGE
// 3 IF_ICMPNE
// 0 IF_ICMPNE
@@ -1,6 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TODO KT-36646 Don't box primitive values in equality comparison with objects in JVM_IR
fun testInt(i: Int?) =
when (i) {
0 -> "zero"
@@ -49,13 +49,9 @@ FILE fqName:<root> fileName:/argumentReorderingInDelegatingConstructorCall.kt
VALUE_PARAMETER name:yy index:1 type:kotlin.Int
BLOCK_BODY
BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
GET_VAR 'yy: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
GET_VAR 'xx: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
x: GET_VAR 'val tmp_1: kotlin.Int [val] declared in <root>.Test1.<init>' type=kotlin.Int origin=null
y: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.Test1.<init>' type=kotlin.Int origin=null
x: GET_VAR 'xx: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
y: GET_VAR 'yy: kotlin.Int declared in <root>.Test1.<init>' type=kotlin.Int origin=null
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test1 modality:FINAL visibility:public superTypes:[<root>.Base]'
PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
FUN FAKE_OVERRIDE name:<get-x> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int [fake_override]
@@ -89,13 +85,9 @@ FILE fqName:<root> fileName:/argumentReorderingInDelegatingConstructorCall.kt
VALUE_PARAMETER name:yy index:1 type:kotlin.Int
BLOCK_BODY
BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL
VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.Int [val]
GET_VAR 'yy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Int [val]
GET_VAR 'xx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (x: kotlin.Int, y: kotlin.Int) [primary] declared in <root>.Base'
x: GET_VAR 'val tmp_3: kotlin.Int [val] declared in <root>.Test2.<init>' type=kotlin.Int origin=null
y: GET_VAR 'val tmp_2: kotlin.Int [val] declared in <root>.Test2.<init>' type=kotlin.Int origin=null
x: GET_VAR 'xx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
y: GET_VAR 'yy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Test2 modality:FINAL visibility:public superTypes:[<root>.Base]'
CONSTRUCTOR visibility:public <> (xxx:kotlin.Int, yyy:kotlin.Int, a:kotlin.Any) returnType:<root>.Test2
VALUE_PARAMETER name:xxx index:0 type:kotlin.Int
@@ -103,13 +95,9 @@ FILE fqName:<root> fileName:/argumentReorderingInDelegatingConstructorCall.kt
VALUE_PARAMETER name:a index:2 type:kotlin.Any
BLOCK_BODY
BLOCK type=kotlin.Unit origin=ARGUMENTS_REORDERING_FOR_CALL
VAR IR_TEMPORARY_VARIABLE name:tmp_4 type:kotlin.Int [val]
GET_VAR 'yyy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
VAR IR_TEMPORARY_VARIABLE name:tmp_5 type:kotlin.Int [val]
GET_VAR 'xxx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> (xx: kotlin.Int, yy: kotlin.Int) declared in <root>.Test2'
xx: GET_VAR 'val tmp_5: kotlin.Int [val] declared in <root>.Test2.<init>' type=kotlin.Int origin=null
yy: GET_VAR 'val tmp_4: kotlin.Int [val] declared in <root>.Test2.<init>' type=kotlin.Int origin=null
xx: GET_VAR 'xxx: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
yy: GET_VAR 'yyy: kotlin.Int declared in <root>.Test2.<init>' type=kotlin.Int origin=null
PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
FUN FAKE_OVERRIDE name:<get-x> visibility:public modality:FINAL <> ($this:<root>.Base) returnType:kotlin.Int [fake_override]
correspondingProperty: PROPERTY FAKE_OVERRIDE name:x visibility:public modality:FINAL [fake_override,val]
@@ -5,80 +5,80 @@ FILE fqName:<root> fileName:/primitiveComparisons.kt
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun btest1 (a: kotlin.Byte, b: kotlin.Byte): kotlin.Boolean declared in <root>'
CALL 'public final fun greater (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GT
arg0: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Byte' type=kotlin.Int origin=null
$this: GET_VAR 'a: kotlin.Byte declared in <root>.btest1' type=kotlin.Byte origin=null
arg1: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Byte' type=kotlin.Int origin=null
$this: GET_VAR 'b: kotlin.Byte declared in <root>.btest1' type=kotlin.Byte origin=null
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'a: kotlin.Byte declared in <root>.btest1' type=kotlin.Byte origin=null
arg1: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'b: kotlin.Byte declared in <root>.btest1' type=kotlin.Byte origin=null
FUN name:btest2 visibility:public modality:FINAL <> (a:kotlin.Byte, b:kotlin.Byte) returnType:kotlin.Boolean
VALUE_PARAMETER name:a index:0 type:kotlin.Byte
VALUE_PARAMETER name:b index:1 type:kotlin.Byte
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun btest2 (a: kotlin.Byte, b: kotlin.Byte): kotlin.Boolean declared in <root>'
CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
arg0: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Byte' type=kotlin.Int origin=null
$this: GET_VAR 'a: kotlin.Byte declared in <root>.btest2' type=kotlin.Byte origin=null
arg1: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Byte' type=kotlin.Int origin=null
$this: GET_VAR 'b: kotlin.Byte declared in <root>.btest2' type=kotlin.Byte origin=null
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'a: kotlin.Byte declared in <root>.btest2' type=kotlin.Byte origin=null
arg1: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'b: kotlin.Byte declared in <root>.btest2' type=kotlin.Byte origin=null
FUN name:btest3 visibility:public modality:FINAL <> (a:kotlin.Byte, b:kotlin.Byte) returnType:kotlin.Boolean
VALUE_PARAMETER name:a index:0 type:kotlin.Byte
VALUE_PARAMETER name:b index:1 type:kotlin.Byte
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun btest3 (a: kotlin.Byte, b: kotlin.Byte): kotlin.Boolean declared in <root>'
CALL 'public final fun greaterOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GTEQ
arg0: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Byte' type=kotlin.Int origin=null
$this: GET_VAR 'a: kotlin.Byte declared in <root>.btest3' type=kotlin.Byte origin=null
arg1: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Byte' type=kotlin.Int origin=null
$this: GET_VAR 'b: kotlin.Byte declared in <root>.btest3' type=kotlin.Byte origin=null
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'a: kotlin.Byte declared in <root>.btest3' type=kotlin.Byte origin=null
arg1: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'b: kotlin.Byte declared in <root>.btest3' type=kotlin.Byte origin=null
FUN name:btest4 visibility:public modality:FINAL <> (a:kotlin.Byte, b:kotlin.Byte) returnType:kotlin.Boolean
VALUE_PARAMETER name:a index:0 type:kotlin.Byte
VALUE_PARAMETER name:b index:1 type:kotlin.Byte
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun btest4 (a: kotlin.Byte, b: kotlin.Byte): kotlin.Boolean declared in <root>'
CALL 'public final fun lessOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LTEQ
arg0: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Byte' type=kotlin.Int origin=null
$this: GET_VAR 'a: kotlin.Byte declared in <root>.btest4' type=kotlin.Byte origin=null
arg1: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Byte' type=kotlin.Int origin=null
$this: GET_VAR 'b: kotlin.Byte declared in <root>.btest4' type=kotlin.Byte origin=null
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'a: kotlin.Byte declared in <root>.btest4' type=kotlin.Byte origin=null
arg1: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'b: kotlin.Byte declared in <root>.btest4' type=kotlin.Byte origin=null
FUN name:stest1 visibility:public modality:FINAL <> (a:kotlin.Short, b:kotlin.Short) returnType:kotlin.Boolean
VALUE_PARAMETER name:a index:0 type:kotlin.Short
VALUE_PARAMETER name:b index:1 type:kotlin.Short
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun stest1 (a: kotlin.Short, b: kotlin.Short): kotlin.Boolean declared in <root>'
CALL 'public final fun greater (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GT
arg0: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Short' type=kotlin.Int origin=null
$this: GET_VAR 'a: kotlin.Short declared in <root>.stest1' type=kotlin.Short origin=null
arg1: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Short' type=kotlin.Int origin=null
$this: GET_VAR 'b: kotlin.Short declared in <root>.stest1' type=kotlin.Short origin=null
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'a: kotlin.Short declared in <root>.stest1' type=kotlin.Short origin=null
arg1: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'b: kotlin.Short declared in <root>.stest1' type=kotlin.Short origin=null
FUN name:stest2 visibility:public modality:FINAL <> (a:kotlin.Short, b:kotlin.Short) returnType:kotlin.Boolean
VALUE_PARAMETER name:a index:0 type:kotlin.Short
VALUE_PARAMETER name:b index:1 type:kotlin.Short
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun stest2 (a: kotlin.Short, b: kotlin.Short): kotlin.Boolean declared in <root>'
CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
arg0: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Short' type=kotlin.Int origin=null
$this: GET_VAR 'a: kotlin.Short declared in <root>.stest2' type=kotlin.Short origin=null
arg1: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Short' type=kotlin.Int origin=null
$this: GET_VAR 'b: kotlin.Short declared in <root>.stest2' type=kotlin.Short origin=null
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'a: kotlin.Short declared in <root>.stest2' type=kotlin.Short origin=null
arg1: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'b: kotlin.Short declared in <root>.stest2' type=kotlin.Short origin=null
FUN name:stest3 visibility:public modality:FINAL <> (a:kotlin.Short, b:kotlin.Short) returnType:kotlin.Boolean
VALUE_PARAMETER name:a index:0 type:kotlin.Short
VALUE_PARAMETER name:b index:1 type:kotlin.Short
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun stest3 (a: kotlin.Short, b: kotlin.Short): kotlin.Boolean declared in <root>'
CALL 'public final fun greaterOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=GTEQ
arg0: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Short' type=kotlin.Int origin=null
$this: GET_VAR 'a: kotlin.Short declared in <root>.stest3' type=kotlin.Short origin=null
arg1: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Short' type=kotlin.Int origin=null
$this: GET_VAR 'b: kotlin.Short declared in <root>.stest3' type=kotlin.Short origin=null
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'a: kotlin.Short declared in <root>.stest3' type=kotlin.Short origin=null
arg1: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'b: kotlin.Short declared in <root>.stest3' type=kotlin.Short origin=null
FUN name:stest4 visibility:public modality:FINAL <> (a:kotlin.Short, b:kotlin.Short) returnType:kotlin.Boolean
VALUE_PARAMETER name:a index:0 type:kotlin.Short
VALUE_PARAMETER name:b index:1 type:kotlin.Short
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun stest4 (a: kotlin.Short, b: kotlin.Short): kotlin.Boolean declared in <root>'
CALL 'public final fun lessOrEqual (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LTEQ
arg0: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Short' type=kotlin.Int origin=null
$this: GET_VAR 'a: kotlin.Short declared in <root>.stest4' type=kotlin.Short origin=null
arg1: CALL 'public open fun toInt (): kotlin.Int declared in kotlin.Short' type=kotlin.Int origin=null
$this: GET_VAR 'b: kotlin.Short declared in <root>.stest4' type=kotlin.Short origin=null
arg0: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'a: kotlin.Short declared in <root>.stest4' type=kotlin.Short origin=null
arg1: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
GET_VAR 'b: kotlin.Short declared in <root>.stest4' type=kotlin.Short origin=null
FUN name:itest1 visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.Boolean
VALUE_PARAMETER name:a index:0 type:kotlin.Int
VALUE_PARAMETER name:b index:1 type:kotlin.Int