improve codegen for for loops downto 0,1 when start value is not const

This commit is contained in:
Irmen de Jong 2024-09-10 23:54:44 +02:00
parent 699a2bb7ab
commit 8eaf884f69
4 changed files with 122 additions and 117 deletions

View File

@ -48,22 +48,36 @@ internal class ForLoopsAsmGen(
when(iterableDt) { when(iterableDt) {
DataType.ARRAY_B, DataType.ARRAY_UB -> { DataType.ARRAY_B, DataType.ARRAY_UB -> {
if (stepsize==1 || stepsize==-1) { val varname = asmgen.asmVariableName(stmt.variable)
asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt))
if (stepsize==-1 && range.to.asConstInteger()==0) {
// simple loop downto 0 step -1
asmgen.out(loopLabel)
asmgen.translate(stmt.statements)
asmgen.out("""
dec $varname
lda $varname
cmp #255
bne $loopLabel""")
}
else if (stepsize==-1 && range.to.asConstInteger()==1) {
// simple loop downto 1 step -1
asmgen.out(loopLabel)
asmgen.translate(stmt.statements)
asmgen.out("""
dec $varname
bne $loopLabel""")
}
else if (stepsize==1 || stepsize==-1) {
// bytes array, step 1 or -1 // bytes array, step 1 or -1
val incdec = if(stepsize==1) "inc" else "dec" val incdec = if(stepsize==1) "inc" else "dec"
// loop over byte range via loopvar // loop over byte range via loopvar
val varname = asmgen.asmVariableName(stmt.variable)
asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt))
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false) asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false)
// 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
@ -71,7 +85,6 @@ internal class ForLoopsAsmGen(
eor #${'$'}80 eor #${'$'}80
+ bpl $endLabel""") + bpl $endLabel""")
} }
}
else else
asmgen.out(""" asmgen.out("""
sec sec
@ -81,16 +94,12 @@ internal class ForLoopsAsmGen(
+ 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")
@ -110,8 +119,6 @@ $modifiedLabel cmp #0 ; modified
// bytes, step >= 2 or <= -2 // bytes, step >= 2 or <= -2
// loop over byte range via loopvar // loop over byte range via loopvar
val varname = asmgen.asmVariableName(stmt.variable)
asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt))
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false) asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false)
// pre-check for end already reached // pre-check for end already reached
if(iterableDt==DataType.ARRAY_B) { if(iterableDt==DataType.ARRAY_B) {
@ -165,15 +172,43 @@ $modifiedLabel cmp #0 ; modified
} }
} }
DataType.ARRAY_W, DataType.ARRAY_UW -> { DataType.ARRAY_W, DataType.ARRAY_UW -> {
when {
// words, step 1 or -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)
if(stepsize==-1 && range.to.asConstInteger()==0) {
// simple loop downto 0 step -1 (words)
asmgen.out(loopLabel)
asmgen.translate(stmt.statements)
asmgen.out("""
lda $varname
bne ++
lda $varname+1
beq $endLabel
+ lda $varname
bne +
dec $varname+1
+ dec $varname""")
asmgen.jmp(loopLabel)
asmgen.out(endLabel)
}
else if (stepsize==-1 && range.to.asConstInteger()==1) {
// simple loop downto 1 step -1 (words)
asmgen.out(loopLabel)
asmgen.translate(stmt.statements)
asmgen.out("""
lda $varname
cmp #1
bne +
lda $varname+1
beq $endLabel
+ lda $varname
bne +
dec $varname+1
+ dec $varname""")
asmgen.jmp(loopLabel)
asmgen.out(endLabel)
}
else if (stepsize == 1 || stepsize == -1) {
// words, step 1 or -1
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY) asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
precheckFromToWord(iterableDt, stepsize, varname, endLabel) precheckFromToWord(iterableDt, stepsize, varname, endLabel)
asmgen.out(""" asmgen.out("""
@ -204,11 +239,8 @@ $modifiedLabel2 cmp #0 ; modified
} }
asmgen.out(endLabel) asmgen.out(endLabel)
} }
stepsize > 0 -> { else if (stepsize > 0) {
// (u)words, step >= 2 // (u)words, step >= 2
val varname = asmgen.asmVariableName(stmt.variable)
assignLoopvarWord(stmt, range)
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY) asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
precheckFromToWord(iterableDt, stepsize, varname, endLabel) precheckFromToWord(iterableDt, stepsize, varname, endLabel)
asmgen.out(""" asmgen.out("""
@ -253,11 +285,9 @@ $modifiedLabel lda #0 ; modified
$endLabel""") $endLabel""")
} }
} }
else -> { else {
// (u)words, step <= -2 // (u)words, step <= -2
val varname = asmgen.asmVariableName(stmt.variable)
assignLoopvarWord(stmt, range)
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY) asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
precheckFromToWord(iterableDt, stepsize, varname, endLabel) precheckFromToWord(iterableDt, stepsize, varname, endLabel)
asmgen.out(""" asmgen.out("""
@ -285,7 +315,6 @@ $modifiedLabel sbc #0 ; modified
$endLabel""") $endLabel""")
} }
} }
}
else -> throw AssemblyError("range expression can only be byte or word") else -> throw AssemblyError("range expression can only be byte or word")
} }

