mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
improved codegen for for loops downto 0
This commit is contained in:
parent
4a2dcd20d1
commit
699a2bb7ab
@ -60,13 +60,18 @@ internal class ForLoopsAsmGen(
|
|||||||
// pre-check for end already reached
|
// pre-check for end already reached
|
||||||
if(iterableDt==DataType.ARRAY_B) {
|
if(iterableDt==DataType.ARRAY_B) {
|
||||||
asmgen.out(" sta $modifiedLabel+1")
|
asmgen.out(" sta $modifiedLabel+1")
|
||||||
if(stepsize<0)
|
if(stepsize<0) {
|
||||||
|
if(range.to.asConstInteger()==0 && asmgen.options.optimize) {
|
||||||
|
throw AssemblyError("downto 0 (signed byte) should have been replaced by an until-loop")
|
||||||
|
} else {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
clc
|
clc
|
||||||
sbc $varname
|
sbc $varname
|
||||||
bvc +
|
bvc +
|
||||||
eor #${'$'}80
|
eor #${'$'}80
|
||||||
+ bpl $endLabel""")
|
+ bpl $endLabel""")
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
sec
|
sec
|
||||||
@ -75,12 +80,17 @@ internal class ForLoopsAsmGen(
|
|||||||
eor #${'$'}80
|
eor #${'$'}80
|
||||||
+ bmi $endLabel""")
|
+ bmi $endLabel""")
|
||||||
} else {
|
} else {
|
||||||
if(stepsize<0)
|
if(stepsize<0) {
|
||||||
|
if(range.to.asConstInteger()==0 && asmgen.options.optimize) {
|
||||||
|
throw AssemblyError("downto 0 (unsigned byte) should have been replaced by an until-loop")
|
||||||
|
} else {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
cmp $varname
|
cmp $varname
|
||||||
beq +
|
beq +
|
||||||
bcs $endLabel
|
bcs $endLabel
|
||||||
+""")
|
+""")
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
asmgen.out(" cmp $varname | bcc $endLabel")
|
asmgen.out(" cmp $varname | bcc $endLabel")
|
||||||
asmgen.out(" sta $modifiedLabel+1")
|
asmgen.out(" sta $modifiedLabel+1")
|
||||||
@ -160,6 +170,8 @@ $modifiedLabel cmp #0 ; modified
|
|||||||
// words, step 1 or -1
|
// words, step 1 or -1
|
||||||
|
|
||||||
stepsize == 1 || stepsize == -1 -> {
|
stepsize == 1 || stepsize == -1 -> {
|
||||||
|
if(range.to.asConstInteger()==0 && asmgen.options.optimize)
|
||||||
|
throw AssemblyError("downto 0 (words) should have been replaced by an until-loop")
|
||||||
val varname = asmgen.asmVariableName(stmt.variable)
|
val varname = asmgen.asmVariableName(stmt.variable)
|
||||||
assignLoopvarWord(stmt, range)
|
assignLoopvarWord(stmt, range)
|
||||||
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
|
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
|
||||||
@ -486,7 +498,7 @@ $loopLabel sty $indexVar
|
|||||||
if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) {
|
if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) {
|
||||||
if(range.last==range.first) return translateForSimpleByteRangeAsc(stmt, range)
|
if(range.last==range.first) return translateForSimpleByteRangeAsc(stmt, range)
|
||||||
if(range.step==1 && range.last>range.first) return translateForSimpleByteRangeAsc(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(range.step==-1 && range.last<range.first) return translateForSimpleByteRangeDesc(stmt, range, iterableDt==DataType.ARRAY_UB)
|
||||||
}
|
}
|
||||||
else if(iterableDt==DataType.ARRAY_W || iterableDt==DataType.ARRAY_UW) {
|
else if(iterableDt==DataType.ARRAY_W || iterableDt==DataType.ARRAY_UW) {
|
||||||
if(range.last==range.first) return translateForSimpleWordRangeAsc(stmt, range)
|
if(range.last==range.first) return translateForSimpleWordRangeAsc(stmt, range)
|
||||||
@ -632,10 +644,8 @@ $endLabel""")
|
|||||||
asmgen.loopEndLabels.removeLast()
|
asmgen.loopEndLabels.removeLast()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateForSimpleByteRangeDesc(stmt: PtForLoop, range: IntProgression) {
|
private fun translateForSimpleByteRangeDesc(stmt: PtForLoop, range: IntProgression, unsigned: Boolean) {
|
||||||
val loopLabel = asmgen.makeLabel("for_loop")
|
val loopLabel = asmgen.makeLabel("for_loop")
|
||||||
val endLabel = asmgen.makeLabel("for_end")
|
|
||||||
asmgen.loopEndLabels.add(endLabel)
|
|
||||||
val varname = asmgen.asmVariableName(stmt.variable)
|
val varname = asmgen.asmVariableName(stmt.variable)
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda #${range.first}
|
lda #${range.first}
|
||||||
@ -644,29 +654,31 @@ $loopLabel""")
|
|||||||
asmgen.translate(stmt.statements)
|
asmgen.translate(stmt.statements)
|
||||||
when (range.last) {
|
when (range.last) {
|
||||||
0 -> {
|
0 -> {
|
||||||
|
if(!unsigned || range.first<=127) {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
|
dec $varname
|
||||||
|
bpl $loopLabel""")
|
||||||
|
} else {
|
||||||
|
asmgen.out("""
|
||||||
|
dec $varname
|
||||||
lda $varname
|
lda $varname
|
||||||
beq $endLabel
|
cmp #255
|
||||||
dec $varname""")
|
bne $loopLabel""")
|
||||||
asmgen.jmp(loopLabel)
|
}
|
||||||
asmgen.out(endLabel)
|
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
dec $varname
|
dec $varname
|
||||||
bne $loopLabel
|
bne $loopLabel""")
|
||||||
$endLabel""")
|
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
dec $varname
|
dec $varname
|
||||||
lda $varname
|
lda $varname
|
||||||
cmp #${range.last-1}
|
cmp #${range.last-1}
|
||||||
bne $loopLabel
|
bne $loopLabel""")
|
||||||
$endLabel""")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
asmgen.loopEndLabels.removeLast()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateForSimpleWordRangeAsc(stmt: PtForLoop, range: IntProgression) {
|
private fun translateForSimpleWordRangeAsc(stmt: PtForLoop, range: IntProgression) {
|
||||||
@ -708,13 +720,22 @@ $loopLabel""")
|
|||||||
sty $varname+1
|
sty $varname+1
|
||||||
$loopLabel""")
|
$loopLabel""")
|
||||||
asmgen.translate(stmt.statements)
|
asmgen.translate(stmt.statements)
|
||||||
|
if(range.last==0) {
|
||||||
|
asmgen.out("""
|
||||||
|
lda $varname
|
||||||
|
bne ++
|
||||||
|
lda $varname+1
|
||||||
|
beq $endLabel""")
|
||||||
|
} else {
|
||||||
asmgen.out("""
|
asmgen.out("""
|
||||||
lda $varname
|
lda $varname
|
||||||
cmp #<${range.last}
|
cmp #<${range.last}
|
||||||
bne +
|
bne +
|
||||||
lda $varname+1
|
lda $varname+1
|
||||||
cmp #>${range.last}
|
cmp #>${range.last}
|
||||||
beq $endLabel
|
beq $endLabel""")
|
||||||
|
}
|
||||||
|
asmgen.out("""
|
||||||
+ lda $varname
|
+ lda $varname
|
||||||
bne +
|
bne +
|
||||||
dec $varname+1
|
dec $varname+1
|
||||||
|
@ -518,6 +518,12 @@ 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 *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.
|
||||||
|
|
||||||
|
.. sidebar::
|
||||||
|
Optimization
|
||||||
|
|
||||||
|
Usually a loop in descending order downto 0 or 1, produces more efficient assembly code than the same loop in ascending order.
|
||||||
|
|
||||||
The loop variable must be declared separately as byte or word earlier, so that you can reuse it for multiple occasions.
|
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.
|
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.
|
If the from value is already outside of the loop range, the whole for loop is skipped.
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
|
improve codegen for for loops downto 0,1 when start value is not const.
|
||||||
|
|
||||||
|
|
||||||
|
IR: Improve codegen for for loops downto 0. (BPL if <=127 etc like 6502 codegen?)
|
||||||
|
|
||||||
|
|
||||||
Improve register load order in subroutine call args assignments:
|
Improve register load order in subroutine call args assignments:
|
||||||
in certain situations, the "wrong" order of evaluation of function call arguments is done which results
|
in certain situations, the "wrong" order of evaluation of function call arguments is done which results
|
||||||
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)
|
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)
|
||||||
|
159
examples/test.p8
159
examples/test.p8
@ -5,139 +5,46 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte @shared x
|
ubyte x
|
||||||
uword @shared w
|
uword w
|
||||||
bool flag1, flag2
|
uword @shared wstart=50000
|
||||||
|
ubyte @shared bstart=127
|
||||||
|
uword y
|
||||||
|
uword duration
|
||||||
|
byte b
|
||||||
|
|
||||||
sys.clear_carry()
|
|
||||||
flag1 = onlyCarry()
|
|
||||||
if flag1
|
|
||||||
txt.print("1: ok\n")
|
|
||||||
else
|
|
||||||
txt.print("1: fail\n")
|
|
||||||
|
|
||||||
x=1
|
cbm.SETTIM(0,0,0)
|
||||||
flag1 = onlyZero()
|
repeat 5000 {
|
||||||
if flag1
|
y=0
|
||||||
txt.print("2: ok\n")
|
; for x in bstart downto 0 {
|
||||||
else
|
; y++
|
||||||
txt.print("2: fail\n")
|
; }
|
||||||
|
x = bstart
|
||||||
sys.clear_carry()
|
do {
|
||||||
flag1, x = carryAndByte()
|
y++
|
||||||
if flag1 and x==42
|
x--
|
||||||
txt.print("3: ok\n")
|
} until x==255
|
||||||
else
|
|
||||||
txt.print("3: fail\n")
|
|
||||||
|
|
||||||
sys.clear_carry()
|
|
||||||
flag1, w = carryAndWord()
|
|
||||||
if flag1 and w==4242
|
|
||||||
txt.print("4: ok\n")
|
|
||||||
else
|
|
||||||
txt.print("4: fail\n")
|
|
||||||
|
|
||||||
sys.clear_carry()
|
|
||||||
flag1, x, w = carryAndValues()
|
|
||||||
if flag1 and x==99 and w==9999
|
|
||||||
txt.print("5: ok\n")
|
|
||||||
else
|
|
||||||
txt.print("5: fail\n")
|
|
||||||
|
|
||||||
x = 1
|
|
||||||
sys.clear_carry()
|
|
||||||
flag1, flag2 = onlyCarryAndZero()
|
|
||||||
if flag1 and flag2
|
|
||||||
txt.print("6: ok\n")
|
|
||||||
else
|
|
||||||
txt.print("6: fail\n")
|
|
||||||
|
|
||||||
x = 1
|
|
||||||
sys.clear_carry()
|
|
||||||
flag1, flag2, x = carryAndZeroAndByte()
|
|
||||||
if flag1 and flag2 and x==33
|
|
||||||
txt.print("7: ok\n")
|
|
||||||
else
|
|
||||||
txt.print("7: fail\n")
|
|
||||||
|
|
||||||
x = 1
|
|
||||||
sys.clear_carry()
|
|
||||||
flag1, flag2, x, w = carryAndNegativeAndByteAndWord()
|
|
||||||
if flag1 and flag2 and x==55 and w==51400
|
|
||||||
txt.print("8: ok\n")
|
|
||||||
else
|
|
||||||
txt.print("8: fail\n")
|
|
||||||
}
|
}
|
||||||
|
txt.print_uw(cbm.RDTIM16())
|
||||||
|
if y!=128
|
||||||
|
txt.print("error 1\n")
|
||||||
|
|
||||||
|
/*
|
||||||
asmsub carryAndNegativeAndByteAndWord() -> bool @Pc, bool @Pn, ubyte @X, uword @AY {
|
for w in 65535 downto 0 {
|
||||||
%asm {{
|
y++
|
||||||
ldx #55
|
|
||||||
lda #200
|
|
||||||
ldy #200
|
|
||||||
sec
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
|
if y!=0
|
||||||
|
txt.print("error 10\n")
|
||||||
|
|
||||||
asmsub carryAndZeroAndByte() -> bool @Pc, bool @Pz, ubyte @Y {
|
y=0
|
||||||
%asm {{
|
for w in 0 to 65535 {
|
||||||
ldy #33
|
y++
|
||||||
lda #0
|
|
||||||
sec
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
|
if y!=0
|
||||||
|
txt.print("error 11\n")
|
||||||
|
*/
|
||||||
|
|
||||||
|
txt.print("\nall done\n")
|
||||||
asmsub onlyCarryAndZero() -> bool @Pc, bool @Pz {
|
|
||||||
%asm {{
|
|
||||||
lda #0
|
|
||||||
sec
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
asmsub carryAndValues() -> bool @Pc, ubyte @X, uword @AY {
|
|
||||||
%asm {{
|
|
||||||
ldx #99
|
|
||||||
lda #<9999
|
|
||||||
ldy #>9999
|
|
||||||
sec
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
asmsub carryAndWord() -> bool @Pc, uword @AY {
|
|
||||||
%asm {{
|
|
||||||
lda #<4242
|
|
||||||
ldy #>4242
|
|
||||||
sec
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub carryAndByte() -> bool @Pc, ubyte @A {
|
|
||||||
%asm {{
|
|
||||||
lda #42
|
|
||||||
sec
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub onlyCarry() -> bool @Pc {
|
|
||||||
%asm {{
|
|
||||||
sec
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub onlyZero() -> bool @Pz {
|
|
||||||
%asm {{
|
|
||||||
lda #0
|
|
||||||
rts
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user