From 056ec986c25644d5613c22bcb3d42a58f1e09c39 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 11 Jan 2022 00:34:44 +0100 Subject: [PATCH] use var initializer assignments in a clearer way --- .../prog8/codegen/target/cpu6502/codegen/AsmGen.kt | 6 +----- .../prog8/compiler/astprocessing/AstPreprocessor.kt | 12 ++++++++++++ .../compiler/astprocessing/StatementReorderer.kt | 13 +++---------- compiler/test/TestCompilerOnCharLit.kt | 3 +-- compiler/test/TestOptimization.kt | 8 +++++--- .../src/prog8/ast/statements/AstStatements.kt | 12 ++++++++++++ docs/source/todo.rst | 1 - 7 files changed, 34 insertions(+), 21 deletions(-) diff --git a/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/AsmGen.kt b/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/AsmGen.kt index a3f364554..7f6533998 100644 --- a/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/AsmGen.kt +++ b/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/AsmGen.kt @@ -220,11 +220,7 @@ class AsmGen(private val program: Program, if(options.dontReinitGlobals) { block.statements.asSequence().filterIsInstance().forEach { it.zeropage = ZeropageWish.NOT_IN_ZEROPAGE - val init = it.nextSibling() as? Assignment - if(init?.target?.identifier?.targetVarDecl(program) === it) { - // put the init value back into the vardecl - it.value = init.value - } + it.findInitializer(program)?.let { initializer -> it.value = initializer.value } // put the init value back into the vardecl } } diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index 68bd193c0..aaa08f4f2 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -85,4 +85,16 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter) : AstWal } return noModifications } + + override fun after(decl: VarDecl, parent: Node): Iterable { + val nextAssignment = decl.nextSibling() as? Assignment + if(nextAssignment!=null && nextAssignment.origin!=AssignmentOrigin.VARINIT) { + // check if it's a proper initializer assignment for the variable + if(decl.value==null && nextAssignment.target.identifier?.targetVarDecl(program)===decl) { + if(!nextAssignment.value.referencesIdentifier(nextAssignment.target.identifier!!.nameInSource)) + nextAssignment.origin = AssignmentOrigin.VARINIT + } + } + return noModifications + } } diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index 3aa2d7b29..3c8a88211 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -58,16 +58,9 @@ internal class StatementReorderer(val program: Program, // no need to zero out the special internal returnvalue intermediates. return noModifications } - val nextStmt = decl.nextSibling() - val nextAssign = nextStmt as? Assignment - if(nextAssign!=null && !nextAssign.isAugmentable) { - val target = nextAssign.target.identifier?.targetStatement(program) - if(target === decl) { - // an initializer assignment for a vardecl is already here - return noModifications - } - } - val nextFor = nextStmt as? ForLoop + if(decl.findInitializer(program)!=null) + return noModifications // an initializer assignment for a vardecl is already here + val nextFor = decl.nextSibling() as? ForLoop val hasNextForWithThisLoopvar = nextFor?.loopVar?.nameInSource==listOf(decl.name) if (!hasNextForWithThisLoopvar) { // Add assignment to initialize with zero diff --git a/compiler/test/TestCompilerOnCharLit.kt b/compiler/test/TestCompilerOnCharLit.kt index 3aba5b100..54d7fdc51 100644 --- a/compiler/test/TestCompilerOnCharLit.kt +++ b/compiler/test/TestCompilerOnCharLit.kt @@ -10,7 +10,6 @@ import prog8.ast.base.DataType import prog8.ast.base.VarDeclType import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteralValue -import prog8.ast.statements.Assignment import prog8.codegen.target.Cx16Target import prog8tests.helpers.assertSuccess import prog8tests.helpers.compileText @@ -76,7 +75,7 @@ class TestCompilerOnCharLit: FunSpec({ withClue("initializer value should have been moved to separate assignment"){ decl.value shouldBe null } - val assignInitialValue = decl.nextSibling() as Assignment + val assignInitialValue = decl.findInitializer(program)!! assignInitialValue.target.identifier!!.nameInSource shouldBe listOf("ch") withClue("char literal should have been replaced by ubyte literal") { assignInitialValue.value shouldBe instanceOf() diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index 5ae12b413..f41748019 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -604,24 +604,26 @@ class TestOptimization: FunSpec({ uword @shared zz zz += 60 ; NOT ok to remove initializer, should evaluate to 60 ubyte @shared xx - xx = 6+sin8u(xx) ; NOT ok to remove initializer + xx = 6+sin8u(xx) ; is not an initializer because it references xx } } """ val result = compileText(C64Target, optimize=true, src, writeAssembly=false).assertSuccess() + printProgram(result.program) /* expected result: uword yy yy = 20 uword zz zz = 60 ubyte xx + xx = 0 xx = sin8u(xx) xx += 6 */ val stmts = result.program.entrypoint.statements - stmts.size shouldBe 7 + stmts.size shouldBe 8 stmts.filterIsInstance().size shouldBe 3 - stmts.filterIsInstance().size shouldBe 4 + stmts.filterIsInstance().size shouldBe 5 } test("only substitue assignments with 0 after a =0 initializer if it is the same variable") { diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 07f7e1d8c..7cd310141 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -272,6 +272,12 @@ class VarDecl(val type: VarDeclType, copy.allowInitializeWithZero = this.allowInitializeWithZero return copy } + + fun findInitializer(program: Program): Assignment? = + (parent as IStatementContainer).statements + .asSequence() + .filterIsInstance() + .singleOrNull { it.origin==AssignmentOrigin.VARINIT && it.target.identifier?.targetVarDecl(program) === this } } class ArrayIndex(var indexExpr: Expression, @@ -399,6 +405,12 @@ class Assignment(var target: AssignTarget, var value: Expression, var origin: As return false } + + fun initializerFor(program: Program) = + if(origin==AssignmentOrigin.VARINIT) + target.identifier!!.targetVarDecl(program) + else + null } data class AssignTarget(var identifier: IdentifierReference?, diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 10abb8f67..589e38b49 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next compiler release (7.7) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- use the assignment origin? in codegen? (origin VARINIT) - optimize codegen of pipe operator to avoid needless assigns to temp var