callgraph

This commit is contained in:
Irmen de Jong 2021-04-05 20:32:30 +02:00
parent 530d03d284
commit 4c1eb1b12a
4 changed files with 38 additions and 13 deletions

View File

@ -3,7 +3,9 @@ package prog8.optimizer
import prog8.ast.Module
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.DataType
import prog8.ast.base.Position
import prog8.ast.base.VarDeclType
import prog8.ast.expressions.AddressOf
import prog8.ast.expressions.FunctionCall
import prog8.ast.expressions.IdentifierReference
@ -18,7 +20,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
val importedBy = mutableMapOf<Module, Set<Module>>().withDefault { setOf() }
val calls = mutableMapOf<Subroutine, Set<Subroutine>>().withDefault { setOf() }
val calledBy = mutableMapOf<Subroutine, Set<Node>>().withDefault { setOf() }
private val allIdentifiers = mutableSetOf<IdentifierReference>()
private val allIdentifiersAndTargets = mutableMapOf<Pair<IdentifierReference, Position>, Statement>()
init {
visit(program)
@ -35,9 +37,9 @@ class CallGraph(private val program: Program) : IAstVisitor {
val blocksFromLibraries = program.allBlocks().filter { it.isInLibrary }
val used = mutableSetOf<Block>()
allIdentifiers.forEach {
if(it.definingBlock() in blocksFromSubroutines) {
val target = it.targetStatement(program)!!.definingBlock()
allIdentifiersAndTargets.forEach {
if(it.key.first.definingBlock() in blocksFromSubroutines) {
val target = it.value.definingBlock()
used.add(target)
}
}
@ -46,7 +48,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
}
private val usedModules: Set<Module> by lazy {
program.modules.toSet() // TODO
usedBlocks.map { it.definingModule() }.toSet()
}
override fun visit(directive: Directive) {
@ -105,7 +107,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
}
override fun visit(identifier: IdentifierReference) {
allIdentifiers.add(identifier)
allIdentifiersAndTargets[Pair(identifier, identifier.position)] = identifier.targetStatement(program)!!
}
fun checkRecursiveCalls(errors: IErrorReporter) {
@ -166,11 +168,24 @@ class CallGraph(private val program: Program) : IAstVisitor {
fun unused(block: Block) = block !in usedBlocks
fun unused(decl: VarDecl): Boolean {
return false // TODO implement unused check for vardecls, also check inline asm
if(decl.type!=VarDeclType.VAR || decl.datatype==DataType.STRUCT || decl.autogeneratedDontRemove || decl.parent is StructDecl)
return false
if(decl.definingBlock() !in usedBlocks)
return false
// TODO also check inline asm for references to the var
val allReferencedVardecls = allIdentifiersAndTargets.filter { it.value is VarDecl }.map { it.value }.toSet()
return decl !in allReferencedVardecls
}
fun unused(struct: StructDecl): Boolean {
return false // TODO implement unused check for struct decls, also check inline asm
if(struct.definingBlock() !in usedBlocks)
return false
// TODO implement unused check for struct decls, also check inline asm
return false
}
inline fun unused(label: Label) = false // just always output labels

View File

@ -105,8 +105,8 @@ internal class UnusedCodeRemover(private val program: Program,
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
val forceOutput = "force_output" in decl.definingBlock().options()
if(!forceOutput && callgraph.unused(decl)) {
if(decl.type == VarDeclType.VAR)
if(!forceOutput && !decl.autogeneratedDontRemove && callgraph.unused(decl)) {
if(decl.type == VarDeclType.VAR && !decl.definingBlock().isInLibrary)
errors.warn("removing unused variable '${decl.name}'", decl.position)
return listOf(IAstModification.Remove(decl, decl.definingScope()))

View File

@ -727,7 +727,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
fun targetVarDecl(program: Program): VarDecl? = targetStatement(program) as? VarDecl
fun targetSubroutine(program: Program): Subroutine? = targetStatement(program) as? Subroutine
override fun equals(other: Any?) = other is IdentifierReference && other.nameInSource==nameInSource
override fun equals(other: Any?) = other is IdentifierReference && other.nameInSource==nameInSource // NOTE: only compare by the name, not the position!
override fun hashCode() = nameInSource.hashCode()
override fun linkParents(parent: Node) {

View File

@ -160,7 +160,6 @@ abstract class AstWalker {
open fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> = noModifications
protected val modifications = mutableListOf<Triple<IAstModification, Node, Node>>()
// private val modificationsReplacedNodes = mutableSetOf<Pair<Node, Position>>()
private fun track(mods: Iterable<IAstModification>, node: Node, parent: Node) {
for (it in mods) {
@ -176,12 +175,23 @@ abstract class AstWalker {
}
fun applyModifications(): Int {
// check if there are double removes, keep only the last one
val removals = modifications.filter { it.first is IAstModification.Remove }
if(removals.size>0) {
val doubles = removals.groupBy { (it.first as IAstModification.Remove).node }.filter { it.value.size>1 }
doubles.forEach {
for(doubleRemove in it.value.dropLast(1)) {
if(!modifications.removeIf { mod-> mod.first === doubleRemove.first })
throw FatalAstException("ast remove problem")
}
}
}
modifications.forEach {
it.first.perform()
}
val amount = modifications.size
modifications.clear()
// modificationsReplacedNodes.clear()
return amount
}