mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 01:29:28 +00:00
callgraph
This commit is contained in:
parent
530d03d284
commit
4c1eb1b12a
@ -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
|
||||
|
@ -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()))
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user