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 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?
var indexerVar = repo.firstOrNull { it.replaces isSameAs expr.indexer }
if(indexerVar==null) {
// add another loop index var to be used for this expression
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))
}
indexerVar.used++ // keep track of how many times it it used, to avoid assigning it multiple times
// TODO make this a bit smarter so it can reuse indexer variables. BUT BEWARE of scoping+initialization problems then
// add another loop index var to be used for this expression
val indexerVarName = "$indexerVarPrefix${expr.indexer.hashCode()}"
val indexerVar = AsmGenInfo.ArrayIndexerInfo(indexerVarName, expr.indexer)
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))
// 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(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()))
}
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

@ -698,7 +698,7 @@ class AsmGenInfo {
var usedFloatEvalResultVar1 = 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,

View File

@ -3,7 +3,6 @@ TODO
====
- 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)
- 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)

View File

@ -1,18 +1,29 @@
%import textio
%import diskio
%import floats
%import graphics
%import test_stack
%zeropage basicsafe
%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 {
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)
gfx2.clear_screen()
repeat {
;
}
}
sub draw() {
uword offset
ubyte angle
uword x
@ -42,11 +53,13 @@ main {
gfx2 {
; read-only control variables:
ubyte active_mode = 255
uword width = 0
uword height = 0
ubyte bpp = 0
sub set_mode(ubyte mode) {
; mode 0 = bitmap 320 x 240 x 1c monochrome
; mode 1 = bitmap 320 x 240 x 256c
@ -130,7 +143,7 @@ gfx2 {
ubyte[8] bits = [128, 64, 32, 16, 8, 4, 2, 1]
when active_mode {
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 -> {
void addr_mul_320_add_24(y, x) ; 24 bits result is in r0 and r1L