mirror of
https://github.com/irmen/prog8.git
synced 2025-01-26 19:30:59 +00:00
for loops no longer execute when from var already reached beyond the end
This commit is contained in:
parent
3d69a95c49
commit
21bc505d85
@ -54,19 +54,28 @@ internal class ForLoopsAsmGen(private val program: PtProgram,
|
||||
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false)
|
||||
// pre-check for end already reached
|
||||
if(iterableDt==DataType.ARRAY_B) {
|
||||
if(stepsize<0) {
|
||||
println("signed byte check to<=from") // TODO
|
||||
} else {
|
||||
println("signed byte check from<=to") // TODO
|
||||
}
|
||||
asmgen.out(" sta $modifiedLabel+1")
|
||||
if(stepsize<0)
|
||||
asmgen.out("""
|
||||
clc
|
||||
sbc $varname
|
||||
bvc +
|
||||
eor #${'$'}80
|
||||
+ bpl $endLabel""")
|
||||
else
|
||||
asmgen.out("""
|
||||
clc
|
||||
sbc $varname
|
||||
bvc +
|
||||
eor #${'$'}80
|
||||
+ bmi $endLabel""")
|
||||
} else {
|
||||
if(stepsize<0) {
|
||||
println("unsigned byte check to<=from") // TODO
|
||||
} else {
|
||||
println("unsigned byte check from<=to") // TODO
|
||||
}
|
||||
if(stepsize<0)
|
||||
asmgen.out(" cmp $varname | bcs $endLabel")
|
||||
else
|
||||
asmgen.out(" cmp $varname | bcc $endLabel | beq $endLabel")
|
||||
asmgen.out(" sta $modifiedLabel+1")
|
||||
}
|
||||
asmgen.out(" sta $modifiedLabel+1")
|
||||
asmgen.out(loopLabel)
|
||||
asmgen.translate(stmt.statements)
|
||||
asmgen.out("""
|
||||
@ -84,20 +93,30 @@ $modifiedLabel cmp #0 ; modified
|
||||
// loop over byte range via loopvar
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt))
|
||||
asmgen.assignExpressionToVariable(range.to, "$modifiedLabel+1", ArrayToElementTypes.getValue(iterableDt))
|
||||
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false)
|
||||
// pre-check for end already reached
|
||||
if(iterableDt==DataType.ARRAY_B) {
|
||||
if(stepsize<0) {
|
||||
println("signed byte check to<=from") // TODO
|
||||
} else {
|
||||
println("signed byte check from<=to") // TODO
|
||||
}
|
||||
asmgen.out(" sta $modifiedLabel+1")
|
||||
if(stepsize<0)
|
||||
asmgen.out("""
|
||||
clc
|
||||
sbc $varname
|
||||
bvc +
|
||||
eor #${'$'}80
|
||||
+ bpl $endLabel""")
|
||||
else
|
||||
asmgen.out("""
|
||||
clc
|
||||
sbc $varname
|
||||
bvc +
|
||||
eor #${'$'}80
|
||||
+ bmi $endLabel""")
|
||||
} else {
|
||||
if(stepsize<0) {
|
||||
println("unsigned byte check to<=from") // TODO
|
||||
} else {
|
||||
println("unsigned byte check from<=to") // TODO
|
||||
}
|
||||
if(stepsize<0)
|
||||
asmgen.out(" cmp $varname | bcs $endLabel")
|
||||
else
|
||||
asmgen.out(" cmp $varname | bcc $endLabel | beq $endLabel")
|
||||
asmgen.out(" sta $modifiedLabel+1")
|
||||
}
|
||||
asmgen.out(loopLabel)
|
||||
asmgen.translate(stmt.statements)
|
||||
@ -129,22 +148,9 @@ $modifiedLabel cmp #0 ; modified
|
||||
|
||||
stepsize == 1 || stepsize == -1 -> {
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
assignLoopvar(stmt, range)
|
||||
assignLoopvarWord(stmt, range)
|
||||
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
|
||||
// pre-check for end already reached
|
||||
if(iterableDt==DataType.ARRAY_W) {
|
||||
if(stepsize<0) {
|
||||
println("signed word check to<=from") // TODO
|
||||
} else {
|
||||
println("signed word check from<=to") // TODO
|
||||
}
|
||||
} else {
|
||||
if(stepsize<0) {
|
||||
println("unsigned word check to<=from") // TODO
|
||||
} else {
|
||||
println("unsigned word check from<=to") // TODO
|
||||
}
|
||||
}
|
||||
precheckFromToWord(iterableDt, stepsize, varname, endLabel)
|
||||
asmgen.out("""
|
||||
sty $modifiedLabel+1
|
||||
sta $modifiedLabel2+1
|
||||
@ -177,14 +183,9 @@ $modifiedLabel2 cmp #0 ; modified
|
||||
|
||||
// (u)words, step >= 2
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
assignLoopvar(stmt, range)
|
||||
assignLoopvarWord(stmt, range)
|
||||
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
|
||||
// pre-check for end already reached
|
||||
if(iterableDt==DataType.ARRAY_W) {
|
||||
println("signed word check from<=to") // TODO
|
||||
} else {
|
||||
println("unsigned word check from<=to") // TODO
|
||||
}
|
||||
precheckFromToWord(iterableDt, stepsize, varname, endLabel)
|
||||
asmgen.out("""
|
||||
sty $modifiedLabel+1
|
||||
sta $modifiedLabel2+1
|
||||
@ -231,14 +232,9 @@ $endLabel""")
|
||||
|
||||
// (u)words, step <= -2
|
||||
val varname = asmgen.asmVariableName(stmt.variable)
|
||||
assignLoopvar(stmt, range)
|
||||
assignLoopvarWord(stmt, range)
|
||||
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
|
||||
// pre-check for end already reached
|
||||
if(iterableDt==DataType.ARRAY_W) {
|
||||
println("signed word check to<=from") // TODO
|
||||
} else {
|
||||
println("unsigned word check to<=from") // TODO
|
||||
}
|
||||
precheckFromToWord(iterableDt, stepsize, varname, endLabel)
|
||||
asmgen.out("""
|
||||
sty $modifiedLabel+1
|
||||
sta $modifiedLabel2+1
|
||||
@ -289,6 +285,53 @@ $endLabel""")
|
||||
asmgen.loopEndLabels.pop()
|
||||
}
|
||||
|
||||
private fun precheckFromToWord(iterableDt: DataType, stepsize: Int, fromVar: String, endLabel: String) {
|
||||
// pre-check for end already reached.
|
||||
// 'to' is in AY, do NOT clobber this!
|
||||
if(iterableDt==DataType.ARRAY_W) {
|
||||
if(stepsize<0)
|
||||
asmgen.out("""
|
||||
sta P8ZP_SCRATCH_REG
|
||||
cmp $fromVar
|
||||
tya
|
||||
sbc $fromVar+1
|
||||
bvc +
|
||||
eor #${'$'}80
|
||||
+ bpl $endLabel
|
||||
lda P8ZP_SCRATCH_REG""")
|
||||
else
|
||||
asmgen.out("""
|
||||
sta P8ZP_SCRATCH_REG
|
||||
cmp $fromVar
|
||||
tya
|
||||
sbc $fromVar+1
|
||||
bvc +
|
||||
eor #${'$'}80
|
||||
+ bmi $endLabel
|
||||
lda P8ZP_SCRATCH_REG""")
|
||||
} else {
|
||||
if(stepsize<0)
|
||||
asmgen.out("""
|
||||
cpy $fromVar+1
|
||||
beq +
|
||||
bcc ++
|
||||
bcs $endLabel
|
||||
+ cmp $fromVar
|
||||
bcc +
|
||||
beq +
|
||||
bne $endLabel
|
||||
+""")
|
||||
else
|
||||
asmgen.out("""
|
||||
cpy $fromVar+1
|
||||
bcc $endLabel
|
||||
bne +
|
||||
cmp $fromVar
|
||||
bcc $endLabel
|
||||
+""")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateForOverIterableVar(stmt: PtForLoop, iterableDt: DataType, ident: PtIdentifier) {
|
||||
val loopLabel = asmgen.makeLabel("for_loop")
|
||||
val endLabel = asmgen.makeLabel("for_end")
|
||||
@ -645,7 +688,7 @@ $loopLabel""")
|
||||
asmgen.loopEndLabels.pop()
|
||||
}
|
||||
|
||||
private fun assignLoopvar(stmt: PtForLoop, range: PtRange) =
|
||||
private fun assignLoopvarWord(stmt: PtForLoop, range: PtRange) =
|
||||
asmgen.assignExpressionToVariable(
|
||||
range.from,
|
||||
asmgen.asmVariableName(stmt.variable),
|
||||
|
@ -473,6 +473,7 @@ Loops
|
||||
The *for*-loop is used to let a variable iterate over a range of values. Iteration is done in steps of 1, but you can change this.
|
||||
The loop variable must be declared separately as byte or word earlier, so that you can reuse it for multiple occasions.
|
||||
Iterating with a floating point variable is not supported. If you want to loop over a floating-point array, use a loop with an integer index variable instead.
|
||||
If the from value is already outside of the loop range, the whole for loop is skipped.
|
||||
|
||||
The *while*-loop is used to repeat a piece of code while a certain condition is still true.
|
||||
The *do--until* loop is used to repeat a piece of code until a certain condition is true.
|
||||
@ -492,16 +493,6 @@ Only simple statements are allowed to be inside an unroll loop (assignments, fun
|
||||
on it to be the last value in the range for instance! The value of the variable should only be used inside the for loop body.
|
||||
(this is an optimization issue to avoid having to deal with mostly useless post-loop logic to adjust the loop variable's value)
|
||||
|
||||
.. warning::
|
||||
For efficiency reasons, it is assumed that the ending value of the for loop is actually >= the starting value
|
||||
(or <= if the step is negative). This means that for loops in prog8 behave differently than in other
|
||||
languages if this is *not* the case! A for loop from ubyte 10 to ubyte 2, for example, will iterate through
|
||||
all values 10, 11, 12, 13, .... 254, 255, 0 (wrapped), 1, 2. In other languages the entire loop will
|
||||
be skipped in such cases. But prog8 omits the overhead of an extra loop range check and/or branch for every for loop
|
||||
because the most common case is that it is not needed.
|
||||
You should add an explicit range check yourself if the ending value can be less than the start value and
|
||||
a full wrap-around loop is not what you want!
|
||||
|
||||
|
||||
Conditional Execution
|
||||
---------------------
|
||||
|
@ -10,12 +10,8 @@ For 9.0 major changes
|
||||
- DONE: divmod() now supports multiple datatypes. divmodw() has been removed.
|
||||
- DONE: cx16diskio module merged into diskio (which got specialized for commander x16 target). load() and load_raw() with extra ram bank parameter are gone.
|
||||
- DONE: drivenumber parameter removed from all routines in diskio module. The drive to work on is now simply stored as a diskio.drivenumber variable, which defaults to 8.
|
||||
- DONE: for loops now skip the whole loop if from value already outside the loop range (this is what all other programming languages also do)
|
||||
|
||||
- VM codegen: fix for loop pre-check for negative stepsizes.
|
||||
- 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition.
|
||||
It is documented behavior to now loop 'around' $00 but it's too easy to forget about!
|
||||
Lot of work because of many special cases in ForLoopsAsmgen.translateForOverNonconstRange()
|
||||
(vm codegen already behaves like this partly! Except for negative step sizes right now)
|
||||
- once 9.0 is stable, upgrade other programs (assem, shell, etc) to it. + add migration guide to the manual.
|
||||
- [much work:] add special (u)word array type (or modifier such as @fast? ) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing
|
||||
this is an enormous amout of work, if this type is to be treated equally as existing (u)word , because all expression / lookup / assignment routines need to know about the distinction....
|
||||
|
@ -5,67 +5,107 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
ubyte from = 20
|
||||
ubyte target = 10
|
||||
ubyte from = 250
|
||||
|
||||
ubyte xx
|
||||
for xx in from to target {
|
||||
txt.print_ub(xx)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n")
|
||||
txt.print("done\n\n")
|
||||
for xx in target downto from {
|
||||
txt.print_ub(xx)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n")
|
||||
txt.print("done\n\n")
|
||||
|
||||
byte starget = -120
|
||||
byte sfrom = 120
|
||||
byte sfrom = -10
|
||||
byte starget = -20
|
||||
|
||||
byte sxx
|
||||
for sxx in sfrom to starget {
|
||||
txt.print_b(sxx)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n")
|
||||
txt.print("done\n\n")
|
||||
for sxx in starget downto sfrom {
|
||||
txt.print_b(sxx)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n")
|
||||
txt.print("done\n\n")
|
||||
|
||||
uword wtarget = 10
|
||||
uword wfrom = 65530
|
||||
uword wfrom = 1020
|
||||
uword wtarget = 1010
|
||||
|
||||
uword ww
|
||||
for ww in wfrom to wtarget {
|
||||
txt.print_uw(ww)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n")
|
||||
txt.print("done\n\n")
|
||||
for ww in wtarget downto wfrom {
|
||||
txt.print_uw(ww)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n")
|
||||
txt.print("done\n\n")
|
||||
|
||||
word swtarget = -32760
|
||||
word swfrom = 32760
|
||||
word swfrom = -1010
|
||||
word swtarget = -1020
|
||||
word sww
|
||||
for sww in swfrom to swtarget {
|
||||
txt.print_w(sww)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n")
|
||||
txt.print("done\n\n")
|
||||
for sww in swtarget downto swfrom {
|
||||
txt.print_w(sww)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n")
|
||||
txt.print("done\n\n")
|
||||
|
||||
; all of the above with stepsize 2 / -2
|
||||
for xx in from to target step 2{
|
||||
txt.print_ub(xx)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n\n")
|
||||
for xx in target downto from step -2 {
|
||||
txt.print_ub(xx)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n\n")
|
||||
for sxx in sfrom to starget step 2 {
|
||||
txt.print_b(sxx)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n\n")
|
||||
for sxx in starget downto sfrom step -2 {
|
||||
txt.print_b(sxx)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n\n")
|
||||
for ww in wfrom to wtarget step 2 {
|
||||
txt.print_uw(ww)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n\n")
|
||||
for ww in wtarget downto wfrom step -2 {
|
||||
txt.print_uw(ww)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n\n")
|
||||
for sww in swfrom to swtarget step 2 {
|
||||
txt.print_w(sww)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n\n")
|
||||
for sww in swtarget downto swfrom step -2 {
|
||||
txt.print_w(sww)
|
||||
txt.spc()
|
||||
}
|
||||
txt.print("done\n\n")
|
||||
|
||||
; TODO all of the above with stepsize 2 / -2
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user