diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index 86cea5abb..48d52d8b2 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -62,10 +62,18 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, } override fun after(assignment: Assignment, parent: Node): Iterable { - val nextAssign = assignment.nextSibling() as? Assignment - if(nextAssign!=null && nextAssign.target.isSameAs(assignment.target, program)) { - if(!nextAssign.isAugmentable && nextAssign.value isSameAs assignment.value && assignment.value !is IFunctionCall) // don't remove function calls even when they're duplicates - return listOf(IAstModification.Remove(assignment, parent as IStatementContainer)) + // remove duplicated assignments, but not if it's a memory mapped IO register + val isIO = try { + assignment.target.isIOAddress(options.compTarget.machine) + } catch (_: FatalAstException) { + false + } + if(!isIO) { + val nextAssign = assignment.nextSibling() as? Assignment + if (nextAssign != null && nextAssign.target.isSameAs(assignment.target, program)) { + if (!nextAssign.isAugmentable && nextAssign.value isSameAs assignment.value && assignment.value !is IFunctionCall) // don't remove function calls even when they're duplicates + return listOf(IAstModification.Remove(assignment, parent as IStatementContainer)) + } } return noModifications diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index 633d96691..56501d232 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -15,6 +15,7 @@ import prog8.ast.statements.* import prog8.code.core.DataType import prog8.code.core.Position import prog8.code.target.C64Target +import prog8.code.target.Cx16Target import prog8.compiler.printProgram import prog8tests.helpers.* @@ -736,4 +737,60 @@ class TestOptimization: FunSpec({ val stmts = result.program.entrypoint.statements stmts.size shouldBe 3 } + + test("repeated assignments to IO register should remain") { + val srcX16=""" +main { + sub start() { + ubyte @shared xx + xx = 42 + xx = 42 ; removed + xx = 42 ; removed + cx16.VERA_DATA0 = 0 + cx16.VERA_DATA0 = 0 + cx16.VERA_DATA0 = 0 + @($9fff) = 0 + @($9fff) = 0 + @($9fff) = 0 + return + } +}""" + var result = compileText(Cx16Target(), true, srcX16, writeAssembly = true)!! + var statements = result.program.entrypoint.statements + statements.size shouldBe 9 + (statements[1] as Assignment).target.identifier!!.nameInSource shouldBe listOf("xx") + (statements[2] as Assignment).target.identifier!!.nameInSource shouldBe listOf("cx16", "VERA_DATA0") + (statements[3] as Assignment).target.identifier!!.nameInSource shouldBe listOf("cx16", "VERA_DATA0") + (statements[4] as Assignment).target.identifier!!.nameInSource shouldBe listOf("cx16", "VERA_DATA0") + (statements[5] as Assignment).target.memoryAddress!!.addressExpression.constValue(result.program)!!.number shouldBe 0x9fff + (statements[6] as Assignment).target.memoryAddress!!.addressExpression.constValue(result.program)!!.number shouldBe 0x9fff + (statements[7] as Assignment).target.memoryAddress!!.addressExpression.constValue(result.program)!!.number shouldBe 0x9fff + + val srcC64=""" +main { + sub start() { + ubyte @shared xx + xx = 42 + xx = 42 ;removed + xx = 42 ;removed + c64.EXTCOL = 0 + c64.EXTCOL = 0 + c64.EXTCOL = 0 + @(53281) = 0 + @(53281) = 0 + @(53281) = 0 + return + } +}""" + result = compileText(C64Target(), true, srcC64, writeAssembly = true)!! + statements = result.program.entrypoint.statements + statements.size shouldBe 9 + (statements[1] as Assignment).target.identifier!!.nameInSource shouldBe listOf("xx") + (statements[2] as Assignment).target.identifier!!.nameInSource shouldBe listOf("c64", "EXTCOL") + (statements[3] as Assignment).target.identifier!!.nameInSource shouldBe listOf("c64", "EXTCOL") + (statements[4] as Assignment).target.identifier!!.nameInSource shouldBe listOf("c64", "EXTCOL") + (statements[5] as Assignment).target.memoryAddress!!.addressExpression.constValue(result.program)!!.number shouldBe 53281.0 + (statements[6] as Assignment).target.memoryAddress!!.addressExpression.constValue(result.program)!!.number shouldBe 53281.0 + (statements[7] as Assignment).target.memoryAddress!!.addressExpression.constValue(result.program)!!.number shouldBe 53281.0 + } }) diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index b268c04ac..f591555e4 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -532,8 +532,7 @@ data class AssignTarget(var identifier: IdentifierReference?, } else false } ident != null -> { - val decl = ident.targetVarDecl(definingModule.program) ?: - throw FatalAstException("invalid identifier ${ident.nameInSource}") + val decl = ident.targetVarDecl(definingModule.program) ?: throw FatalAstException("invalid identifier ${ident.nameInSource}") return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteral) machine.isIOAddress((decl.value as NumericLiteral).number.toUInt()) else