mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 08:29:25 +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.Module
|
||||||
import prog8.ast.Node
|
import prog8.ast.Node
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
|
import prog8.ast.base.VarDeclType
|
||||||
import prog8.ast.expressions.AddressOf
|
import prog8.ast.expressions.AddressOf
|
||||||
import prog8.ast.expressions.FunctionCall
|
import prog8.ast.expressions.FunctionCall
|
||||||
import prog8.ast.expressions.IdentifierReference
|
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 importedBy = mutableMapOf<Module, Set<Module>>().withDefault { setOf() }
|
||||||
val calls = mutableMapOf<Subroutine, Set<Subroutine>>().withDefault { setOf() }
|
val calls = mutableMapOf<Subroutine, Set<Subroutine>>().withDefault { setOf() }
|
||||||
val calledBy = mutableMapOf<Subroutine, Set<Node>>().withDefault { setOf() }
|
val calledBy = mutableMapOf<Subroutine, Set<Node>>().withDefault { setOf() }
|
||||||
private val allIdentifiers = mutableSetOf<IdentifierReference>()
|
private val allIdentifiersAndTargets = mutableMapOf<Pair<IdentifierReference, Position>, Statement>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
visit(program)
|
visit(program)
|
||||||
@ -35,9 +37,9 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
val blocksFromLibraries = program.allBlocks().filter { it.isInLibrary }
|
val blocksFromLibraries = program.allBlocks().filter { it.isInLibrary }
|
||||||
val used = mutableSetOf<Block>()
|
val used = mutableSetOf<Block>()
|
||||||
|
|
||||||
allIdentifiers.forEach {
|
allIdentifiersAndTargets.forEach {
|
||||||
if(it.definingBlock() in blocksFromSubroutines) {
|
if(it.key.first.definingBlock() in blocksFromSubroutines) {
|
||||||
val target = it.targetStatement(program)!!.definingBlock()
|
val target = it.value.definingBlock()
|
||||||
used.add(target)
|
used.add(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,7 +48,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val usedModules: Set<Module> by lazy {
|
private val usedModules: Set<Module> by lazy {
|
||||||
program.modules.toSet() // TODO
|
usedBlocks.map { it.definingModule() }.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(directive: Directive) {
|
override fun visit(directive: Directive) {
|
||||||
@ -105,7 +107,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(identifier: IdentifierReference) {
|
override fun visit(identifier: IdentifierReference) {
|
||||||
allIdentifiers.add(identifier)
|
allIdentifiersAndTargets[Pair(identifier, identifier.position)] = identifier.targetStatement(program)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkRecursiveCalls(errors: IErrorReporter) {
|
fun checkRecursiveCalls(errors: IErrorReporter) {
|
||||||
@ -166,11 +168,24 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
fun unused(block: Block) = block !in usedBlocks
|
fun unused(block: Block) = block !in usedBlocks
|
||||||
|
|
||||||
fun unused(decl: VarDecl): Boolean {
|
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 {
|
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
|
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> {
|
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||||
val forceOutput = "force_output" in decl.definingBlock().options()
|
val forceOutput = "force_output" in decl.definingBlock().options()
|
||||||
if(!forceOutput && callgraph.unused(decl)) {
|
if(!forceOutput && !decl.autogeneratedDontRemove && callgraph.unused(decl)) {
|
||||||
if(decl.type == VarDeclType.VAR)
|
if(decl.type == VarDeclType.VAR && !decl.definingBlock().isInLibrary)
|
||||||
errors.warn("removing unused variable '${decl.name}'", decl.position)
|
errors.warn("removing unused variable '${decl.name}'", decl.position)
|
||||||
|
|
||||||
return listOf(IAstModification.Remove(decl, decl.definingScope()))
|
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 targetVarDecl(program: Program): VarDecl? = targetStatement(program) as? VarDecl
|
||||||
fun targetSubroutine(program: Program): Subroutine? = targetStatement(program) as? Subroutine
|
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 hashCode() = nameInSource.hashCode()
|
||||||
|
|
||||||
override fun linkParents(parent: Node) {
|
override fun linkParents(parent: Node) {
|
||||||
|
@ -160,7 +160,6 @@ abstract class AstWalker {
|
|||||||
open fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
|
|
||||||
protected val modifications = mutableListOf<Triple<IAstModification, Node, Node>>()
|
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) {
|
private fun track(mods: Iterable<IAstModification>, node: Node, parent: Node) {
|
||||||
for (it in mods) {
|
for (it in mods) {
|
||||||
@ -176,12 +175,23 @@ abstract class AstWalker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun applyModifications(): Int {
|
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 {
|
modifications.forEach {
|
||||||
it.first.perform()
|
it.first.perform()
|
||||||
}
|
}
|
||||||
val amount = modifications.size
|
val amount = modifications.size
|
||||||
modifications.clear()
|
modifications.clear()
|
||||||
// modificationsReplacedNodes.clear()
|
|
||||||
return amount
|
return amount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user