diff --git a/compiler/src/prog8/optimizer/CallGraph.kt b/compiler/src/prog8/optimizer/CallGraph.kt index 4b533d7ff..f95b8ad8e 100644 --- a/compiler/src/prog8/optimizer/CallGraph.kt +++ b/compiler/src/prog8/optimizer/CallGraph.kt @@ -21,18 +21,17 @@ class CallGraph(private val program: Program) : IAstVisitor { val calls = mutableMapOf>().withDefault { setOf() } val calledBy = mutableMapOf>().withDefault { setOf() } private val allIdentifiersAndTargets = mutableMapOf, Statement>() + private val allAssemblyNodes = mutableListOf() init { visit(program) } private val usedSubroutines: Set by lazy { - // TODO also check inline assembly if it uses the subroutine calledBy.keys } private val usedBlocks: Set by lazy { - // TODO also check inline assembly if it uses the block val blocksFromSubroutines = usedSubroutines.map { it.definingBlock() } val blocksFromLibraries = program.allBlocks().filter { it.isInLibrary } val used = mutableSetOf() @@ -110,6 +109,10 @@ class CallGraph(private val program: Program) : IAstVisitor { allIdentifiersAndTargets[Pair(identifier, identifier.position)] = identifier.targetStatement(program)!! } + override fun visit(inlineAssembly: InlineAssembly) { + allAssemblyNodes.add(inlineAssembly) + } + fun checkRecursiveCalls(errors: IErrorReporter) { val cycles = recursionCycles() if(cycles.any()) { @@ -163,9 +166,13 @@ class CallGraph(private val program: Program) : IAstVisitor { 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 { 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) 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 + return decl !in allReferencedVardecls && !nameInAssemblyCode(decl.name) } - fun unused(struct: StructDecl): Boolean { - if(struct.definingBlock() !in usedBlocks) - return false - - // TODO implement unused check for struct decls, also check inline asm - return false - } + private fun nameInAssemblyCode(name: String) = allAssemblyNodes.any { it.assembly.contains(name) } 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 VarDecl -> unused(stmt) is Label -> false // just always output labels - is StructDecl -> unused(stmt) else -> false } } diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 570944f3c..0bce281a1 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -948,7 +948,7 @@ class WhenChoice(var values: MutableList?, // if null, th class StructDecl(override val name: String, override var statements: MutableList, // actually, only vardecls here - override val position: Position): Statement(), INameScope, ISymbolStatement { + override val position: Position): Statement(), INameScope { override lateinit var parent: Node diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 2c2b0e473..80b226d18 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,8 +2,6 @@ TODO ==== -- implement new 'unused' in CallGraph for more node types - - allow inlining of subroutines with params - 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)