Skip to content

Commit 17fbe28

Browse files
committed
Added method to convert IRProgram to a set of CFG's
1 parent 019de20 commit 17fbe28

2 files changed

Lines changed: 79 additions & 20 deletions

File tree

src/main/kotlin/deep/decaf/low/CFG.kt

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package deep.decaf.low
22

33
import deep.decaf.ir.*
4+
import java.lang.RuntimeException
45
import java.util.*
56

67
interface CFGNode {
@@ -67,6 +68,7 @@ class ConditionalNode(
6768
sealed class ConditionalNodeType
6869
object IfElse : ConditionalNodeType()
6970
data class For(val id: Int) : ConditionalNodeType()
71+
data class MethodEnd(val name: String) : ConditionalNodeType()
7072

7173
sealed class JumpNodes(
7274
override var next: CFGNode?,
@@ -172,6 +174,12 @@ class CFGCreationInfo {
172174
}
173175
}
174176

177+
data class CFGProgram(
178+
val mainCFG: CFG,
179+
val cfgMap: Map<String, CFG>,
180+
val declarations: List<IRFieldDeclaration>
181+
)
182+
175183
fun constructCFG(statement: IRStatement, info: CFGCreationInfo): CFG {
176184
return when (statement) {
177185
is IRAssignStatement -> {
@@ -456,6 +464,62 @@ fun constructCFG(block: IRBlock?, info: CFGCreationInfo): CFG? {
456464
}
457465
}
458466

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+
459523
private fun cfgNodeLabel(node: CFGNode): String {
460524
return when (node) {
461525
is RegularNode -> node.statements.joinToString("\n") { irToString(it) }

src/main/kotlin/deep/decaf/tester/CFGCreationTester.kt

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import deep.decaf.parser.*
66
import org.antlr.v4.runtime.*
77
import java.io.*
88

9-
fun main(args: Array<String>) {
9+
fun main() {
1010
val folder = File("/home/deep/work/compiler/cfg_test")
1111
val files = folder.listFiles()!!.filter { !it.isDirectory }.sorted()
1212
for (file in files) {
@@ -16,24 +16,19 @@ fun main(args: Array<String>) {
1616
val errors = checkSemantics(irTree)
1717
if (errors.isNotEmpty())
1818
throw RuntimeException("Invalid program")
19-
val cfgCreationInfo = CFGCreationInfo()
20-
for (method in irTree.methodDeclarations) {
21-
if (method.name == "main") {
22-
val cfg = constructCFG(method.block, cfgCreationInfo)
23-
val dotString = dotFileFromCFG(cfg!!)
24-
println(dotString)
25-
val processBuilder = ProcessBuilder(
26-
listOf("dot", "-Tpdf", "-o", "${file.name}.pdf")
27-
)
28-
val outDir = File("/home/deep/work/test")
29-
processBuilder.directory(outDir)
30-
processBuilder.redirectError(File("${outDir.absolutePath}/${file.name}.log"))
31-
val process = processBuilder.start()
32-
val inputWriter = BufferedWriter(OutputStreamWriter(process.outputStream))
33-
inputWriter.write(dotString)
34-
inputWriter.flush()
35-
inputWriter.close()
36-
}
37-
}
19+
val programCFG = constructCFG(irTree)
20+
val dotString = dotFileFromCFG(programCFG.mainCFG)
21+
println(dotString)
22+
val processBuilder = ProcessBuilder(
23+
listOf("dot", "-Tpdf", "-o", "${file.name}.pdf")
24+
)
25+
val outDir = File("/home/deep/work/test")
26+
processBuilder.directory(outDir)
27+
processBuilder.redirectError(File("${outDir.absolutePath}/${file.name}.log"))
28+
val process = processBuilder.start()
29+
val inputWriter = BufferedWriter(OutputStreamWriter(process.outputStream))
30+
inputWriter.write(dotString)
31+
inputWriter.flush()
32+
inputWriter.close()
3833
}
3934
}

0 commit comments

Comments
 (0)