From 8eb69d6edab9994c82b3e70a40328b7aba3f342e Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 18 Oct 2020 15:48:49 +0200 Subject: [PATCH] vardecl with initializer expression are now optimized again (unless floats) --- compiler/res/prog8lib/c64/graphics.p8 | 2 +- .../ast/processing/StatementReorderer.kt | 24 ++++++++++++++++- .../src/prog8/ast/statements/AstStatements.kt | 9 ++++++- .../compiler/BeforeAsmGenerationAstChanger.kt | 13 +++++---- examples/test.p8 | 27 +++++++++---------- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/compiler/res/prog8lib/c64/graphics.p8 b/compiler/res/prog8lib/c64/graphics.p8 index 29cd8f945..8fbe03f42 100644 --- a/compiler/res/prog8lib/c64/graphics.p8 +++ b/compiler/res/prog8lib/c64/graphics.p8 @@ -33,7 +33,7 @@ graphics { } word @zp d = 0 ubyte positive_ix = true - word @zp dx = x2-x1 + word @zp dx = x2-x1 as word word @zp dy = y2-y1 if dx < 0 { dx = -dx diff --git a/compiler/src/prog8/ast/processing/StatementReorderer.kt b/compiler/src/prog8/ast/processing/StatementReorderer.kt index 0fc240fc0..5dad13bdd 100644 --- a/compiler/src/prog8/ast/processing/StatementReorderer.kt +++ b/compiler/src/prog8/ast/processing/StatementReorderer.kt @@ -11,7 +11,7 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte // - 'main' block must be the very first statement UNLESS it has an address set. // - library blocks are put last. // - blocks are ordered by address, where blocks without address are placed last. - // - in every scope, most directives and vardecls are moved to the top. + // - in every block and module, most directives and vardecls are moved to the top. (not in subroutines!) // - the 'start' subroutine is moved to the top. // - (syntax desugaring) a vardecl with a non-const initializer value is split into a regular vardecl and an assignment statement. // - (syntax desugaring) struct value assignment is expanded into several struct member assignments. @@ -121,6 +121,28 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte return noModifications } + override fun after(decl: VarDecl, parent: Node): Iterable { + val declValue = decl.value + if(declValue!=null && decl.type== VarDeclType.VAR && decl.datatype in NumericDatatypes) { + val declConstValue = declValue.constValue(program) + if(declConstValue==null) { + // move the vardecl (without value) to the scope and replace this with a regular assignment + // Unless we're dealing with a floating point variable because that will actually make things less efficient at the moment (because floats are mostly calcualated via the stack) + if(decl.datatype!=DataType.FLOAT) { + decl.value = null + decl.allowInitializeWithZero = false + val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position) + val assign = Assignment(target, declValue, decl.position) + return listOf( + IAstModification.ReplaceNode(decl, assign, parent), + IAstModification.InsertFirst(decl, decl.definingScope() as Node) + ) + } + } + } + return noModifications + } + override fun before(assignment: Assignment, parent: Node): Iterable { val valueType = assignment.value.inferType(program) val targetType = assignment.target.inferType(program, assignment) diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index 5c2ebc54b..85d6b4988 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -5,6 +5,7 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.processing.AstWalker import prog8.ast.processing.IAstVisitor +import prog8.compiler.CompilerException import prog8.compiler.target.CompilationTarget @@ -171,6 +172,7 @@ open class VarDecl(val type: VarDeclType, private set var structHasBeenFlattened = false // set later private set + var allowInitializeWithZero = true // prefix for literal values that are turned into a variable on the heap @@ -242,7 +244,12 @@ open class VarDecl(val type: VarDeclType, return "VarDecl(name=$name, vartype=$type, datatype=$datatype, struct=$structName, value=$value, pos=$position)" } - fun zeroElementValue() = defaultZero(declaredDatatype, position) + fun zeroElementValue(): NumericLiteralValue { + if(allowInitializeWithZero) + return defaultZero(declaredDatatype, position) + else + throw CompilerException("attempt to get zero value for vardecl that shouldn't get it") + } fun flattenStructMembers(): MutableList { val result = struct!!.statements.withIndex().map { diff --git a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt index d82ea95c3..6f0b635e7 100644 --- a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt +++ b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt @@ -19,11 +19,14 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E if (decl.value == null && !decl.autogeneratedDontRemove && decl.type == VarDeclType.VAR && decl.datatype in NumericDatatypes) { // a numeric vardecl without an initial value is initialized with zero, // unless there's already an assignment below, that initializes the value - val nextAssign = decl.definingScope().nextSibling(decl) as? Assignment - if(nextAssign!=null && nextAssign.target.isSameAs(IdentifierReference(listOf(decl.name), Position.DUMMY))) - decl.value = null - else - decl.value = decl.zeroElementValue() + if(decl.allowInitializeWithZero) + { + val nextAssign = decl.definingScope().nextSibling(decl) as? Assignment + if (nextAssign != null && nextAssign.target.isSameAs(IdentifierReference(listOf(decl.name), Position.DUMMY))) + decl.value = null + else + decl.value = decl.zeroElementValue() + } } return noModifications } diff --git a/examples/test.p8 b/examples/test.p8 index f00304a6f..507c57ff1 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,23 +7,20 @@ main { sub start() { - ubyte[] array = [1,2,3,4] + uword zc - const ubyte ic = 2 - ubyte ib = 2 + zc = 99 + scolor2=scolor + + ; TODO WHy does this compile with stack eval: + ubyte scolor = (zc>>13) as ubyte + 4 + + ; TODO this is more optimized: + ubyte scolor2 + scolor2 = (zc>>13) as ubyte + 4 + + scolor2=scolor - ib = array[ic+1] - ib = array[ib] - ib = array[ib+1] - ib = array[ib+2] - ib = array[ib-1] - ib = array[ib-2] - ib = array[ib*2] - ib = array[2*ib] - ib = array[ib*3] - ib = array[3*ib] - ib = array[ib*4] - ib = array[4*ib] testX() }