fix problems with moving vardecls from inner scope to subroutine scope

This commit is contained in:
Irmen de Jong 2021-04-12 22:25:33 +02:00
parent 319ac3a641
commit 54d92a027a
5 changed files with 43 additions and 60 deletions

View File

@ -18,15 +18,17 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
subroutineVariables.add(decl.name to decl)
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
// A numeric vardecl without an initial value is initialized with zero,
// unless there's already an assignment below, that initializes the value.
// This allows you to restart the program and have the same starting values of the variables
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
else {
decl.value = decl.zeroElementValue()
}
}
}
return noModifications
@ -80,17 +82,22 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
val sub = scope.definingSubroutine()
if (sub != null) {
// move vardecls of the scope into the upper scope. Make sure the position remains the same!
val numericVarsWithValue = decls.filter { it.value != null && it.datatype in NumericDatatypes }
val replaceVardecls =numericVarsWithValue.map {
val initValue = it.value!! // assume here that value has always been set by now
it.value = null // make sure no value init assignment for this vardecl will be created later (would be superfluous)
val target = AssignTarget(IdentifierReference(listOf(it.name), it.position), null, null, it.position)
val assign = Assignment(target, initValue, it.position)
initValue.parent = assign
IAstModification.ReplaceNode(it, assign, scope)
val replacements = mutableListOf<IAstModification>()
val movements = mutableListOf<IAstModification.InsertFirst>()
for(decl in decls) {
if(decl.value!=null && decl.datatype in NumericDatatypes) {
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position)
val assign = Assignment(target, decl.value!!, decl.position)
replacements.add(IAstModification.ReplaceNode(decl, assign, scope))
decl.value = null
decl.allowInitializeWithZero = false
} else {
replacements.add(IAstModification.Remove(decl, scope))
}
movements.add(IAstModification.InsertFirst(decl, sub))
}
val moveVardeclsUp = decls.map { IAstModification.InsertFirst(it, sub) }
return replaceVardecls + moveVardeclsUp
return replacements + movements
}
return noModifications
}

View File

@ -1,9 +1,6 @@
package prog8.compiler.astprocessing
import prog8.ast.IFunctionCall
import prog8.ast.Module
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.*
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
@ -201,18 +198,15 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
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.copy(), decl.definingScope())
)
}
// move the vardecl (without value) to the scope of the defining subroutine and put a regular assignment in its place here.
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.definingSubroutine() as INameScope)
)
}
}
return noModifications

View File

@ -281,7 +281,12 @@ open class VarDecl(val type: VarDeclType,
return result
}
fun copy() = VarDecl(type, declaredDatatype, zeropage, arraysize, name, structName, value, isArray, autogeneratedDontRemove, position)
fun copy(): VarDecl {
val c = VarDecl(type, declaredDatatype, zeropage, arraysize, name, structName, value, isArray, autogeneratedDontRemove, position)
c.allowInitializeWithZero = this.allowInitializeWithZero
c.structHasBeenFlattened = this.structHasBeenFlattened
return c
}
}
// a vardecl used only for subroutine parameters

View File

@ -2,9 +2,6 @@
TODO
====
- fix: cube3d is suddenly way bigger than it was a few changes ago
- make sure that in if statements, the left and right operand of the comparison is never a complex expression
anymore (only number, variable, addressof or memread) by rewriting if <left> <op> <right> {..} into:
if_eval_left = left

View File

@ -2,35 +2,15 @@
%zeropage basicsafe
main {
sub start() {
word total
sub start() {
ubyte yy
ubyte joy=1
ubyte zz
joy >>= 1
if_cs
yy++
joy >>= 1
if_cs
yy++
; TODO the shifting checks above result in way smaller code than this:
if joy+44 > 33 {
yy++
repeat 10 {
word wcosa
word zz=1
total += zz
}
yy=joy+44>33
if yy {
yy++
}
if joy & %00000001
yy++
if joy & %00000010
yy++
txt.print_w(total)
}
}