CFG exhaustive when else instruction for KT-8700

This commit is contained in:
Mikhail Glukhikh
2015-12-14 16:08:01 +03:00
committed by Mikhail Glukhikh
parent 697228eae0
commit b805ce06c2
25 changed files with 446 additions and 51 deletions
@@ -0,0 +1,91 @@
== Direction ==
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
---------------------
L0:
1 <START> INIT: in: {} out: {}
L1:
<END>
error:
<ERROR>
sink:
<SINK> USE: in: {} out: {}
=====================
== foo ==
fun foo(dir: Direction): Int {
val res: Int
when (dir) {
Direction.NORTH -> res = 1
Direction.SOUTH -> res = 2
Direction.WEST -> res = 3
Direction.EAST -> res = 4
}
return res
}
---------------------
L0:
1 <START> INIT: in: {} out: {}
v(dir: Direction) INIT: in: {} out: {dir=D}
magic[FAKE_INITIALIZER](dir: Direction) -> <v0> INIT: in: {dir=D} out: {dir=D}
w(dir|<v0>) INIT: in: {dir=D} out: {dir=ID} USE: in: {dir=READ} out: {dir=READ}
2 mark({ val res: Int when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } return res }) INIT: in: {dir=ID} out: {dir=ID}
v(val res: Int) INIT: in: {dir=ID} out: {dir=ID, res=D}
mark(when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }) INIT: in: {dir=ID, res=D} out: {dir=ID, res=D} USE: in: {dir=READ, res=READ} out: {dir=READ, res=READ}
r(dir) -> <v1> USE: in: {res=READ} out: {dir=READ, res=READ}
mark(Direction.NORTH -> res = 1)
mark(Direction.NORTH)
mark(Direction.NORTH)
r(NORTH) -> <v2>
magic[EQUALS_IN_WHEN_CONDITION](Direction.NORTH|<v1>, <v2>) -> <v3>
jmp?(L4|<v3>) USE: in: {res=READ} out: {res=READ}
L3 ['when' entry body]:
r(1) -> <v4> USE: in: {res=WRITTEN_AFTER_READ} out: {res=WRITTEN_AFTER_READ}
w(res|<v4>) INIT: in: {dir=ID, res=D} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=WRITTEN_AFTER_READ}
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID}
L4 [next 'when' entry]:
mark(Direction.SOUTH -> res = 2) INIT: in: {dir=ID, res=D} out: {dir=ID, res=D}
mark(Direction.SOUTH)
mark(Direction.SOUTH)
r(SOUTH) -> <v5>
magic[EQUALS_IN_WHEN_CONDITION](Direction.SOUTH|<v1>, <v5>) -> <v6>
jmp?(L6|<v6>) USE: in: {res=READ} out: {res=READ}
L5 ['when' entry body]:
r(2) -> <v7> USE: in: {res=WRITTEN_AFTER_READ} out: {res=WRITTEN_AFTER_READ}
w(res|<v7>) INIT: in: {dir=ID, res=D} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=WRITTEN_AFTER_READ}
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID}
L6 [next 'when' entry]:
mark(Direction.WEST -> res = 3) INIT: in: {dir=ID, res=D} out: {dir=ID, res=D}
mark(Direction.WEST)
mark(Direction.WEST)
r(WEST) -> <v8>
magic[EQUALS_IN_WHEN_CONDITION](Direction.WEST|<v1>, <v8>) -> <v9>
jmp?(L8|<v9>) USE: in: {res=READ} out: {res=READ}
L7 ['when' entry body]:
r(3) -> <v10> USE: in: {res=WRITTEN_AFTER_READ} out: {res=WRITTEN_AFTER_READ}
w(res|<v10>) INIT: in: {dir=ID, res=D} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=WRITTEN_AFTER_READ}
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID}
L8 [next 'when' entry]:
mark(Direction.EAST -> res = 4) INIT: in: {dir=ID, res=D} out: {dir=ID, res=D}
mark(Direction.EAST)
mark(Direction.EAST)
r(EAST) -> <v11>
magic[EQUALS_IN_WHEN_CONDITION](Direction.EAST|<v1>, <v11>) -> <v12>
jmp?(L10|<v12>) USE: in: {res=READ} out: {res=READ}
L9 ['when' entry body]:
r(4) -> <v13> USE: in: {res=WRITTEN_AFTER_READ} out: {res=WRITTEN_AFTER_READ}
w(res|<v13>) INIT: in: {dir=ID, res=D} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=WRITTEN_AFTER_READ}
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID}
L10 [next 'when' entry]:
magic[EXHAUSTIVE_WHEN_ELSE](when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }) -> <v14> INIT: in: {dir=ID, res=D} out: {dir=ID, res=IED}
L2 [after 'when' expression]:
merge(when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }|!<v15>, !<v16>, !<v17>, !<v18>) -> <v19> INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=READ}
r(res) -> <v20> USE: in: {} out: {res=READ}
ret(*|<v20>) L1
L1:
1 <END> INIT: in: {dir=ID} out: {dir=ID}
error:
<ERROR> INIT: in: {} out: {}
sink:
<SINK> INIT: in: {dir=ID} out: {dir=ID} USE: in: {} out: {}
=====================
@@ -0,0 +1,14 @@
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
fun foo(dir: Direction): Int {
val res: Int
when (dir) {
Direction.NORTH -> res = 1
Direction.SOUTH -> res = 2
Direction.WEST -> res = 3
Direction.EAST -> res = 4
}
return res
}
@@ -0,0 +1,46 @@
== Direction ==
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
---------------------
=====================
== foo ==
fun foo(dir: Direction): Int {
val res: Int
when (dir) {
Direction.NORTH -> res = 1
Direction.SOUTH -> res = 2
Direction.WEST -> res = 3
Direction.EAST -> res = 4
}
return res
}
---------------------
<v0>: Direction NEW: magic[FAKE_INITIALIZER](dir: Direction) -> <v0>
<v14>: * NEW: magic[EXHAUSTIVE_WHEN_ELSE](when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }) -> <v14>
dir <v1>: * NEW: r(dir) -> <v1>
NORTH <v2>: * NEW: r(NORTH) -> <v2>
Direction.NORTH <v2>: * COPY
Direction.NORTH <v3>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.NORTH|<v1>, <v2>) -> <v3>
1 <v4>: Int NEW: r(1) -> <v4>
res = 1 !<v15>: *
SOUTH <v5>: * NEW: r(SOUTH) -> <v5>
Direction.SOUTH <v5>: * COPY
Direction.SOUTH <v6>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.SOUTH|<v1>, <v5>) -> <v6>
2 <v7>: Int NEW: r(2) -> <v7>
res = 2 !<v16>: *
WEST <v8>: * NEW: r(WEST) -> <v8>
Direction.WEST <v8>: * COPY
Direction.WEST <v9>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.WEST|<v1>, <v8>) -> <v9>
3 <v10>: Int NEW: r(3) -> <v10>
res = 3 !<v17>: *
EAST <v11>: * NEW: r(EAST) -> <v11>
Direction.EAST <v11>: * COPY
Direction.EAST <v12>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](Direction.EAST|<v1>, <v11>) -> <v12>
4 <v13>: Int NEW: r(4) -> <v13>
res = 4 !<v18>: *
when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } <v19>: * NEW: merge(when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }|!<v15>, !<v16>, !<v17>, !<v18>) -> <v19>
res <v20>: Int NEW: r(res) -> <v20>
return res !<v21>: *
{ val res: Int when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } return res } !<v21>: * COPY
=====================
@@ -18,29 +18,29 @@ L0:
mark(true)
r(true) -> <v2>
magic[EQUALS_IN_WHEN_CONDITION](true|<v1>, <v2>) -> <v3>
jmp?(L4|<v3>) NEXT:[mark(false -> return 0), r(1) -> <v4>]
jmp?(L4|<v3>) NEXT:[mark(false -> return 0), r(1) -> <v4>]
L3 ['when' entry body]:
r(1) -> <v4>
ret(*|<v4>) L1 NEXT:[<END>]
- jmp(L2) NEXT:[merge(when (flag) { true -> return 1 false -> return 0 }|!<v8>, !<v9>) -> <v10>] PREV:[]
ret(*|<v4>) L1 NEXT:[<END>]
- jmp(L2) NEXT:[merge(when (flag) { true -> return 1 false -> return 0 }|!<v9>, !<v10>) -> <v11>] PREV:[]
L4 [next 'when' entry]:
mark(false -> return 0) PREV:[jmp?(L4|<v3>)]
mark(false -> return 0) PREV:[jmp?(L4|<v3>)]
mark(false)
r(false) -> <v5>
magic[EQUALS_IN_WHEN_CONDITION](false|<v1>, <v5>) -> <v6>
jmp?(L6|<v6>) NEXT:[jmp(error), r(0) -> <v7>]
jmp?(L6|<v6>) NEXT:[magic[EXHAUSTIVE_WHEN_ELSE](when (flag) { true -> return 1 false -> return 0 }) -> <v8>, r(0) -> <v7>]
L5 ['when' entry body]:
r(0) -> <v7>
ret(*|<v7>) L1 NEXT:[<END>]
- jmp(L2) NEXT:[merge(when (flag) { true -> return 1 false -> return 0 }|!<v8>, !<v9>) -> <v10>] PREV:[]
ret(*|<v7>) L1 NEXT:[<END>]
- jmp(L2) NEXT:[merge(when (flag) { true -> return 1 false -> return 0 }|!<v9>, !<v10>) -> <v11>] PREV:[]
L6 [next 'when' entry]:
jmp(error) NEXT:[<ERROR>] PREV:[jmp?(L6|<v6>)]
magic[EXHAUSTIVE_WHEN_ELSE](when (flag) { true -> return 1 false -> return 0 }) -> <v8> PREV:[jmp?(L6|<v6>)]
L2 [after 'when' expression]:
- merge(when (flag) { true -> return 1 false -> return 0 }|!<v8>, !<v9>) -> <v10> PREV:[]
- merge(when (flag) { true -> return 1 false -> return 0 }|!<v9>, !<v10>) -> <v11>
L1:
1 <END> NEXT:[<SINK>] PREV:[ret(*|<v4>) L1, ret(*|<v7>) L1]
1 <END> NEXT:[<SINK>] PREV:[ret(*|<v4>) L1, ret(*|<v7>) L1]
error:
<ERROR> PREV:[jmp(error)]
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
<SINK> PREV:[<ERROR>, <END>]
=====================
@@ -7,15 +7,16 @@ fun foo(flag: Boolean): Int {
}
---------------------
<v0>: Boolean NEW: magic[FAKE_INITIALIZER](flag: Boolean) -> <v0>
<v8>: * NEW: magic[EXHAUSTIVE_WHEN_ELSE](when (flag) { true -> return 1 false -> return 0 }) -> <v8>
flag <v1>: * NEW: r(flag) -> <v1>
true <v2>: * NEW: r(true) -> <v2>
true <v3>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](true|<v1>, <v2>) -> <v3>
1 <v4>: Int NEW: r(1) -> <v4>
return 1 !<v8>: *
return 1 !<v9>: *
false <v5>: * NEW: r(false) -> <v5>
false <v6>: * NEW: magic[EQUALS_IN_WHEN_CONDITION](false|<v1>, <v5>) -> <v6>
0 <v7>: Int NEW: r(0) -> <v7>
return 0 !<v9>: *
when (flag) { true -> return 1 false -> return 0 } <v10>: * NEW: merge(when (flag) { true -> return 1 false -> return 0 }|!<v8>, !<v9>) -> <v10>
{ when (flag) { true -> return 1 false -> return 0 } } <v10>: * COPY
return 0 !<v10>: *
when (flag) { true -> return 1 false -> return 0 } <v11>: * NEW: merge(when (flag) { true -> return 1 false -> return 0 }|!<v9>, !<v10>) -> <v11>
{ when (flag) { true -> return 1 false -> return 0 } } <v11>: * COPY
=====================
@@ -0,0 +1,14 @@
enum class Color { RED, GREEN, BLUE }
fun foo(arr: Array<Color>): Color {
loop@ for (color in arr) {
when (color) {
Color.RED -> return color
Color.GREEN -> break@loop
Color.BLUE -> if (arr.size == 1) return color else continue@loop
}
// Unreachable
<!UNREACHABLE_CODE!>return Color.BLUE<!>
}
return Color.GREEN
}
@@ -0,0 +1,25 @@
package
public fun foo(/*0*/ arr: kotlin.Array<Color>): Color
public final enum class Color : kotlin.Enum<Color> {
enum entry RED
enum entry GREEN
enum entry BLUE
private constructor Color()
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Color): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
@kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "Use 'values()' function instead", replaceWith = kotlin.ReplaceWith(expression = "this.values()", imports = {})) public final /*synthesized*/ val values: kotlin.Array<Color>
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): Color
public final /*synthesized*/ fun values(): kotlin.Array<Color>
}
@@ -0,0 +1,11 @@
fun foo(b: Boolean): Int {
val x: Int
val y: Int
when (b) {
true -> y = 1
false -> y = 0
}
// x is initialized here
x = 3
return x + y
}
@@ -0,0 +1,3 @@
package
public fun foo(/*0*/ b: kotlin.Boolean): kotlin.Int
@@ -0,0 +1,14 @@
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
fun foo(dir: Direction): Int {
when (dir) {
Direction.NORTH -> return 1
Direction.SOUTH -> throw AssertionError("!!!")
Direction.WEST -> return 3
Direction.EAST -> return 4
}
// Error: Unreachable code. Return is not required.
<!UNREACHABLE_CODE!>if (dir == Direction.SOUTH) return 2<!>
}
@@ -0,0 +1,27 @@
package
public fun foo(/*0*/ dir: Direction): kotlin.Int
public final enum class Direction : kotlin.Enum<Direction> {
enum entry NORTH
enum entry SOUTH
enum entry WEST
enum entry EAST
private constructor Direction()
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Direction): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
@kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "Use 'values()' function instead", replaceWith = kotlin.ReplaceWith(expression = "this.values()", imports = {})) public final /*synthesized*/ val values: kotlin.Array<Direction>
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): Direction
public final /*synthesized*/ fun values(): kotlin.Array<Direction>
}
@@ -0,0 +1,22 @@
fun foo(a: Boolean, b: Boolean): Int {
val x: Int
if (a) {
x = 1
}
when (b) {
true -> <!VAL_REASSIGNMENT!>x<!> = 2
false -> x = 3
}
return x
}
fun bar(a: Boolean, b: Boolean): Int {
val x: Int
if (a) {
x = 1
}
when (b) {
false -> <!VAL_REASSIGNMENT!>x<!> = 3
}
return <!UNINITIALIZED_VARIABLE!>x<!>
}
@@ -0,0 +1,4 @@
package
public fun bar(/*0*/ a: kotlin.Boolean, /*1*/ b: kotlin.Boolean): kotlin.Int
public fun foo(/*0*/ a: kotlin.Boolean, /*1*/ b: kotlin.Boolean): kotlin.Int
@@ -0,0 +1,22 @@
fun foo(a: Boolean, b: Boolean): Int {
var x: Int
if (a) {
x = 1
}
when (b) {
true -> x = 2
false -> x = 3
}
return x
}
fun bar(a: Boolean, b: Boolean): Int {
var x: Int
if (a) {
x = 1
}
when (b) {
false -> x = 3
}
return <!UNINITIALIZED_VARIABLE!>x<!>
}
@@ -0,0 +1,4 @@
package
public fun bar(/*0*/ a: kotlin.Boolean, /*1*/ b: kotlin.Boolean): kotlin.Int
public fun foo(/*0*/ a: kotlin.Boolean, /*1*/ b: kotlin.Boolean): kotlin.Int