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,29 +48,42 @@ internal class ForLoopsAsmGen(
when(iterableDt) {
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
val incdec = if(stepsize==1) "inc" else "dec"
// 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)
// pre-check for end already reached
if(iterableDt==DataType.ARRAY_B) {
asmgen.out(" sta $modifiedLabel+1")
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("""
clc
sbc $varname
bvc +
eor #${'$'}80
+ bpl $endLabel""")
}
asmgen.out("""
clc
sbc $varname
bvc +
eor #${'$'}80
+ bpl $endLabel""")
}
else
asmgen.out("""
@ -81,15 +94,11 @@ internal class ForLoopsAsmGen(
+ bmi $endLabel""")
} else {
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("""
cmp $varname
beq +
bcs $endLabel
asmgen.out("""
cmp $varname
beq +
bcs $endLabel
+""")
}
}
else
asmgen.out(" cmp $varname | bcc $endLabel")
@ -110,8 +119,6 @@ $modifiedLabel cmp #0 ; modified
// bytes, step >= 2 or <= -2
// 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)
// pre-check for end already reached
if(iterableDt==DataType.ARRAY_B) {
@ -165,60 +172,85 @@ $modifiedLabel cmp #0 ; modified
}
}
DataType.ARRAY_W, DataType.ARRAY_UW -> {
when {
val varname = asmgen.asmVariableName(stmt.variable)
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
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)
assignLoopvarWord(stmt, range)
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
precheckFromToWord(iterableDt, stepsize, varname, endLabel)
asmgen.out("""
sty $modifiedLabel+1
sta $modifiedLabel2+1
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
precheckFromToWord(iterableDt, stepsize, varname, endLabel)
asmgen.out("""
sty $modifiedLabel+1
sta $modifiedLabel2+1
$loopLabel""")
asmgen.translate(stmt.statements)
asmgen.out("""
asmgen.translate(stmt.statements)
asmgen.out("""
lda $varname+1
$modifiedLabel cmp #0 ; modified
bne +
lda $varname
$modifiedLabel2 cmp #0 ; modified
beq $endLabel""")
if(stepsize==1) {
asmgen.out("""
if(stepsize==1) {
asmgen.out("""
+ inc $varname
bne $loopLabel
inc $varname+1""")
asmgen.jmp(loopLabel)
} else {
asmgen.out("""
asmgen.jmp(loopLabel)
} else {
asmgen.out("""
+ lda $varname
bne +
dec $varname+1
+ dec $varname""")
asmgen.jmp(loopLabel)
}
asmgen.out(endLabel)
asmgen.jmp(loopLabel)
}
stepsize > 0 -> {
// (u)words, step >= 2
val varname = asmgen.asmVariableName(stmt.variable)
assignLoopvarWord(stmt, range)
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
precheckFromToWord(iterableDt, stepsize, varname, endLabel)
asmgen.out("""
sty $modifiedLabel+1
sta $modifiedLabel2+1
asmgen.out(endLabel)
}
else if (stepsize > 0) {
// (u)words, step >= 2
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
precheckFromToWord(iterableDt, stepsize, varname, endLabel)
asmgen.out("""
sty $modifiedLabel+1
sta $modifiedLabel2+1
$loopLabel""")
asmgen.translate(stmt.statements)
asmgen.translate(stmt.statements)
if (iterableDt == DataType.ARRAY_UW) {
asmgen.out("""
if (iterableDt == DataType.ARRAY_UW) {
asmgen.out("""
lda $varname
clc
adc #<$stepsize
@ -234,8 +266,8 @@ $modifiedLabel2 lda #0 ; modified
bcc $endLabel
bcs $loopLabel
$endLabel""")
} else {
asmgen.out("""
} else {
asmgen.out("""
lda $varname
clc
adc #<$stepsize
@ -251,22 +283,20 @@ $modifiedLabel lda #0 ; modified
eor #$80
+ bpl $loopLabel
$endLabel""")
}
}
else -> {
}
else {
// (u)words, step <= -2
val varname = asmgen.asmVariableName(stmt.variable)
assignLoopvarWord(stmt, range)
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
precheckFromToWord(iterableDt, stepsize, varname, endLabel)
asmgen.out("""
sty $modifiedLabel+1
sta $modifiedLabel2+1
// (u)words, step <= -2
asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
precheckFromToWord(iterableDt, stepsize, varname, endLabel)
asmgen.out("""
sty $modifiedLabel+1
sta $modifiedLabel2+1
$loopLabel""")
asmgen.translate(stmt.statements)
asmgen.translate(stmt.statements)
asmgen.out("""
asmgen.out("""
lda $varname
sec
sbc #<${stepsize.absoluteValue}
@ -283,7 +313,6 @@ $modifiedLabel sbc #0 ; modified
eor #$80
+ bpl $loopLabel
$endLabel""")
}
}
}
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
}

View File

@ -1,7 +1,11 @@
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?)

View File

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