Break / continue implementation, test with break / continue, related changes in loop & loop tests
This commit is contained in:
committed by
Dmitry Petrov
parent
e03e13af43
commit
5a04c72e75
+34
-6
@@ -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? {
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user