mirror of
https://github.com/irmen/prog8.git
synced 2025-02-04 02:30:19 +00:00
tests for callgraph and unused subroutine removal in optimizer
This commit is contained in:
parent
82d3d81bb2
commit
df2d5c6585
91
compiler/test/TestCallgraph.kt
Normal file
91
compiler/test/TestCallgraph.kt
Normal file
@ -0,0 +1,91 @@
|
||||
package prog8tests
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.compiler.target.C64Target
|
||||
import prog8.optimizer.CallGraph
|
||||
import prog8tests.helpers.assertSuccess
|
||||
import prog8tests.helpers.compileText
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class TestCallgraph {
|
||||
@Test
|
||||
fun testGraphForEmptySubs() {
|
||||
val sourcecode = """
|
||||
%import string
|
||||
main {
|
||||
sub start() {
|
||||
}
|
||||
sub empty() {
|
||||
}
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target, false, sourcecode).assertSuccess()
|
||||
val graph = CallGraph(result.programAst)
|
||||
|
||||
assertEquals(1, graph.imports.size)
|
||||
assertEquals(1, graph.importedBy.size)
|
||||
val toplevelModule = result.programAst.toplevelModule
|
||||
val importedModule = graph.imports.getValue(toplevelModule).single()
|
||||
assertEquals("string", importedModule.name)
|
||||
val importedBy = graph.importedBy.getValue(importedModule).single()
|
||||
assertTrue(importedBy.name.startsWith("on_the_fly_test"))
|
||||
|
||||
assertFalse(graph.unused(toplevelModule))
|
||||
assertFalse(graph.unused(importedModule))
|
||||
|
||||
val mainBlock = toplevelModule.statements.filterIsInstance<Block>().single()
|
||||
for(stmt in mainBlock.statements) {
|
||||
val sub = stmt as Subroutine
|
||||
assertFalse(sub in graph.calls)
|
||||
assertFalse(sub in graph.calledBy)
|
||||
|
||||
if(sub === result.programAst.entrypoint)
|
||||
assertFalse(graph.unused(sub), "start() should always be marked as used to avoid having it removed")
|
||||
else
|
||||
assertTrue(graph.unused(sub))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGraphForEmptyButReferencedSub() {
|
||||
val sourcecode = """
|
||||
%import string
|
||||
main {
|
||||
sub start() {
|
||||
uword xx = &empty
|
||||
xx++
|
||||
}
|
||||
sub empty() {
|
||||
}
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target, false, sourcecode).assertSuccess()
|
||||
val graph = CallGraph(result.programAst)
|
||||
|
||||
assertEquals(1, graph.imports.size)
|
||||
assertEquals(1, graph.importedBy.size)
|
||||
val toplevelModule = result.programAst.toplevelModule
|
||||
val importedModule = graph.imports.getValue(toplevelModule).single()
|
||||
assertEquals("string", importedModule.name)
|
||||
val importedBy = graph.importedBy.getValue(importedModule).single()
|
||||
assertTrue(importedBy.name.startsWith("on_the_fly_test"))
|
||||
|
||||
assertFalse(graph.unused(toplevelModule))
|
||||
assertFalse(graph.unused(importedModule))
|
||||
|
||||
val mainBlock = toplevelModule.statements.filterIsInstance<Block>().single()
|
||||
val startSub = mainBlock.statements.filterIsInstance<Subroutine>().single{it.name=="start"}
|
||||
val emptySub = mainBlock.statements.filterIsInstance<Subroutine>().single{it.name=="empty"}
|
||||
|
||||
assertTrue(startSub in graph.calls, "start 'calls' (references) empty")
|
||||
assertFalse(emptySub in graph.calls, "empty doesn't call anything")
|
||||
assertTrue(emptySub in graph.calledBy, "empty gets 'called'")
|
||||
assertFalse(startSub in graph.calledBy, "start doesn't get called (except as entrypoint ofc.)")
|
||||
}
|
||||
}
|
59
compiler/test/TestOptimization.kt
Normal file
59
compiler/test/TestOptimization.kt
Normal file
@ -0,0 +1,59 @@
|
||||
package prog8tests
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import prog8.ast.statements.Block
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.compiler.target.C64Target
|
||||
import prog8tests.helpers.assertSuccess
|
||||
import prog8tests.helpers.compileText
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertSame
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class TestOptimization {
|
||||
@Test
|
||||
fun testRemoveEmptySubroutineExceptStart() {
|
||||
val sourcecode = """
|
||||
main {
|
||||
sub start() {
|
||||
}
|
||||
sub empty() {
|
||||
; going to be removed
|
||||
}
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target, true, sourcecode).assertSuccess()
|
||||
val toplevelModule = result.programAst.toplevelModule
|
||||
val mainBlock = toplevelModule.statements.single() as Block
|
||||
assertEquals(1, mainBlock.statements.size)
|
||||
val startSub = mainBlock.statements[0] as Subroutine
|
||||
assertSame(result.programAst.entrypoint, startSub)
|
||||
assertEquals("start", startSub.name)
|
||||
assertEquals(0, startSub.statements.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDontRemoveEmptySubroutineIfItsReferenced() {
|
||||
val sourcecode = """
|
||||
main {
|
||||
sub start() {
|
||||
uword xx = &empty
|
||||
xx++
|
||||
}
|
||||
sub empty() {
|
||||
; should not be removed
|
||||
}
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target, true, sourcecode).assertSuccess()
|
||||
val toplevelModule = result.programAst.toplevelModule
|
||||
val mainBlock = toplevelModule.statements.single() as Block
|
||||
val startSub = mainBlock.statements[0] as Subroutine
|
||||
val emptySub = mainBlock.statements[1] as Subroutine
|
||||
assertSame(result.programAst.entrypoint, startSub)
|
||||
assertEquals("start", startSub.name)
|
||||
assertEquals("empty", emptySub.name)
|
||||
assertEquals(0, emptySub.statements.size)
|
||||
}
|
||||
}
|
@ -1,18 +1,10 @@
|
||||
%import textio
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte xx
|
||||
uword address = &irq
|
||||
; cx16.set_irq(&irq, false)
|
||||
address++
|
||||
}
|
||||
|
||||
when xx {
|
||||
2 -> {
|
||||
}
|
||||
3 -> {
|
||||
}
|
||||
50 -> {
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
sub irq() {
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user