From ea13386d0b78ab0324e8d06759bcc31b4be37a5e Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 23 Sep 2016 17:28:39 +0300 Subject: [PATCH] IR to CFG: member access unrolling --- .../ir2cfg/generators/FunctionGenerator.kt | 12 ++++ .../testData/ir/irCfg/loop/digitCount.txt | 7 ++ compiler/testData/ir/irCfg/loop/factorial.txt | 17 +++-- compiler/testData/ir/irCfg/loop/isPerfect.txt | 33 ++++++--- compiler/testData/ir/irCfg/sequentialFun.txt | 10 +-- compiler/testData/ir/irCfg/when/cascadeIf.txt | 6 ++ .../testData/ir/irCfg/when/expressionIf.txt | 3 + compiler/testData/ir/irCfg/when/ifChain.txt | 71 +++++++++++++++---- .../testData/ir/irCfg/when/whenReturn.txt | 8 +++ 9 files changed, 135 insertions(+), 32 deletions(-) diff --git a/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/generators/FunctionGenerator.kt b/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/generators/FunctionGenerator.kt index 007b6113ec5..92a9169a63e 100644 --- a/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/generators/FunctionGenerator.kt +++ b/compiler/ir/ir.ir2cfg/src/org/jetbrains/kotlin/ir2cfg/generators/FunctionGenerator.kt @@ -188,6 +188,18 @@ class FunctionGenerator(val function: IrFunction) { return jump } + override fun visitMemberAccess(expression: IrMemberAccessExpression, data: Boolean): IrElement? { + expression.dispatchReceiver?.process() + expression.extensionReceiver?.process() + for (valueParameter in expression.descriptor.valueParameters) { + expression.getValueArgument(valueParameter)?.process() + } + if (data) { + builder.add(expression) + } + return expression + } + override fun visitElement(element: IrElement, data: Boolean): IrElement? { TODO("not implemented") } diff --git a/compiler/testData/ir/irCfg/loop/digitCount.txt b/compiler/testData/ir/irCfg/loop/digitCount.txt index 8be9b1233d3..78d2f6f0bee 100644 --- a/compiler/testData/ir/irCfg/loop/digitCount.txt +++ b/compiler/testData/ir/irCfg/loop/digitCount.txt @@ -15,6 +15,10 @@ INCOMING <- BB 0, 4 Do..while entry: DO_WHILE label=null origin=DO_WHILE_LOOP CONTENT 1 WHEN type=kotlin.Unit origin=null + 2 GET_VAR 'value-parameter m: Int' type=kotlin.Int origin=null + 3 GET_VAR 'number: Int' type=kotlin.Int origin=null + 4 CONST Int type=kotlin.Int value='10' + 5 CALL 'mod(Int): Int' type=kotlin.Int origin=PERC OUTGOING -> BB 2 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ BB 2 @@ -29,6 +33,9 @@ INCOMING <- BB 2 When exit: WHEN type=kotlin.Unit origin=null CONTENT 1 SET_VAR 'number: Int' type=kotlin.Unit origin=DIVEQ + 2 GET_VAR 'number: Int' type=kotlin.Int origin=null + 3 CONST Int type=kotlin.Int value='0' + 4 CALL 'compareTo(Int): Int' type=kotlin.Int origin=GT OUTGOING -> BB 4, 5 CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT BB 4 diff --git a/compiler/testData/ir/irCfg/loop/factorial.txt b/compiler/testData/ir/irCfg/loop/factorial.txt index 6f534cda70a..56606416b17 100644 --- a/compiler/testData/ir/irCfg/loop/factorial.txt +++ b/compiler/testData/ir/irCfg/loop/factorial.txt @@ -5,24 +5,29 @@ CONTENT 1 FUN public fun factorial(i: kotlin.Int): kotlin.Int 2 CONST Int type=kotlin.Int value='1' 3 VAR var result: kotlin.Int - 4 CALL 'iterator(): IntIterator' type=kotlin.collections.IntIterator origin=FOR_LOOP_ITERATOR - 5 VAR IR_TEMPORARY_VARIABLE val tmp0_iterator: kotlin.collections.IntIterator - 6 WHILE label=null origin=FOR_LOOP_INNER_WHILE + 4 CONST Int type=kotlin.Int value='2' + 5 GET_VAR 'value-parameter i: Int' type=kotlin.Int origin=null + 6 CALL 'rangeTo(Int): IntRange' type=kotlin.ranges.IntRange origin=RANGE + 7 CALL 'iterator(): IntIterator' type=kotlin.collections.IntIterator origin=FOR_LOOP_ITERATOR + 8 VAR IR_TEMPORARY_VARIABLE val tmp0_iterator: kotlin.collections.IntIterator + 9 WHILE label=null origin=FOR_LOOP_INNER_WHILE OUTGOING -> BB 1 While entry: WHILE label=null origin=FOR_LOOP_INNER_WHILE BB 1 INCOMING <- BB 0, 2 While entry: WHILE label=null origin=FOR_LOOP_INNER_WHILE CONTENT + 1 GET_VAR 'tmp0_iterator: IntIterator' type=kotlin.collections.IntIterator origin=null OUTGOING -> BB 2, 3 CALL 'hasNext(): Boolean' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT BB 2 INCOMING <- BB 1 CALL 'hasNext(): Boolean' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT CONTENT - 1 CALL 'next(): Int' type=kotlin.Int origin=FOR_LOOP_NEXT - 2 VAR val j: kotlin.Int - 3 SET_VAR 'result: Int' type=kotlin.Unit origin=MULTEQ + 1 GET_VAR 'tmp0_iterator: IntIterator' type=kotlin.collections.IntIterator origin=null + 2 CALL 'next(): Int' type=kotlin.Int origin=FOR_LOOP_NEXT + 3 VAR val j: kotlin.Int + 4 SET_VAR 'result: Int' type=kotlin.Unit origin=MULTEQ OUTGOING -> BB 1 While entry: WHILE label=null origin=FOR_LOOP_INNER_WHILE BB 3 diff --git a/compiler/testData/ir/irCfg/loop/isPerfect.txt b/compiler/testData/ir/irCfg/loop/isPerfect.txt index 2eea9851405..54c19f063fb 100644 --- a/compiler/testData/ir/irCfg/loop/isPerfect.txt +++ b/compiler/testData/ir/irCfg/loop/isPerfect.txt @@ -5,24 +5,36 @@ CONTENT 1 FUN public fun isPerfect(n: kotlin.Int): kotlin.Boolean 2 CONST Int type=kotlin.Int value='1' 3 VAR var sum: kotlin.Int - 4 CALL 'iterator(): IntIterator' type=kotlin.collections.IntIterator origin=FOR_LOOP_ITERATOR - 5 VAR IR_TEMPORARY_VARIABLE val tmp0_iterator: kotlin.collections.IntIterator - 6 WHILE label=null origin=FOR_LOOP_INNER_WHILE + 4 CONST Int type=kotlin.Int value='2' + 5 GET_VAR 'value-parameter n: Int' type=kotlin.Int origin=null + 6 CONST Int type=kotlin.Int value='2' + 7 CALL 'div(Int): Int' type=kotlin.Int origin=DIV + 8 CALL 'rangeTo(Int): IntRange' type=kotlin.ranges.IntRange origin=RANGE + 9 CALL 'iterator(): IntIterator' type=kotlin.collections.IntIterator origin=FOR_LOOP_ITERATOR + 10 VAR IR_TEMPORARY_VARIABLE val tmp0_iterator: kotlin.collections.IntIterator + 11 WHILE label=null origin=FOR_LOOP_INNER_WHILE OUTGOING -> BB 1 While entry: WHILE label=null origin=FOR_LOOP_INNER_WHILE BB 1 INCOMING <- BB 0, 3, 6 While entry: WHILE label=null origin=FOR_LOOP_INNER_WHILE CONTENT + 1 GET_VAR 'tmp0_iterator: IntIterator' type=kotlin.collections.IntIterator origin=null OUTGOING -> BB 2, 7 CALL 'hasNext(): Boolean' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT BB 2 INCOMING <- BB 1 CALL 'hasNext(): Boolean' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT CONTENT - 1 CALL 'next(): Int' type=kotlin.Int origin=FOR_LOOP_NEXT - 2 VAR val m: kotlin.Int - 3 WHEN type=kotlin.Unit origin=null + 1 GET_VAR 'tmp0_iterator: IntIterator' type=kotlin.collections.IntIterator origin=null + 2 CALL 'next(): Int' type=kotlin.Int origin=FOR_LOOP_NEXT + 3 VAR val m: kotlin.Int + 4 WHEN type=kotlin.Unit origin=null + 5 GET_VAR 'value-parameter n: Int' type=kotlin.Int origin=null + 6 GET_VAR 'm: Int' type=kotlin.Int origin=null + 7 CALL 'mod(Int): Int' type=kotlin.Int origin=PERC + 8 CONST Int type=kotlin.Int value='0' + 9 CALL 'compareTo(Int): Int' type=kotlin.Int origin=GT OUTGOING -> BB 3, 4 CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT BB 3 @@ -38,6 +50,9 @@ INCOMING <- BB 2 CONTENT 1 SET_VAR 'sum: Int' type=kotlin.Unit origin=PLUSEQ 2 WHEN type=kotlin.Unit origin=null + 3 GET_VAR 'sum: Int' type=kotlin.Int origin=null + 4 GET_VAR 'value-parameter n: Int' type=kotlin.Int origin=null + 5 CALL 'compareTo(Int): Int' type=kotlin.Int origin=GT OUTGOING -> BB 5, 6 CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT BB 5 @@ -63,8 +78,10 @@ BB 8 INCOMING <- BB 5, 7 While exit: WHILE label=null origin=FOR_LOOP_INNER_WHILE CONTENT - 1 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ - 2 RETURN type=kotlin.Nothing from='isPerfect(Int): Boolean' + 1 GET_VAR 'sum: Int' type=kotlin.Int origin=null + 2 GET_VAR 'value-parameter n: Int' type=kotlin.Int origin=null + 3 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ + 4 RETURN type=kotlin.Nothing from='isPerfect(Int): Boolean' OUTGOING -> NONE Function exit: FUN public fun isPerfect(n: kotlin.Int): kotlin.Boolean diff --git a/compiler/testData/ir/irCfg/sequentialFun.txt b/compiler/testData/ir/irCfg/sequentialFun.txt index b26a71f2edd..6be37bda118 100644 --- a/compiler/testData/ir/irCfg/sequentialFun.txt +++ b/compiler/testData/ir/irCfg/sequentialFun.txt @@ -3,10 +3,12 @@ BB 0 CONTENT 1 FUN public fun foo(arg: kotlin.Int): kotlin.Int - 2 CALL 'times(Int): Int' type=kotlin.Int origin=MUL - 3 VAR val dbl: kotlin.Int - 4 GET_VAR 'dbl: Int' type=kotlin.Int origin=null - 5 RETURN type=kotlin.Nothing from='foo(Int): Int' + 2 GET_VAR 'value-parameter arg: Int' type=kotlin.Int origin=null + 3 CONST Int type=kotlin.Int value='2' + 4 CALL 'times(Int): Int' type=kotlin.Int origin=MUL + 5 VAR val dbl: kotlin.Int + 6 GET_VAR 'dbl: Int' type=kotlin.Int origin=null + 7 RETURN type=kotlin.Nothing from='foo(Int): Int' OUTGOING -> NONE Function exit: FUN public fun foo(arg: kotlin.Int): kotlin.Int diff --git a/compiler/testData/ir/irCfg/when/cascadeIf.txt b/compiler/testData/ir/irCfg/when/cascadeIf.txt index f18fdeeacce..00f2d34f4d4 100644 --- a/compiler/testData/ir/irCfg/when/cascadeIf.txt +++ b/compiler/testData/ir/irCfg/when/cascadeIf.txt @@ -4,12 +4,18 @@ BB 0 CONTENT 1 FUN public fun compare(x: kotlin.Int, y: kotlin.Int): kotlin.Int 2 WHEN type=kotlin.Int origin=WHEN + 3 GET_VAR 'value-parameter x: Int' type=kotlin.Int origin=null + 4 GET_VAR 'value-parameter y: Int' type=kotlin.Int origin=null + 5 CALL 'compareTo(Int): Int' type=kotlin.Int origin=GT OUTGOING -> BB 1, 3 CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT BB 1 INCOMING <- BB 0 CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT CONTENT + 1 GET_VAR 'value-parameter x: Int' type=kotlin.Int origin=null + 2 GET_VAR 'value-parameter y: Int' type=kotlin.Int origin=null + 3 CALL 'compareTo(Int): Int' type=kotlin.Int origin=LT OUTGOING -> BB 2, 4 CALL 'LT0(Int): Boolean' type=kotlin.Boolean origin=LT BB 2 diff --git a/compiler/testData/ir/irCfg/when/expressionIf.txt b/compiler/testData/ir/irCfg/when/expressionIf.txt index e9a440ddcc3..e8c3ea64715 100644 --- a/compiler/testData/ir/irCfg/when/expressionIf.txt +++ b/compiler/testData/ir/irCfg/when/expressionIf.txt @@ -4,6 +4,9 @@ BB 0 CONTENT 1 FUN public fun max(x: kotlin.Int, y: kotlin.Int): kotlin.Int 2 WHEN type=kotlin.Int origin=null + 3 GET_VAR 'value-parameter x: Int' type=kotlin.Int origin=null + 4 GET_VAR 'value-parameter y: Int' type=kotlin.Int origin=null + 5 CALL 'compareTo(Int): Int' type=kotlin.Int origin=GT OUTGOING -> BB 1, 2 CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT BB 1 diff --git a/compiler/testData/ir/irCfg/when/ifChain.txt b/compiler/testData/ir/irCfg/when/ifChain.txt index fb6bb644a70..05e7baa50ba 100644 --- a/compiler/testData/ir/irCfg/when/ifChain.txt +++ b/compiler/testData/ir/irCfg/when/ifChain.txt @@ -4,6 +4,8 @@ BB 0 CONTENT 1 FUN public fun minBiRoot(a: kotlin.Double, b: kotlin.Double, c: kotlin.Double): kotlin.Double 2 WHEN type=kotlin.Unit origin=null + 3 GET_VAR 'value-parameter a: Double' type=kotlin.Double origin=null + 4 CONST Double type=kotlin.Double value='0.0' OUTGOING -> BB 1, 6 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ BB 1 @@ -11,6 +13,8 @@ INCOMING <- BB 0 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ CONTENT 1 WHEN type=kotlin.Unit origin=null + 2 GET_VAR 'value-parameter b: Double' type=kotlin.Double origin=null + 3 CONST Double type=kotlin.Double value='0.0' OUTGOING -> BB 2, 3 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ BB 2 @@ -25,9 +29,15 @@ BB 3 INCOMING <- BB 1 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ CONTENT - 1 CALL 'div(Double): Double' type=kotlin.Double origin=DIV - 2 VAR val bc: kotlin.Double - 3 WHEN type=kotlin.Unit origin=null + 1 GET_VAR 'value-parameter c: Double' type=kotlin.Double origin=null + 2 CALL 'unaryMinus(): Double' type=kotlin.Double origin=UMINUS + 3 GET_VAR 'value-parameter b: Double' type=kotlin.Double origin=null + 4 CALL 'div(Double): Double' type=kotlin.Double origin=DIV + 5 VAR val bc: kotlin.Double + 6 WHEN type=kotlin.Unit origin=null + 7 GET_VAR 'bc: Double' type=kotlin.Double origin=null + 8 CONST Double type=kotlin.Double value='0.0' + 9 CALL 'compareTo(Double): Int' type=kotlin.Int origin=LT OUTGOING -> BB 4, 5 CALL 'LT0(Int): Boolean' type=kotlin.Boolean origin=LT BB 4 @@ -42,17 +52,29 @@ BB 5 INCOMING <- BB 3 CALL 'LT0(Int): Boolean' type=kotlin.Boolean origin=LT CONTENT - 1 CALL 'unaryMinus(): Double' type=kotlin.Double origin=UMINUS - 2 RETURN type=kotlin.Nothing from='minBiRoot(Double, Double, Double): Double' + 1 GET_VAR 'bc: Double' type=kotlin.Double origin=null + 2 CALL 'unaryMinus(): Double' type=kotlin.Double origin=UMINUS + 3 RETURN type=kotlin.Nothing from='minBiRoot(Double, Double, Double): Double' OUTGOING -> NONE Function exit: FUN public fun minBiRoot(a: kotlin.Double, b: kotlin.Double, c: kotlin.Double): kotlin.Double BB 6 INCOMING <- BB 0 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ CONTENT - 1 CALL 'minus(Double): Double' type=kotlin.Double origin=MINUS - 2 VAR val d: kotlin.Double - 3 WHEN type=kotlin.Unit origin=null + 1 GET_VAR 'value-parameter b: Double' type=kotlin.Double origin=null + 2 GET_VAR 'value-parameter b: Double' type=kotlin.Double origin=null + 3 CALL 'times(Double): Double' type=kotlin.Double origin=MUL + 4 CONST Int type=kotlin.Int value='4' + 5 GET_VAR 'value-parameter a: Double' type=kotlin.Double origin=null + 6 CALL 'times(Double): Double' type=kotlin.Double origin=MUL + 7 GET_VAR 'value-parameter c: Double' type=kotlin.Double origin=null + 8 CALL 'times(Double): Double' type=kotlin.Double origin=MUL + 9 CALL 'minus(Double): Double' type=kotlin.Double origin=MINUS + 10 VAR val d: kotlin.Double + 11 WHEN type=kotlin.Unit origin=null + 12 GET_VAR 'd: Double' type=kotlin.Double origin=null + 13 CONST Double type=kotlin.Double value='0.0' + 14 CALL 'compareTo(Double): Int' type=kotlin.Int origin=LT OUTGOING -> BB 7, 8 CALL 'LT0(Int): Boolean' type=kotlin.Boolean origin=LT BB 7 @@ -67,11 +89,28 @@ BB 8 INCOMING <- BB 6 CALL 'LT0(Int): Boolean' type=kotlin.Boolean origin=LT CONTENT - 1 CALL 'div(Double): Double' type=kotlin.Double origin=DIV - 2 VAR val y1: kotlin.Double - 3 CALL 'div(Double): Double' type=kotlin.Double origin=DIV - 4 VAR val y2: kotlin.Double - 5 WHEN type=kotlin.Double origin=null + 1 GET_VAR 'value-parameter b: Double' type=kotlin.Double origin=null + 2 CALL 'unaryMinus(): Double' type=kotlin.Double origin=UMINUS + 3 GET_VAR 'd: Double' type=kotlin.Double origin=null + 4 CALL 'plus(Double): Double' type=kotlin.Double origin=PLUS + 5 CONST Int type=kotlin.Int value='2' + 6 GET_VAR 'value-parameter a: Double' type=kotlin.Double origin=null + 7 CALL 'times(Double): Double' type=kotlin.Double origin=MUL + 8 CALL 'div(Double): Double' type=kotlin.Double origin=DIV + 9 VAR val y1: kotlin.Double + 10 GET_VAR 'value-parameter b: Double' type=kotlin.Double origin=null + 11 CALL 'unaryMinus(): Double' type=kotlin.Double origin=UMINUS + 12 GET_VAR 'd: Double' type=kotlin.Double origin=null + 13 CALL 'minus(Double): Double' type=kotlin.Double origin=MINUS + 14 CONST Int type=kotlin.Int value='2' + 15 GET_VAR 'value-parameter a: Double' type=kotlin.Double origin=null + 16 CALL 'times(Double): Double' type=kotlin.Double origin=MUL + 17 CALL 'div(Double): Double' type=kotlin.Double origin=DIV + 18 VAR val y2: kotlin.Double + 19 WHEN type=kotlin.Double origin=null + 20 GET_VAR 'y1: Double' type=kotlin.Double origin=null + 21 GET_VAR 'y2: Double' type=kotlin.Double origin=null + 22 CALL 'compareTo(Double): Int' type=kotlin.Int origin=GT OUTGOING -> BB 9, 10 CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT BB 9 @@ -100,6 +139,9 @@ INCOMING <- BB 10, 11 CONTENT 1 VAR val y3: kotlin.Double 2 WHEN type=kotlin.Double origin=null + 3 GET_VAR 'y3: Double' type=kotlin.Double origin=null + 4 CONST Double type=kotlin.Double value='0.0' + 5 CALL 'compareTo(Double): Int' type=kotlin.Int origin=LT OUTGOING -> BB 13, 14 CALL 'LT0(Int): Boolean' type=kotlin.Boolean origin=LT BB 13 @@ -119,7 +161,8 @@ BB 15 INCOMING <- BB 13 CONST Boolean type=kotlin.Boolean value='true' CONTENT - 1 CALL 'unaryMinus(): Double' type=kotlin.Double origin=UMINUS + 1 GET_VAR 'y3: Double' type=kotlin.Double origin=null + 2 CALL 'unaryMinus(): Double' type=kotlin.Double origin=UMINUS OUTGOING -> BB 16 When exit: WHEN type=kotlin.Double origin=null BB 16 diff --git a/compiler/testData/ir/irCfg/when/whenReturn.txt b/compiler/testData/ir/irCfg/when/whenReturn.txt index a8c8157a1ad..078317f60fc 100644 --- a/compiler/testData/ir/irCfg/when/whenReturn.txt +++ b/compiler/testData/ir/irCfg/when/whenReturn.txt @@ -6,24 +6,32 @@ CONTENT 2 GET_VAR 'value-parameter grade: String' type=kotlin.String origin=null 3 VAR IR_TEMPORARY_VARIABLE val tmp0_subject: kotlin.String 4 WHEN type=kotlin.Nothing origin=WHEN + 5 GET_VAR 'tmp0_subject: String' type=kotlin.String origin=null + 6 CONST String type=kotlin.String value='A' OUTGOING -> BB 1, 5 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ BB 1 INCOMING <- BB 0 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ CONTENT + 1 GET_VAR 'tmp0_subject: String' type=kotlin.String origin=null + 2 CONST String type=kotlin.String value='B' OUTGOING -> BB 2, 6 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ BB 2 INCOMING <- BB 1 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ CONTENT + 1 GET_VAR 'tmp0_subject: String' type=kotlin.String origin=null + 2 CONST String type=kotlin.String value='C' OUTGOING -> BB 3, 7 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ BB 3 INCOMING <- BB 2 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ CONTENT + 1 GET_VAR 'tmp0_subject: String' type=kotlin.String origin=null + 2 CONST String type=kotlin.String value='D' OUTGOING -> BB 4, 8 CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ BB 4