|
1 | 1 | package deep.decaf.low |
2 | 2 |
|
3 | 3 | import deep.decaf.ir.* |
| 4 | +import java.lang.RuntimeException |
4 | 5 | import java.util.* |
5 | 6 |
|
6 | 7 | interface CFGNode { |
@@ -67,6 +68,7 @@ class ConditionalNode( |
67 | 68 | sealed class ConditionalNodeType |
68 | 69 | object IfElse : ConditionalNodeType() |
69 | 70 | data class For(val id: Int) : ConditionalNodeType() |
| 71 | +data class MethodEnd(val name: String) : ConditionalNodeType() |
70 | 72 |
|
71 | 73 | sealed class JumpNodes( |
72 | 74 | override var next: CFGNode?, |
@@ -172,6 +174,12 @@ class CFGCreationInfo { |
172 | 174 | } |
173 | 175 | } |
174 | 176 |
|
| 177 | +data class CFGProgram( |
| 178 | + val mainCFG: CFG, |
| 179 | + val cfgMap: Map<String, CFG>, |
| 180 | + val declarations: List<IRFieldDeclaration> |
| 181 | +) |
| 182 | + |
175 | 183 | fun constructCFG(statement: IRStatement, info: CFGCreationInfo): CFG { |
176 | 184 | return when (statement) { |
177 | 185 | is IRAssignStatement -> { |
@@ -456,6 +464,62 @@ fun constructCFG(block: IRBlock?, info: CFGCreationInfo): CFG? { |
456 | 464 | } |
457 | 465 | } |
458 | 466 |
|
| 467 | +fun constructCFG(program: IRProgram): CFGProgram { |
| 468 | + val methodCFGMap = mutableMapOf<String, CFG>() |
| 469 | + var mainCFG: CFG? = null |
| 470 | + for (method in program.methodDeclarations) { |
| 471 | + val info = CFGCreationInfo() |
| 472 | + val cfg = constructCFG(method.block, info) |
| 473 | + if (cfg != null) { |
| 474 | + // Rewire returns to point to end of method |
| 475 | + val endMethod = ExitNoOpNode(mutableListOf(cfg.exit), null, MethodEnd(method.name)) |
| 476 | + cfg.exit.next = endMethod |
| 477 | + |
| 478 | + val visited = mutableMapOf<String, Boolean>() |
| 479 | + fun dfs(node: CFGNode) { |
| 480 | + val done = visited[node.uuid] ?: false |
| 481 | + if (!done) { |
| 482 | + visited[node.uuid] = true |
| 483 | + if (node is ReturnNode) { |
| 484 | + val next = node.next |
| 485 | + if (next != null) { |
| 486 | + if (next is SingleInput) { |
| 487 | + next.prev = null |
| 488 | + } else if (next is NoOpNode) { |
| 489 | + next.prevs.remove(node) |
| 490 | + } |
| 491 | + } |
| 492 | + node.next = endMethod |
| 493 | + endMethod.prevs.add(node) |
| 494 | + } else { |
| 495 | + if (node is SingleOutput && node.next != null) { |
| 496 | + dfs(node.next!!) |
| 497 | + } else if (node is ConditionalNode) { |
| 498 | + if (node.truePath != null) { |
| 499 | + dfs(node.truePath!!) |
| 500 | + } |
| 501 | + if (node.falsePath != null) { |
| 502 | + dfs(node.falsePath!!) |
| 503 | + } |
| 504 | + } |
| 505 | + } |
| 506 | + } |
| 507 | + } |
| 508 | + |
| 509 | + dfs(cfg.entry) |
| 510 | + methodCFGMap[method.name] = CFG(cfg.entry, endMethod) |
| 511 | + if (method.name == "main") { |
| 512 | + mainCFG = cfg |
| 513 | + } |
| 514 | + } |
| 515 | + } |
| 516 | + if (mainCFG != null) { |
| 517 | + return CFGProgram(mainCFG, methodCFGMap, program.fieldDeclarations) |
| 518 | + } else { |
| 519 | + throw IllegalStateException("semantic checker screwed up") |
| 520 | + } |
| 521 | +} |
| 522 | + |
459 | 523 | private fun cfgNodeLabel(node: CFGNode): String { |
460 | 524 | return when (node) { |
461 | 525 | is RegularNode -> node.statements.joinToString("\n") { irToString(it) } |
|
0 commit comments