mirror of
https://github.com/irmen/prog8.git
synced 2024-09-09 02:54:28 +00:00
callgraph improved unused node checking
This commit is contained in:
parent
4c1eb1b12a
commit
3e3b0bcd8b
@ -21,18 +21,17 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
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 allIdentifiersAndTargets = mutableMapOf<Pair<IdentifierReference, Position>, Statement>()
|
private val allIdentifiersAndTargets = mutableMapOf<Pair<IdentifierReference, Position>, Statement>()
|
||||||
|
private val allAssemblyNodes = mutableListOf<InlineAssembly>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
visit(program)
|
visit(program)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val usedSubroutines: Set<Subroutine> by lazy {
|
private val usedSubroutines: Set<Subroutine> by lazy {
|
||||||
// TODO also check inline assembly if it uses the subroutine
|
|
||||||
calledBy.keys
|
calledBy.keys
|
||||||
}
|
}
|
||||||
|
|
||||||
private val usedBlocks: Set<Block> by lazy {
|
private val usedBlocks: Set<Block> by lazy {
|
||||||
// TODO also check inline assembly if it uses the block
|
|
||||||
val blocksFromSubroutines = usedSubroutines.map { it.definingBlock() }
|
val blocksFromSubroutines = usedSubroutines.map { it.definingBlock() }
|
||||||
val blocksFromLibraries = program.allBlocks().filter { it.isInLibrary }
|
val blocksFromLibraries = program.allBlocks().filter { it.isInLibrary }
|
||||||
val used = mutableSetOf<Block>()
|
val used = mutableSetOf<Block>()
|
||||||
@ -110,6 +109,10 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
allIdentifiersAndTargets[Pair(identifier, identifier.position)] = identifier.targetStatement(program)!!
|
allIdentifiersAndTargets[Pair(identifier, identifier.position)] = identifier.targetStatement(program)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visit(inlineAssembly: InlineAssembly) {
|
||||||
|
allAssemblyNodes.add(inlineAssembly)
|
||||||
|
}
|
||||||
|
|
||||||
fun checkRecursiveCalls(errors: IErrorReporter) {
|
fun checkRecursiveCalls(errors: IErrorReporter) {
|
||||||
val cycles = recursionCycles()
|
val cycles = recursionCycles()
|
||||||
if(cycles.any()) {
|
if(cycles.any()) {
|
||||||
@ -163,9 +166,13 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
|
|
||||||
fun unused(module: Module) = module !in usedModules
|
fun unused(module: Module) = module !in usedModules
|
||||||
|
|
||||||
fun unused(sub: Subroutine) = sub !in usedSubroutines
|
fun unused(sub: Subroutine): Boolean {
|
||||||
|
return sub !in usedSubroutines && !nameInAssemblyCode(sub.name)
|
||||||
|
}
|
||||||
|
|
||||||
fun unused(block: Block) = block !in usedBlocks
|
fun unused(block: Block): Boolean {
|
||||||
|
return block !in usedBlocks && !nameInAssemblyCode(block.name)
|
||||||
|
}
|
||||||
|
|
||||||
fun unused(decl: VarDecl): Boolean {
|
fun unused(decl: VarDecl): Boolean {
|
||||||
if(decl.type!=VarDeclType.VAR || decl.datatype==DataType.STRUCT || decl.autogeneratedDontRemove || decl.parent is StructDecl)
|
if(decl.type!=VarDeclType.VAR || decl.datatype==DataType.STRUCT || decl.autogeneratedDontRemove || decl.parent is StructDecl)
|
||||||
@ -174,19 +181,11 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
if(decl.definingBlock() !in usedBlocks)
|
if(decl.definingBlock() !in usedBlocks)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
// TODO also check inline asm for references to the var
|
|
||||||
val allReferencedVardecls = allIdentifiersAndTargets.filter { it.value is VarDecl }.map { it.value }.toSet()
|
val allReferencedVardecls = allIdentifiersAndTargets.filter { it.value is VarDecl }.map { it.value }.toSet()
|
||||||
|
return decl !in allReferencedVardecls && !nameInAssemblyCode(decl.name)
|
||||||
return decl !in allReferencedVardecls
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unused(struct: StructDecl): Boolean {
|
private fun nameInAssemblyCode(name: String) = allAssemblyNodes.any { it.assembly.contains(name) }
|
||||||
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
|
||||||
|
|
||||||
@ -196,7 +195,6 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
is Block -> unused(stmt)
|
is Block -> unused(stmt)
|
||||||
is VarDecl -> unused(stmt)
|
is VarDecl -> unused(stmt)
|
||||||
is Label -> false // just always output labels
|
is Label -> false // just always output labels
|
||||||
is StructDecl -> unused(stmt)
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -948,7 +948,7 @@ class WhenChoice(var values: MutableList<Expression>?, // if null, th
|
|||||||
|
|
||||||
class StructDecl(override val name: String,
|
class StructDecl(override val name: String,
|
||||||
override var statements: MutableList<Statement>, // actually, only vardecls here
|
override var statements: MutableList<Statement>, // actually, only vardecls here
|
||||||
override val position: Position): Statement(), INameScope, ISymbolStatement {
|
override val position: Position): Statement(), INameScope {
|
||||||
|
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
|
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
- implement new 'unused' in CallGraph for more node types
|
|
||||||
|
|
||||||
- allow inlining of subroutines with params
|
- allow inlining of subroutines with params
|
||||||
- optimize several inner loops in gfx2
|
- optimize several inner loops in gfx2
|
||||||
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
|
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
|
||||||
|
Loading…
Reference in New Issue
Block a user