more forloop codegen

This commit is contained in:
Irmen de Jong 2020-08-17 21:47:26 +02:00
parent e6ff87ecd0
commit 3976cc26a2
2 changed files with 202 additions and 257 deletions

View File

@ -14,10 +14,6 @@ import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.toHex
import kotlin.math.absoluteValue
// todo choose more efficient comparisons to avoid needless lda's
// todo optimized code for step == 2 or -2
// todo allocate loop counter variable dynamically, preferrably on zeropage
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) {
internal fun translate(stmt: ForLoop) {
@ -41,8 +37,6 @@ internal class ForLoopsAsmGen(private val program: Program, private val asmgen:
}
private fun translateForOverNonconstRange(stmt: ForLoop, iterableDt: DataType, range: RangeExpr) {
// TODO more optimized code possible now that continue is gone?
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
@ -66,13 +60,13 @@ $loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
lda $varname
cmp $ESTACK_LO_PLUS1_HEX,x
cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code
beq $endLabel
$incdec $varname
jmp $loopLabel
$endLabel inx""")
}
else {
} else {
// bytes, step >= 2 or <= -2
@ -93,7 +87,7 @@ $loopLabel""")
clc
adc #$stepsize
sta $varname
cmp $ESTACK_LO_PLUS1_HEX,x
cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code
bcc $loopLabel
beq $loopLabel""")
} else {
@ -101,7 +95,7 @@ $loopLabel""")
sec
sbc #${stepsize.absoluteValue}
sta $varname
cmp $ESTACK_LO_PLUS1_HEX,x
cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code
bcs $loopLabel""")
}
asmgen.out("""
@ -123,10 +117,10 @@ $endLabel inx""")
asmgen.translate(stmt.body)
asmgen.out("""
lda $varname+1
cmp $ESTACK_HI_PLUS1_HEX,x
cmp $ESTACK_HI_PLUS1_HEX,x TODO modifying code
bne +
lda $varname
cmp $ESTACK_LO_PLUS1_HEX,x
cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code
beq $endLabel""")
if(stepsize==1) {
asmgen.out("""
@ -166,12 +160,12 @@ $endLabel inx""")
lda $varname+1
adc #>$stepsize
sta $varname+1
lda $ESTACK_HI_PLUS1_HEX,x
lda $ESTACK_HI_PLUS1_HEX,x TODO modifying code
cmp $varname+1
bcc $endLabel
bne $loopLabel
lda $varname
cmp $ESTACK_LO_PLUS1_HEX,x
cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code
bcc $endLabel
bcs $loopLabel
$endLabel inx""")
@ -184,9 +178,9 @@ $endLabel inx""")
lda $varname+1
adc #>$stepsize
sta $varname+1
lda $ESTACK_LO_PLUS1_HEX,x
lda $ESTACK_LO_PLUS1_HEX,x TODO modifying code
cmp $varname
lda $ESTACK_HI_PLUS1_HEX,x
lda $ESTACK_HI_PLUS1_HEX,x TODO modifying code
sbc $varname+1
bvc +
eor #$80
@ -214,11 +208,11 @@ $endLabel inx""")
lda $varname+1
sbc #>${stepsize.absoluteValue}
sta $varname+1
cmp $ESTACK_HI_PLUS1_HEX,x
cmp $ESTACK_HI_PLUS1_HEX,x TODO modifying code
bcc $endLabel
bne $loopLabel
lda $varname
cmp $ESTACK_LO_PLUS1_HEX,x
cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code
bcs $loopLabel
$endLabel inx""")
} else {
@ -232,9 +226,9 @@ $endLabel inx""")
sbc #>${stepsize.absoluteValue}
sta $varname+1
pla
cmp $ESTACK_LO_PLUS1_HEX,x
cmp $ESTACK_LO_PLUS1_HEX,x TODO modifying code
lda $varname+1
sbc $ESTACK_HI_PLUS1_HEX,x
sbc $ESTACK_HI_PLUS1_HEX,x TODO modifying code
bvc +
eor #$80
+ bpl $loopLabel
@ -250,7 +244,6 @@ $endLabel inx""")
}
private fun translateForOverIterableVar(stmt: ForLoop, iterableDt: DataType, ident: IdentifierReference) {
// TODO more optimized code possible now that continue is gone?
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
@ -275,9 +268,9 @@ $loopLabel lda ${65535.toHex()} ; modified
$endLabel""")
}
DataType.ARRAY_UB, DataType.ARRAY_B -> {
// TODO: optimize loop code when the length of the array is < 256
// TODO: optimize loop code when the length of the array is < 256 (i.e. always)
val length = decl.arraysize!!.size()!!
val counterLabel = asmgen.makeLabel("for_counter")
val counterLabel = asmgen.makeLabel("for_counter") // todo allocate dynamically, zero page preferred if iterations >= 8
val modifiedLabel = asmgen.makeLabel("for_modified")
asmgen.out("""
lda #<$iterableName
@ -294,14 +287,14 @@ $modifiedLabel lda ${65535.toHex()},y ; modified""")
iny
cpy #${length and 255}
beq $endLabel
jmp $loopLabel
bne $loopLabel
$counterLabel .byte 0
$endLabel""")
}
DataType.ARRAY_W, DataType.ARRAY_UW -> {
// TODO: optimize loop code when the length of the array is < 256
// TODO: optimize loop code when the length of the array is < 256 (i.e. always)
val length = decl.arraysize!!.size()!! * 2
val counterLabel = asmgen.makeLabel("for_counter")
val counterLabel = asmgen.makeLabel("for_counter") // todo allocate dynamically, zero page preferred if iterations >= 8
val modifiedLabel = asmgen.makeLabel("for_modified")
val modifiedLabel2 = asmgen.makeLabel("for_modified2")
val loopvarName = asmgen.asmIdentifierName(stmt.loopVar)
@ -327,7 +320,7 @@ $modifiedLabel2 lda ${65535.toHex()},y ; modified
iny
cpy #${length and 255}
beq $endLabel
jmp $loopLabel
bne $loopLabel
$counterLabel .byte 0
$endLabel""")
}
@ -343,179 +336,117 @@ $endLabel""")
if (range.isEmpty() || range.step==0)
throw AssemblyError("empty range or step 0")
if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) {
if(range.step==1 && range.first>=0 && range.last <= 255 && range.last>range.first) return translateForSimpleByteRangeAsc(stmt, range)
if(range.step==-1 && range.first<=255 && range.first >=0 && range.last<range.first) return translateForSimpleByteRangeDesc(stmt, range)
if(range.step==1 && range.last>range.first) return translateForSimpleByteRangeAsc(stmt, range)
if(range.step==-1 && range.last<range.first) return translateForSimpleByteRangeDesc(stmt, range)
}
if(iterableDt==DataType.ARRAY_W || iterableDt==DataType.ARRAY_UW) {
if(range.step==1 && range.first>=0 && range.last <= 255 && range.last>range.first) return translateForSimpleWordRange255Asc(stmt, range)
if(range.step==-1 && range.first<=255 && range.first >=0 && range.last<range.first) return translateForSimpleWordRange255Desc(stmt, range)
if(range.step==1 && range.first>=0 && range.last <= 65535 && range.last>range.first) return translateForSimpleWordRange65535Asc(stmt, range)
if(range.step==-1 && range.first<=65535 && range.first >=0 && range.last<range.first) return translateForSimpleWordRange65535Desc(stmt, range)
else if(iterableDt==DataType.ARRAY_W || iterableDt==DataType.ARRAY_UW) {
if(range.step==1 && range.last>range.first) return translateForSimpleWordRangeAsc(stmt, range)
if(range.step==-1 && range.last<range.first) return translateForSimpleWordRangeDesc(stmt, range)
}
// not one of the easy cases, generate more complex code...
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
// TODO more optimized code possible now that continue is gone?
when(iterableDt) {
DataType.ARRAY_B, DataType.ARRAY_UB -> {
// loop over byte range via loopvar, step > 1 or < -1
val counterLabel = asmgen.makeLabel("for_counter")
// loop over byte range via loopvar, step >= 2 or <= -2
val varname = asmgen.asmIdentifierName(stmt.loopVar)
when {
range.step==1 || range.step==-1 -> {
throw AssemblyError("step 1 and -1 should have been handled specifically")
}
range.step >= 2 -> {
// step >= 2
asmgen.out("""
lda #${(range.last-range.first) / range.step + 1}
sta $counterLabel
lda #${range.first}
sta $varname
asmgen.out("""
lda #${range.first}
sta $varname
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
dec $counterLabel
beq $endLabel
lda $varname
clc
adc #${range.step}
sta $varname
jmp $loopLabel
$counterLabel .byte 0
$endLabel""")
asmgen.translate(stmt.body)
when (range.step) {
0, 1, -1 -> {
throw AssemblyError("step 0, 1 and -1 should have been handled specifically $stmt")
}
2 -> {
if(range.last==255) {
asmgen.out("""
inc $varname
beq $endLabel
inc $varname
bne $loopLabel""")
} else {
asmgen.out("""
lda $varname
cmp #${range.last}
beq $endLabel
inc $varname
inc $varname
jmp $loopLabel""")
}
}
-2 -> {
when (range.last) {
0 -> asmgen.out("""
lda $varname
beq $endLabel
dec $varname
dec $varname
jmp $loopLabel""")
1 -> asmgen.out("""
dec $varname
beq $endLabel
dec $varname
bne $loopLabel""")
else -> asmgen.out("""
lda $varname
cmp #${range.last}
beq $endLabel
dec $varname
dec $varname
jmp $loopLabel""")
}
}
else -> {
// step <= -2
// step <= -3 or >= 3
asmgen.out("""
lda #${(range.first-range.last) / range.step.absoluteValue + 1}
sta $counterLabel
lda #${range.first}
sta $varname
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
dec $counterLabel
beq $endLabel
lda $varname
sec
sbc #${range.step.absoluteValue}
sta $varname
jmp $loopLabel
$counterLabel .byte 0
$endLabel""")
lda $varname
cmp #${range.last}
beq $endLabel
clc
adc #${range.step}
sta $varname
jmp $loopLabel""")
}
}
asmgen.out(endLabel)
}
DataType.ARRAY_W, DataType.ARRAY_UW -> {
// loop over word range via loopvar, step > 1 or < -1
// loop over word range via loopvar, step >= 2 or <= -2
val varname = asmgen.asmIdentifierName(stmt.loopVar)
when {
range.step==1 || range.step==-1 -> {
throw AssemblyError("step 1 and -1 should have been handled specifically")
}
// range.step == 1 -> {
// // word, step = 1
// val lastValue = range.last+1
// asmgen.out("""
// lda #<${range.first}
// ldy #>${range.first}
// sta $varname
// sty $varname+1
//$loopLabel""")
// asmgen.translate(stmt.body)
// asmgen.out("""
// inc $varname
// bne +
// inc $varname+1
//+ lda $varname
// cmp #<$lastValue
// bne +
// lda $varname+1
// cmp #>$lastValue
// beq $endLabel
//+ jmp $loopLabel
//$endLabel""")
// }
// range.step == -1 -> {
// // word, step = 1
// val lastValue = range.last-1
// asmgen.out("""
// lda #<${range.first}
// ldy #>${range.first}
// sta $varname
// sty $varname+1
//$loopLabel""")
// asmgen.translate(stmt.body)
// asmgen.out("""
// lda $varname
// bne +
// dec $varname+1
//+ dec $varname
// lda $varname
// cmp #<$lastValue
// bne +
// lda $varname+1
// cmp #>$lastValue
// beq $endLabel
//+ jmp $loopLabel
//$endLabel""")
// }
range.step >= 2 -> {
// word, step >= 2
// note: range.last has already been adjusted by kotlin itself to actually be the last value of the sequence
val lastValue = range.last+range.step
asmgen.out("""
lda #<${range.first}
ldy #>${range.first}
sta $varname
sty $varname+1
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
clc
lda $varname
adc #<${range.step}
sta $varname
lda $varname+1
adc #>${range.step}
sta $varname+1
lda $varname
cmp #<$lastValue
bne +
lda $varname+1
cmp #>$lastValue
beq $endLabel
+ jmp $loopLabel
$endLabel""")
when (range.step) {
0, 1, -1 -> {
throw AssemblyError("step 0, 1 and -1 should have been handled specifically $stmt")
}
else -> {
// step <= -2
// word, step >= 2 or <= -2
// note: range.last has already been adjusted by kotlin itself to actually be the last value of the sequence
val lastValue = range.last+range.step
asmgen.out("""
lda #<${range.first}
ldy #>${range.first}
sta $varname
sty $varname+1
lda #<${range.first}
ldy #>${range.first}
sta $varname
sty $varname+1
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
sec
lda $varname
sbc #<${range.step.absoluteValue}
sta $varname
lda $varname+1
sbc #>${range.step.absoluteValue}
sta $varname+1
lda $varname
cmp #<$lastValue
bne +
lda $varname+1
cmp #>$lastValue
beq $endLabel
+ jmp $loopLabel
lda $varname
cmp #<${range.last}
bne +
lda $varname+1
cmp #>${range.last}
bne +
beq $endLabel
+ lda $varname
clc
adc #<${range.step}
sta $varname
lda $varname+1
adc #>${range.step}
sta $varname+1
jmp $loopLabel
$endLabel""")
}
}
@ -530,28 +461,23 @@ $endLabel""")
val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val varname = asmgen.asmIdentifierName(stmt.loopVar)
if (range.last == 255) {
asmgen.out("""
asmgen.out("""
lda #${range.first}
sta $varname
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.translate(stmt.body)
if (range.last == 255) {
asmgen.out("""
inc $varname
bne $loopLabel
$endLabel""")
} else {
asmgen.out("""
lda #${range.first}
sta $varname
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
lda $varname
cmp #${range.last}
beq $endLabel
inc $varname
bne $loopLabel
jmp $loopLabel
$endLabel""")
}
asmgen.loopEndLabels.pop()
@ -562,13 +488,13 @@ $endLabel""")
val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val varname = asmgen.asmIdentifierName(stmt.loopVar)
when (range.last) {
0 -> {
asmgen.out("""
asmgen.out("""
lda #${range.first}
sta $varname
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.translate(stmt.body)
when (range.last) {
0 -> {
asmgen.out("""
lda $varname
beq $endLabel
@ -577,48 +503,78 @@ $loopLabel""")
$endLabel""")
}
1 -> {
asmgen.out("""
lda #${range.first}
sta $varname
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
dec $varname
bne $loopLabel
jmp $loopLabel
$endLabel""")
}
else -> {
asmgen.out("""
lda #${range.first}
sta $varname
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
lda $varname
cmp #${range.last}
beq $endLabel
dec $varname
bne $loopLabel
jmp $loopLabel
$endLabel""")
}
}
asmgen.loopEndLabels.pop()
}
private fun translateForSimpleWordRange255Asc(stmt: ForLoop, range: IntProgression) {
TODO("Not yet implemented")
private fun translateForSimpleWordRangeAsc(stmt: ForLoop, range: IntProgression) {
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val varname = asmgen.asmIdentifierName(stmt.loopVar)
asmgen.out("""
lda #<${range.first}
ldy #>${range.first}
sta $varname
sty $varname+1
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
lda $varname
cmp #<${range.last}
bne +
lda $varname+1
cmp #>${range.last}
bne +
beq $endLabel
+ inc $varname
bne $loopLabel
inc $varname+1
jmp $loopLabel
$endLabel""")
asmgen.loopEndLabels.pop()
}
private fun translateForSimpleWordRange255Desc(stmt: ForLoop, range: IntProgression) {
TODO("Not yet implemented")
private fun translateForSimpleWordRangeDesc(stmt: ForLoop, range: IntProgression) {
val loopLabel = asmgen.makeLabel("for_loop")
val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val varname = asmgen.asmIdentifierName(stmt.loopVar)
asmgen.out("""
lda #<${range.first}
ldy #>${range.first}
sta $varname
sty $varname+1
$loopLabel""")
asmgen.translate(stmt.body)
asmgen.out("""
lda $varname
cmp #<${range.last}
bne +
lda $varname+1
cmp #>${range.last}
bne +
beq $endLabel
+ lda $varname
bne +
dec $varname+1
+ dec $varname
jmp $loopLabel
$endLabel""")
asmgen.loopEndLabels.pop()
}
private fun translateForSimpleWordRange65535Asc(stmt: ForLoop, range: IntProgression) {
TODO("Not yet implemented")
}
private fun translateForSimpleWordRange65535Desc(stmt: ForLoop, range: IntProgression) {
TODO("Not yet implemented")
}
}

View File

@ -6,93 +6,82 @@
main {
sub start() {
ubyte counterb
uword counterw
byte counterb
word counterw
for counterb in 0 to 10 {
c64scr.print_ub(counterb)
for counterb in -10 to 11 {
c64scr.print_b(counterb)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterb in 10 to 30 {
c64scr.print_ub(counterb)
for counterb in 11 to -10 step -1 {
c64scr.print_b(counterb)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterb in 250 to 255 {
c64scr.print_ub(counterb)
for counterb in -10 to 11 step 2 {
c64scr.print_b(counterb)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterb in 10 to 0 step -1 {
c64scr.print_ub(counterb)
for counterb in 11 to -10 step -2 {
c64scr.print_b(counterb)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterb in 10 to 1 step -1 {
c64scr.print_ub(counterb)
for counterb in -10 to 11 step 3 {
c64scr.print_b(counterb)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterb in 30 to 10 step -1 {
c64scr.print_ub(counterb)
for counterb in 11 to -10 step -3 {
c64scr.print_b(counterb)
c64.CHROUT(',')
}
c64.CHROUT('\n')
c64.CHROUT('\n')
c64.CHROUT('\n')
for counterw in -10 to 11 {
c64scr.print_w(counterw)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterb in 255 to 250 step -1 {
c64scr.print_ub(counterb)
c64.CHROUT(',')
}
c64.CHROUT('\n')
c64.CHROUT('\n')
for counterw in 0 to 10 {
c64scr.print_uw(counterw)
for counterw in 11 to -10 step -1 {
c64scr.print_w(counterw)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterw in 10 to 30 {
c64scr.print_uw(counterw)
for counterw in -10 to 11 step 2 {
c64scr.print_w(counterw)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterw in 250 to 255 {
c64scr.print_uw(counterw)
for counterw in 11 to -10 step -2 {
c64scr.print_w(counterw)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterw in 10 to 0 step -1 {
c64scr.print_uw(counterw)
for counterw in -10 to 11 step 3 {
c64scr.print_w(counterw)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterw in 10 to 1 step -1 {
c64scr.print_uw(counterw)
for counterw in 11 to -10 step -3 {
c64scr.print_w(counterw)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterw in 30 to 10 step -1 {
c64scr.print_uw(counterw)
c64.CHROUT(',')
}
c64.CHROUT('\n')
for counterw in 255 to 250 step -1 {
c64scr.print_uw(counterw)
c64.CHROUT(',')
}
c64.CHROUT('\n')
}
}