vardecl with initializer expression are now optimized again (unless floats)

This commit is contained in:
Irmen de Jong 2020-10-18 15:48:49 +02:00
parent 74b5124a42
commit 8eb69d6eda
5 changed files with 52 additions and 23 deletions

View File

@ -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

View File

@ -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<IAstModification> {
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<IAstModification> {
val valueType = assignment.value.inferType(program)
val targetType = assignment.target.inferType(program, assignment)

View File

@ -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<Statement> {
val result = struct!!.statements.withIndex().map {

View File

@ -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
}

View File

@ -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()
}