Break / continue implementation, test with break / continue, related changes in loop & loop tests

This commit is contained in:
Mikhail Glukhikh
2016-09-23 15:24:38 +03:00
committed by Dmitry Petrov
parent e03e13af43
commit 5a04c72e75
6 changed files with 135 additions and 6 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.ir2cfg.graph.ControlFlowGraph
import org.jetbrains.kotlin.ir2cfg.nodes.MergeCfgElement
@@ -31,6 +32,10 @@ class FunctionGenerator(val function: IrFunction) {
val exit = MergeCfgElement(function, "Function exit")
val loopEntries = mutableMapOf<IrLoop, IrElement>()
val loopExits = mutableMapOf<IrLoop, IrElement>()
fun generate(): ControlFlowGraph {
val visitor = FunctionVisitor()
function.accept(visitor, true)
@@ -130,7 +135,10 @@ class FunctionGenerator(val function: IrFunction) {
if (data) {
builder.add(loop)
}
val exit = MergeCfgElement(loop, "While exit")
loopExits[loop] = exit
val entry = MergeCfgElement(loop, "While entry")
loopEntries[loop] = entry
builder.jump(entry)
val condition = loop.condition
condition.process(includeSelf = false)
@@ -139,25 +147,45 @@ class FunctionGenerator(val function: IrFunction) {
if (!body?.process().isNothing()) {
builder.jump(entry)
}
builder.move(condition)
return condition
builder.jump(exit, from = condition)
return exit
}
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: Boolean): IrElement? {
if (data) {
builder.add(loop)
}
val exit = MergeCfgElement(loop, "Do..while exit")
loopExits[loop] = exit
val entry = MergeCfgElement(loop, "Do..while entry")
loopEntries[loop] = entry
builder.jump(entry)
val body = loop.body
val condition = loop.condition
if (body?.process() !is IrReturn) {
if (!body?.process().isNothing()) {
condition.process(includeSelf = false)
builder.jump(condition)
builder.jump(entry)
builder.move(condition)
builder.jump(entry, from = condition)
builder.jump(exit, from = condition)
}
return condition
builder.move(exit)
return exit
}
override fun visitBreak(jump: IrBreak, data: Boolean): IrElement? {
if (data) {
builder.add(jump)
}
builder.jump(loopExits[jump.loop] ?: throw AssertionError("Loop exit not found for ${jump.loop.dump()}"))
return jump
}
override fun visitContinue(jump: IrContinue, data: Boolean): IrElement? {
if (data) {
builder.add(jump)
}
builder.jump(loopEntries[jump.loop] ?: throw AssertionError("Loop entry not found for ${jump.loop.dump()}"))
return jump
}
override fun visitElement(element: IrElement, data: Boolean): IrElement? {
+6
View File
@@ -40,6 +40,12 @@ OUTGOING -> BB 1
BB 5
INCOMING <- BB 3
CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT
CONTENT
OUTGOING -> BB 6
Do..while exit: DO_WHILE label=null origin=DO_WHILE_LOOP
BB 6
INCOMING <- BB 5
Do..while exit: DO_WHILE label=null origin=DO_WHILE_LOOP
CONTENT
1 GET_VAR 'count: Int' type=kotlin.Int origin=null
2 RETURN type=kotlin.Nothing from='digitCountInNumber(Int, Int): Int'
+6
View File
@@ -28,6 +28,12 @@ OUTGOING -> BB 1
BB 3
INCOMING <- BB 1
CALL 'hasNext(): Boolean' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT
CONTENT
OUTGOING -> BB 4
While exit: WHILE label=null origin=FOR_LOOP_INNER_WHILE
BB 4
INCOMING <- BB 3
While exit: WHILE label=null origin=FOR_LOOP_INNER_WHILE
CONTENT
1 GET_VAR 'result: Int' type=kotlin.Int origin=null
2 RETURN type=kotlin.Nothing from='factorial(Int): Int'
+9
View File
@@ -0,0 +1,9 @@
fun isPerfect(n: Int): Boolean {
var sum = 1
for (m in 2..n/2) {
if (n % m > 0) continue
sum += m
if (sum > n) break
}
return sum == n
}
+74
View File
@@ -0,0 +1,74 @@
// FILE: /isPerfect.kt
// FUN: isPerfect
BB 0
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
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
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
OUTGOING -> BB 3, 4
CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT
BB 3
INCOMING <- BB 2
CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT
CONTENT
1 CONTINUE label=null loop.label=null
OUTGOING -> BB 1
While entry: WHILE label=null origin=FOR_LOOP_INNER_WHILE
BB 4
INCOMING <- BB 2
CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT
CONTENT
1 SET_VAR 'sum: Int' type=kotlin.Unit origin=PLUSEQ
2 WHEN type=kotlin.Unit origin=null
OUTGOING -> BB 5, 6
CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT
BB 5
INCOMING <- BB 4
CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT
CONTENT
1 BREAK label=null loop.label=null
OUTGOING -> BB 8
While exit: WHILE label=null origin=FOR_LOOP_INNER_WHILE
BB 6
INCOMING <- BB 4
CALL 'GT0(Int): Boolean' type=kotlin.Boolean origin=GT
CONTENT
OUTGOING -> BB 1
While entry: WHILE label=null origin=FOR_LOOP_INNER_WHILE
BB 7
INCOMING <- BB 1
CALL 'hasNext(): Boolean' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT
CONTENT
OUTGOING -> BB 8
While exit: WHILE label=null origin=FOR_LOOP_INNER_WHILE
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'
OUTGOING -> NONE
Function exit: FUN public fun isPerfect(n: kotlin.Int): kotlin.Boolean
// END FUN: isPerfect
// END FILE: /isPerfect.kt
@@ -90,6 +90,12 @@ public class IrCfgTestCaseGenerated extends AbstractIrCfgTestCase {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irCfg/loop/factorial.kt");
doTest(fileName);
}
@TestMetadata("isPerfect.kt")
public void testIsPerfect() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irCfg/loop/isPerfect.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/ir/irCfg/when")