mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
no longer generate double assignment to the indexer var for in-place modifying array variable
This commit is contained in:
parent
e876008427
commit
83fbf86b1c
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
; }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user