fix problem with reuse of auto-indexer-variables that could result in wrong code for routines using multiple array indexings

This commit is contained in:
Irmen de Jong 2020-12-23 02:30:46 +01:00
parent dc600cc3ed
commit f0f6150e18
4 changed files with 31 additions and 25 deletions

View File

@ -156,28 +156,22 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte
val indexerVarPrefix = "prog8_autovar_index_" val indexerVarPrefix = "prog8_autovar_index_"
val repo = subroutine.asmGenInfo.usedAutoArrayIndexerForStatements val repo = subroutine.asmGenInfo.usedAutoArrayIndexerForStatements
// TODO make this even smarter so that an indexerVar can be reused for a different following statement... requires updating the partOfStatement? // TODO make this a bit smarter so it can reuse indexer variables. BUT BEWARE of scoping+initialization problems then
var indexerVar = repo.firstOrNull { it.replaces isSameAs expr.indexer } // add another loop index var to be used for this expression
if(indexerVar==null) { val indexerVarName = "$indexerVarPrefix${expr.indexer.hashCode()}"
// add another loop index var to be used for this expression val indexerVar = AsmGenInfo.ArrayIndexerInfo(indexerVarName, expr.indexer)
val indexerVarName = "$indexerVarPrefix${expr.indexer.hashCode()}" repo.add(indexerVar)
indexerVar = AsmGenInfo.ArrayIndexerInfo(indexerVarName, expr.indexer, statement) // create the indexer var at block level scope
repo.add(indexerVar) val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.PREFER_ZEROPAGE,
// create the indexer var at block level scope null, indexerVarName, null, null, isArray = false, autogeneratedDontRemove = true, position = expr.position)
val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.PREFER_ZEROPAGE, modifications.add(IAstModification.InsertFirst(vardecl, subroutine))
null, indexerVarName, null, null, isArray = false, autogeneratedDontRemove = true, position = expr.position)
modifications.add(IAstModification.InsertFirst(vardecl, subroutine))
}
indexerVar.used++ // keep track of how many times it it used, to avoid assigning it multiple times
// 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 // assign the indexing expression to the helper variable, but only if that hasn't been done already
val indexerExpression = expr.indexer.origExpression!! val indexerExpression = expr.indexer.origExpression!!
val target = AssignTarget(IdentifierReference(listOf(indexerVar.name), indexerExpression.position), null, null, indexerExpression.position) val target = AssignTarget(IdentifierReference(listOf(indexerVar.name), indexerExpression.position), null, null, indexerExpression.position)
if(indexerVar.used==1) { val assign = Assignment(target, indexerExpression, indexerExpression.position)
val assign = Assignment(target, indexerExpression, indexerExpression.position) modifications.add(IAstModification.InsertBefore(statement, assign, statement.definingScope()))
modifications.add(IAstModification.InsertBefore(statement, assign, statement.definingScope()))
}
modifications.add(IAstModification.SetExpression( { modifications.add(IAstModification.SetExpression( {
expr.indexer.indexVar = it as IdentifierReference expr.indexer.indexVar = it as IdentifierReference
expr.indexer.indexNum = null expr.indexer.indexNum = null

View File

@ -698,7 +698,7 @@ class AsmGenInfo {
var usedFloatEvalResultVar1 = false var usedFloatEvalResultVar1 = false
var usedFloatEvalResultVar2 = false var usedFloatEvalResultVar2 = false
class ArrayIndexerInfo(val name: String, val replaces: ArrayIndex, val partOfStatement: Statement, var used: Int=0) class ArrayIndexerInfo(val name: String, val replaces: ArrayIndex)
} }
// the subroutine class covers both the normal user-defined subroutines, // the subroutine class covers both the normal user-defined subroutines,

View File

@ -3,7 +3,6 @@ TODO
==== ====
- optimize (byte) bitshifting 1<<x (and 2**x) via lookup table 1,2,4,8,... - optimize (byte) bitshifting 1<<x (and 2**x) via lookup table 1,2,4,8,...
- Cx16 target: support full-screen 640x480 and 320x240 graphics? That requires our own custom graphics routines though to draw lines, and plot pixels.
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine) - hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_' - make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_'
- option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging) - option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging)

View File

@ -1,18 +1,29 @@
%import textio %import textio
%import diskio
%import floats
%import graphics %import graphics
%import test_stack %import test_stack
%zeropage basicsafe
%option no_sysinit %option no_sysinit
; TODO full-screen graphics mode library, in development. (as replacement for the graphics routines in ROM that are constrained to 200 vertical pixels and lores mode only)
main { main {
sub start () { sub start () {
ubyte[] modes = [0, 1, 128]
ubyte mode
for mode in modes {
gfx2.set_mode(mode)
gfx2.clear_screen()
draw()
cx16.wait(120)
}
gfx2.set_mode(128) repeat {
gfx2.clear_screen() ;
}
}
sub draw() {
uword offset uword offset
ubyte angle ubyte angle
uword x uword x
@ -42,11 +53,13 @@ main {
gfx2 { gfx2 {
; read-only control variables:
ubyte active_mode = 255 ubyte active_mode = 255
uword width = 0 uword width = 0
uword height = 0 uword height = 0
ubyte bpp = 0 ubyte bpp = 0
sub set_mode(ubyte mode) { sub set_mode(ubyte mode) {
; mode 0 = bitmap 320 x 240 x 1c monochrome ; mode 0 = bitmap 320 x 240 x 1c monochrome
; mode 1 = bitmap 320 x 240 x 256c ; mode 1 = bitmap 320 x 240 x 256c
@ -130,7 +143,7 @@ gfx2 {
ubyte[8] bits = [128, 64, 32, 16, 8, 4, 2, 1] ubyte[8] bits = [128, 64, 32, 16, 8, 4, 2, 1]
when active_mode { when active_mode {
0 -> { 0 -> {
cx16.vpoke_or(0, y*(320/8) + x/8, bits[lsb(x)&7]) ; TODO !?!? if the &7 remains, the code at the '128' label is wrong!!! if changed or removed, the code at 128 works fine! cx16.vpoke_or(0, y*(320/8) + x/8, bits[lsb(x)&7])
} }
1 -> { 1 -> {
void addr_mul_320_add_24(y, x) ; 24 bits result is in r0 and r1L void addr_mul_320_add_24(y, x) ; 24 bits result is in r0 and r1L