no longer generate double assignment to the indexer var for in-place modifying array variable

This commit is contained in:
Irmen de Jong 2020-11-27 23:46:01 +01:00
parent e876008427
commit 83fbf86b1c
4 changed files with 93 additions and 47 deletions

View File

@ -216,6 +216,14 @@ interface INameScope {
null
}
fun previousSibling(stmt: Statement): Statement? {
val previousIdx = statements.indexOfFirst { it===stmt } - 1
return if(previousIdx>=0)
statements[previousIdx]
else
null
}
fun indexOfChild(stmt: Statement): Int {
val idx = statements.indexOfFirst { it===stmt }
if(idx>=0)

View File

@ -96,36 +96,30 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte
val subroutine = expr.definingSubroutine()!!
val statement = expr.containingStatement()
val indexerVarPrefix = "prog8_autovar_index_"
val indexerVarName: String
val repo = subroutine.asmGenInfo.usedAutoArrayIndexerForStatements
val freeVar = repo.filter { statement !in it.value }.map { it.key }.firstOrNull()
if(freeVar==null) {
// TODO make this even smarter so that an indexerVar can be reused for a different following statement... requires updating the partOfStatement?
var indexerVar = repo.firstOrNull { it.replaces isSameAs expr.indexer }
if(indexerVar==null) {
// add another loop index var to be used for this expression
val statementId = expr.hashCode()
indexerVarName = "$indexerVarPrefix$statementId"
val indexerVarName = "$indexerVarPrefix${expr.indexer.hashCode()}"
indexerVar = AsmGenInfo.ArrayIndexerInfo(indexerVarName, expr.indexer, statement)
repo.add(indexerVar)
// create the indexer var at block level scope
val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.PREFER_ZEROPAGE,
null, indexerVarName, null, null, isArray = false, autogeneratedDontRemove = true, position = expr.position)
modifications.add(IAstModification.InsertFirst(vardecl, subroutine))
var statements = repo[indexerVarName]
if(statements==null) {
statements = mutableSetOf()
repo[indexerVarName] = statements
}
statements.add(statement)
} else {
// reuse an already created indexer autovar
repo.getValue(freeVar).add(statement)
indexerVarName = freeVar
}
indexerVar.used++ // keep track of how many times it it used, to avoid assigning it multiple times
// assign the indexing expression to the helper variable, and replace the indexer with just the variable
// replace the indexer with just the variable
// assign the indexing expression to the helper variable, but only if that hasn't been done already
val indexerExpression = expr.indexer.origExpression!!
val target = AssignTarget(IdentifierReference(listOf(indexerVarName), indexerExpression.position), null, null, indexerExpression.position)
val assign = Assignment(target, indexerExpression, indexerExpression.position)
val beforeWhat = expr.containingStatement()
modifications.add(IAstModification.InsertBefore(beforeWhat, assign, beforeWhat.definingScope()))
val target = AssignTarget(IdentifierReference(listOf(indexerVar.name), indexerExpression.position), null, null, indexerExpression.position)
if(indexerVar.used==1) {
val assign = Assignment(target, indexerExpression, indexerExpression.position)
modifications.add(IAstModification.InsertBefore(statement, assign, statement.definingScope()))
}
modifications.add(IAstModification.SetExpression( {
expr.indexer.indexVar = it as IdentifierReference
expr.indexer.indexNum = null

View File

@ -313,6 +313,7 @@ class ArrayIndex(var origExpression: Expression?, // will be replaced
}
is IdentifierReference -> {
indexVar = replacement
indexNum = null
}
else -> {
throw FatalAstException("invalid replace")
@ -347,7 +348,12 @@ class ArrayIndex(var origExpression: Expression?, // will be replaced
fun constIndex() = indexNum?.number?.toInt()
infix fun isSameAs(other: ArrayIndex) = indexNum==other.indexNum && indexVar == other.indexVar
infix fun isSameAs(other: ArrayIndex): Boolean {
return if(indexNum!=null || indexVar!=null)
indexNum==other.indexNum && indexVar == other.indexVar
else
other.origExpression!=null && origExpression!! isSameAs other.origExpression!!
}
}
open class Assignment(var target: AssignTarget, var value: Expression, override val position: Position) : Statement() {
@ -679,16 +685,19 @@ class NopStatement(override val position: Position): Statement() {
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
}
class AsmGenInfo {
// This class contains various attributes that influence the assembly code generator.
// Conceptually it should be part of any INameScope.
// But because the resulting code only creates "real" scopes on a subroutine level,
// it's more consistent to only define these attributes on a Subroutine node.
var usedAutoArrayIndexerForStatements = mutableMapOf<String, MutableSet<Statement>>()
var usedAutoArrayIndexerForStatements = mutableListOf<ArrayIndexerInfo>()
var usedRegsaveA = false
var usedRegsaveX = false
var usedRegsaveY = false
var usedFloatEvalResultVar = false
class ArrayIndexerInfo(val name: String, val replaces: ArrayIndex, val partOfStatement: Statement, var used: Int=0)
}
// the subroutine class covers both the normal user-defined subroutines,

View File

@ -7,33 +7,68 @@ main {
sub start() {
float fl
word ww
uword uw
byte bb
ubyte ub
str string1 = "irmen"
uword[] array = [1111,2222,3333]
ubyte[] ubarray = [100,200]
uw = string1 as uword
txt.print_uwhex(uw,1)
txt.chrout('\n')
uw = array as uword
txt.print_uwhex(uw,1)
txt.chrout('\n')
uw = name() as uword
txt.print_uwhex(uw,1)
txt.chrout('\n')
uw = name()
txt.print_uwhex(uw,1)
txt.chrout('\n')
test_stack.test()
ubyte index = 0
ubarray[index+1] += 13
ubarray[index+1] += 13
ubarray[index+1] += 13
ubarray[index+2] += 13
txt.print_ub(ubarray[1])
txt.chrout('\n')
}
sub name() -> str {
return "irmen"
}
; sub start222() {
;
; ubyte[] ubarray = [100,200]
; uword[] uwarray = [1000,2000]
; float[] flarray = [100.1, 200.2]
;
; ubyte index = 1
;
; ubarray[1] += 3
; txt.print_ub(ubarray[1])
; txt.chrout('\n')
; ubarray[index] += 3
; txt.print_ub(ubarray[1])
; txt.chrout('\n')
; index = 0
; ubarray[index*99+1] += 3
; txt.print_ub(ubarray[1])
; txt.chrout('\n')
; txt.chrout('\n')
;
; index = 1
; uwarray[1] += 3
; txt.print_uw(uwarray[1])
; txt.chrout('\n')
; uwarray[index] += 3
; txt.print_uw(uwarray[1])
; txt.chrout('\n')
; index = 0
; uwarray[index*99+1] += 3
; txt.print_uw(uwarray[1])
; txt.chrout('\n')
; txt.chrout('\n')
;
; index=1
; flarray[1] += 3.0
; floats.print_f(flarray[1])
; txt.chrout('\n')
; flarray[index] += 3.0
; floats.print_f(flarray[1])
; txt.chrout('\n')
; index = 0
; flarray[index*99+1] += 3.0
; floats.print_f(flarray[1])
; txt.chrout('\n')
;
; test_stack.test()
;
; }
;
; sub name() -> str {
; return "irmen"
; }
}