View File

@ -200,35 +200,6 @@ class StatementOptimizer(private val program: Program,
} }
} }
val loopvarDt = forLoop.loopVarDt(program)
if(loopvarDt.istype(DataType.UWORD) || loopvarDt.istype(DataType.UBYTE)) {
fun incOrDec(inc: Boolean): Assignment {
val pos = forLoop.position
val loopVar = forLoop.loopVar
val addSubOne = BinaryExpression(loopVar.copy(), if(inc) "+" else "-", NumericLiteral.optimalInteger(1, pos), pos, false)
return Assignment(AssignTarget(loopVar.copy(), null, null, null, false, pos), addSubOne, AssignmentOrigin.USERCODE, pos)
}
if (range != null && range.to.constValue(program)?.number == 0.0 && range.step.constValue(program)?.number==-1.0) {
val fromExpr = range.from
if(fromExpr.constValue(program)==null) {
// FOR X = something DOWNTO 0 {...} --> X=something, DO { ... , X-- } UNTIL X=255 (or 65535 if uword)
val pos = forLoop.position
val checkValue = NumericLiteral(loopvarDt.getOr(DataType.UNDEFINED), if(loopvarDt.istype(DataType.UBYTE)) 255.0 else 65535.0, pos)
val condition = BinaryExpression(forLoop.loopVar.copy(), "==", checkValue, pos)
val decOne = incOrDec(false)
forLoop.body.statements.add(decOne)
val replacement = AnonymousScope(mutableListOf(
Assignment(AssignTarget(forLoop.loopVar.copy(), null, null, null, false, pos),
fromExpr, AssignmentOrigin.OPTIMIZER, pos),
UntilLoop(forLoop.body, condition, pos)
), pos)
return listOf(IAstModification.ReplaceNode(forLoop, replacement, parent))
}
}
}
return noModifications return noModifications
} }

View File

@ -1,7 +1,11 @@
TODO TODO
==== ====
improve codegen for for loops downto 0,1 when start value is not const. Badapple has become 200 bytes LARGER than before!!
Fix testgfx2 screen text being uppercase (should be upper+lowercased)
assembler seems to crash on hello4...
IR: Improve codegen for for loops downto 0. (BPL if <=127 etc like 6502 codegen?) IR: Improve codegen for for loops downto 0. (BPL if <=127 etc like 6502 codegen?)

View File

@ -7,28 +7,29 @@ main {
sub start() { sub start() {
ubyte x ubyte x
uword w uword w
uword @shared wstart=50000 uword @shared wstart=1000
ubyte @shared bstart=127 ubyte @shared bstart=100
uword y uword y
uword duration uword duration
byte b byte b
cbm.SETTIM(0,0,0) cbm.SETTIM(0,0,0)
repeat 5000 { repeat 1000 {
y=0 y=0
; for x in bstart downto 0 { for w in wstart downto 0 {
; y++
; }
x = bstart
do {
y++ y++
x-- }
} until x==255 for w in wstart downto 1 {
y++
}
; TODO words
} }
txt.print_uw(cbm.RDTIM16()) txt.print_uw(cbm.RDTIM16())
if y!=128 if y!=2001
txt.print("error 1\n") txt.print("error\n")
; without new loops: $26e, 482 jiffies
/* /*
for w in 65535 downto 0 { for w in 65535 downto 0 {