mirror of
https://github.com/irmen/prog8.git
synced 2025-04-15 08:39:19 +00:00
fix issues with reporting inlined subroutines as unused
This commit is contained in:
parent
589948c7f4
commit
fc253237c9
@ -21,8 +21,9 @@ internal class IRUnusedCodeRemover(private val irprog: IRProgram, private val er
|
||||
irprog.blocks.forEach { block ->
|
||||
block.children.filterIsInstance<IRSubroutine>().reversed().forEach { sub ->
|
||||
if(sub.isEmpty()) {
|
||||
if(!sub.position.file.startsWith(libraryFilePrefix))
|
||||
if(!sub.position.file.startsWith(libraryFilePrefix)) {
|
||||
errors.warn("unused subroutine ${sub.label}", sub.position)
|
||||
}
|
||||
block.children.remove(sub)
|
||||
numRemoved++
|
||||
}
|
||||
|
@ -184,6 +184,7 @@ class Inliner(val program: Program): AstWalker() {
|
||||
}
|
||||
return if(sub.isAsmSubroutine) {
|
||||
// simply insert the asm for the argument-less routine
|
||||
sub.hasBeenInlined=true
|
||||
listOf(IAstModification.ReplaceNode(origNode, sub.statements.single().copy(), parent))
|
||||
} else {
|
||||
// note that we don't have to process any args, because we online inline parameterless subroutines.
|
||||
@ -192,12 +193,16 @@ class Inliner(val program: Program): AstWalker() {
|
||||
val fcall = toInline.value as? FunctionCallExpression
|
||||
if(fcall!=null) {
|
||||
// insert the function call expression as a void function call directly
|
||||
sub.hasBeenInlined=true
|
||||
val call = FunctionCallStatement(fcall.target.copy(), fcall.args.map { it.copy() }.toMutableList(), true, fcall.position)
|
||||
listOf(IAstModification.ReplaceNode(origNode, call, parent))
|
||||
} else
|
||||
noModifications
|
||||
}
|
||||
else -> listOf(IAstModification.ReplaceNode(origNode, toInline.copy(), parent))
|
||||
else -> {
|
||||
sub.hasBeenInlined=true
|
||||
listOf(IAstModification.ReplaceNode(origNode, toInline.copy(), parent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -226,8 +231,10 @@ class Inliner(val program: Program): AstWalker() {
|
||||
is Return -> {
|
||||
// is an expression, so we have to have a Return here in the inlined sub
|
||||
// note that we don't have to process any args, because we online inline parameterless subroutines.
|
||||
if(toInline.value!=null)
|
||||
if(toInline.value!=null) {
|
||||
sub.hasBeenInlined=true
|
||||
listOf(IAstModification.ReplaceNode(functionCallExpr, toInline.value!!.copy(), parent))
|
||||
}
|
||||
else
|
||||
noModifications
|
||||
}
|
||||
|
@ -64,13 +64,17 @@ class UnusedCodeRemover(private val program: Program,
|
||||
override fun after(block: Block, parent: Node): Iterable<IAstModification> {
|
||||
if("force_output" !in block.options()) {
|
||||
if (block.containsNoCodeNorVars) {
|
||||
if(block.name != internedStringsModuleName)
|
||||
errors.warn("removing unused block '${block.name}'", block.position)
|
||||
if(block.name != internedStringsModuleName) {
|
||||
if(!block.statements.any { it is Subroutine && it.hasBeenInlined })
|
||||
errors.warn("removing unused block '${block.name}'", block.position)
|
||||
}
|
||||
return listOf(IAstModification.Remove(block, parent as IStatementContainer))
|
||||
}
|
||||
if(callgraph.unused(block)) {
|
||||
if(block.statements.any{ it !is VarDecl || it.type== VarDeclType.VAR})
|
||||
errors.warn("removing unused block '${block.name}'", block.position)
|
||||
if(block.statements.any{ it !is VarDecl || it.type== VarDeclType.VAR}) {
|
||||
if(!block.statements.any { it is Subroutine && it.hasBeenInlined })
|
||||
errors.warn("removing unused block '${block.name}'", block.position)
|
||||
}
|
||||
program.removeInternedStringsFromRemovedBlock(block)
|
||||
return listOf(IAstModification.Remove(block, parent as IStatementContainer))
|
||||
}
|
||||
@ -81,7 +85,7 @@ class UnusedCodeRemover(private val program: Program,
|
||||
|
||||
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
||||
val forceOutput = "force_output" in subroutine.definingBlock.options()
|
||||
if (subroutine !== program.entrypoint && !forceOutput && !subroutine.inline && !subroutine.isAsmSubroutine) {
|
||||
if (subroutine !== program.entrypoint && !forceOutput && !subroutine.isAsmSubroutine) {
|
||||
if(callgraph.unused(subroutine)) {
|
||||
if(subroutine.containsNoCodeNorVars) {
|
||||
if(!subroutine.definingModule.isLibrary)
|
||||
@ -93,8 +97,9 @@ class UnusedCodeRemover(private val program: Program,
|
||||
}
|
||||
return removals
|
||||
}
|
||||
if(!subroutine.definingModule.isLibrary)
|
||||
errors.warn("removing unused subroutine '${subroutine.name}'", subroutine.position)
|
||||
if(!subroutine.definingModule.isLibrary && !subroutine.hasBeenInlined) {
|
||||
errors.warn("unused subroutine '${subroutine.name}'", subroutine.position)
|
||||
}
|
||||
program.removeInternedStringsFromRemovedSubroutine(subroutine)
|
||||
return listOf(IAstModification.Remove(subroutine, parent as IStatementContainer))
|
||||
}
|
||||
|
@ -373,6 +373,9 @@ private fun optimizeAst(program: Program, compilerOptions: CompilationOptions, e
|
||||
if (optsDone1 + optsDone2 + optsDone3 + optsDone4 == 0)
|
||||
break
|
||||
}
|
||||
val remover2 = UnusedCodeRemover(program, errors, compTarget)
|
||||
remover2.visit(program)
|
||||
remover2.applyModifications()
|
||||
errors.report()
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ class AsmInstructionNamesReplacer(
|
||||
return if(newName!=subroutine.name || changedParams.isNotEmpty()) {
|
||||
val newSub = Subroutine(newName, subroutine.parameters, subroutine.returntypes,
|
||||
subroutine.asmParameterRegisters, subroutine.asmReturnvaluesRegisters, subroutine.asmClobbers, subroutine.asmAddress, subroutine.isAsmSubroutine,
|
||||
subroutine.inline, subroutine.statements, subroutine.position)
|
||||
subroutine.inline, false, subroutine.statements, subroutine.position)
|
||||
if(changedParams.isNotEmpty())
|
||||
subsWithParamRefsToFix += newSub
|
||||
listOf(IAstModification.ReplaceNode(subroutine, newSub, parent))
|
||||
|
@ -65,7 +65,7 @@ internal class BoolRemover(val program: Program) : AstWalker() {
|
||||
}.toMutableList()
|
||||
val newSubroutine = Subroutine(subroutine.name, newParams, newReturnTypes,
|
||||
subroutine.asmParameterRegisters, subroutine.asmReturnvaluesRegisters, subroutine.asmClobbers,
|
||||
subroutine.asmAddress, subroutine.isAsmSubroutine, subroutine.inline, subroutine.statements,
|
||||
subroutine.asmAddress, subroutine.isAsmSubroutine, subroutine.inline, false, subroutine.statements,
|
||||
subroutine.position)
|
||||
return listOf(IAstModification.ReplaceNode(subroutine, newSubroutine, parent))
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class TestMemory: FunSpec({
|
||||
|
||||
fun wrapWithProgram(statements: List<Statement>): Program {
|
||||
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, statements.toMutableList(), Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements.toMutableList(), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
program.addModule(module)
|
||||
return program
|
||||
@ -153,7 +153,7 @@ class TestMemory: FunSpec({
|
||||
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, false, false, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||
.addModule(module)
|
||||
@ -165,7 +165,7 @@ class TestMemory: FunSpec({
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||
.addModule(module)
|
||||
@ -177,7 +177,7 @@ class TestMemory: FunSpec({
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||
.addModule(module)
|
||||
@ -189,7 +189,7 @@ class TestMemory: FunSpec({
|
||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||
.addModule(module)
|
||||
@ -202,7 +202,7 @@ class TestMemory: FunSpec({
|
||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||
.addModule(module)
|
||||
@ -215,7 +215,7 @@ class TestMemory: FunSpec({
|
||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
|
||||
.addModule(module)
|
||||
|
@ -334,6 +334,7 @@ class TestOptimization: FunSpec({
|
||||
uword yy ; to be removed
|
||||
yy=99 ; to be removed
|
||||
cx16.r0 = 0
|
||||
cx16.r0++
|
||||
}
|
||||
}
|
||||
}"""
|
||||
@ -343,7 +344,7 @@ class TestOptimization: FunSpec({
|
||||
ifstmt.truepart.statements.size shouldBe 1
|
||||
(ifstmt.truepart.statements[0] as Assignment).target.identifier!!.nameInSource shouldBe listOf("cx16", "r0")
|
||||
val func2 = result.compilerAst.entrypoint.statements[2] as Subroutine
|
||||
func2.statements.size shouldBe 1
|
||||
func2.statements.size shouldBe 2
|
||||
(func2.statements[0] as Assignment).target.identifier!!.nameInSource shouldBe listOf("cx16", "r0")
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ class TestAsmGenSymbols: StringSpec({
|
||||
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
|
||||
val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
|
||||
val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, statements, Position.DUMMY)
|
||||
val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, false, statements, Position.DUMMY)
|
||||
val labelInBlock = Label("label_outside", Position.DUMMY)
|
||||
val varInBlock = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, Position.DUMMY)
|
||||
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
|
||||
|
@ -159,7 +159,7 @@ private fun Prog8ANTLRParser.AsmsubroutineContext.toAst(): Subroutine {
|
||||
val statements = statement_block()?.toAst() ?: mutableListOf()
|
||||
return Subroutine(subdecl.name, subdecl.parameters.toMutableList(), subdecl.returntypes,
|
||||
subdecl.asmParameterRegisters, subdecl.asmReturnvaluesRegisters,
|
||||
subdecl.asmClobbers, null, true, inline, statements, toPosition())
|
||||
subdecl.asmClobbers, null, true, inline, false, statements, toPosition())
|
||||
}
|
||||
|
||||
private fun Prog8ANTLRParser.RomsubroutineContext.toAst(): Subroutine {
|
||||
|
@ -688,6 +688,7 @@ class Subroutine(override val name: String,
|
||||
val asmAddress: UInt?,
|
||||
val isAsmSubroutine: Boolean,
|
||||
var inline: Boolean,
|
||||
var hasBeenInlined: Boolean=false,
|
||||
override var statements: MutableList<Statement>,
|
||||
override val position: Position) : Statement(), INameScope {
|
||||
|
||||
|
@ -3,10 +3,7 @@ TODO
|
||||
|
||||
For next minor release
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
- fix expericodegen compiler errors:
|
||||
tehtriz: thinks sound.init routine is unused
|
||||
textelite: thinks trader.do_local routine is unused , and debug_seed
|
||||
- fix IR/VM: animals.p8 example somehow doesn't print the animal name in the first question, and exits after 1 animal instead of looping
|
||||
- fix IR/VM: animals.p8 example somehow doesn't print the animal name correctly in the first question, and exits after 1 animal instead of looping
|
||||
- fix Github issue with X register https://github.com/irmen/prog8/issues/94
|
||||
|
||||
...
|
||||
|
Loading…
x
Reference in New Issue
Block a user