getting rid of problematic fallback (infinite recursion)

This commit is contained in:
Irmen de Jong 2024-03-02 18:46:34 +01:00
parent f29d24e96a
commit fe8b6e820c
3 changed files with 376 additions and 67 deletions

View File

@ -82,16 +82,6 @@ internal class IfElseAsmGen(private val program: PtProgram,
}
}
private fun fallbackTranslate(stmt: PtIfElse) {
errors.warn("SLOW FALLBACK FOR 'IF' CODEGEN - ask for support", stmt.position) // TODO should have no more of these
assignConditionValueToRegisterAndTest(stmt.condition)
val jumpAfterIf = stmt.ifScope.children.singleOrNull() as? PtJump
if(jumpAfterIf!=null)
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
else
translateIfElseBodies("beq", stmt)
}
private fun fallbackTranslateForSimpleCondition(ifElse: PtIfElse) {
// the condition is "simple" enough to just assign its 0/1 value to a register and branch on that
assignConditionValueToRegisterAndTest(ifElse.condition)
@ -102,7 +92,6 @@ internal class IfElseAsmGen(private val program: PtProgram,
translateIfElseBodies("beq", ifElse)
}
private fun translateIfElseBodies(elseBranchInstr: String, stmt: PtIfElse) {
// comparison value is already in A
val afterIfLabel = asmgen.makeLabel("afterif")
@ -204,8 +193,14 @@ internal class IfElseAsmGen(private val program: PtProgram,
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
else
translateIfElseBodies("beq", stmt)
} else
fallbackTranslate(stmt)
} else {
errors.warn("SLOW FALLBACK FOR 'IF' CODEGEN - ask for support", stmt.position) // TODO should have no more of these at all
assignConditionValueToRegisterAndTest(stmt.condition)
if(jumpAfterIf!=null)
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
else
translateIfElseBodies("beq", stmt)
}
}
else -> throw AssemblyError("expected comparison or logical operator")
}
@ -410,7 +405,6 @@ internal class IfElseAsmGen(private val program: PtProgram,
private fun translateByteGreater(stmt: PtIfElse, signed: Boolean, jumpAfterIf: PtJump?) {
val condition = stmt.condition as PtBinaryExpression
if(signed) {
// TODO if compared to a number, a more optimized routine is possible (X>=Y+1)
// X>Y --> Y<X
asmgen.assignExpressionToRegister(condition.right, RegisterOrPair.A, signed)
cmpAwithByteValue(condition.left, true)
@ -1098,10 +1092,9 @@ _jump jmp ($asmLabel)
jump: PtJump?,
stmt: PtIfElse
) {
// special case for (u)word == X and (u)word != X
fun translateNotEquals(valueLsb: String, valueMsb: String) {
fun translateAYNotEquals(valueLsb: String, valueMsb: String) {
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
@ -1149,8 +1142,8 @@ _jump jmp ($asmLabel)
}
}
fun translateEquals(valueLsb: String, valueMsb: String) {
return if(jump!=null) {
fun translateAYEquals(valueLsb: String, valueMsb: String) {
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
@ -1196,71 +1189,356 @@ _jump jmp ($asmLabel)
}
}
fun translateEqualsVarVar(left: PtIdentifier, right: PtIdentifier) {
if(notEquals) {
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
lda ${left.name}
cmp ${right.name}
bne +
lda ${left.name}+1
cmp ${right.name}+1
beq ++
+ jmp ($asmLabel)
+""")
} else {
asmgen.out("""
lda ${left.name}
cmp ${right.name}
bne $asmLabel
lda ${left.name}+1
cmp ${right.name}+1
bne $asmLabel""")
}
asmgen.translate(stmt.elseScope)
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
lda ${left.name}
cmp ${right.name}
bne +
lda ${left.name}+1
cmp ${right.name}+1
beq $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
lda ${left.name}
cmp ${right.name}
bne +
lda ${left.name}+1
cmp ${right.name}+1
beq $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
} else {
// XXX translateAYEquals(right.name, right.name + "+1")
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
lda ${left.name}
cmp ${right.name}
bne +
lda ${left.name}+1
cmp ${right.name}+1
bne +
jmp ($asmLabel)
+""")
} else {
asmgen.out("""
lda ${left.name}
cmp ${right.name}
bne +
lda ${left.name}+1
cmp ${right.name}+1
beq $asmLabel
+""")
}
asmgen.translate(stmt.elseScope)
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
lda ${left.name}
cmp ${right.name}
bne $elseLabel
lda ${left.name}+1
cmp ${right.name}+1
bne $elseLabel""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
lda ${left.name}
cmp ${right.name}
bne $afterIfLabel
lda ${left.name}
cmp ${right.name}+1
bne $afterIfLabel""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
}
}
fun translateEqualsVarNum(left: PtIdentifier, right: PtNumber) {
val value = right.number.toInt()
if(notEquals) {
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
lda ${left.name}
cmp #<$value
bne +
lda ${left.name}+1
cmp #>$value
beq ++
+ jmp ($asmLabel)
+""")
} else {
asmgen.out("""
lda ${left.name}
cmp #<$value
bne $asmLabel
lda ${left.name}+1
cmp #>$value
bne $asmLabel""")
}
asmgen.translate(stmt.elseScope)
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
lda ${left.name}
cmp #<$value
bne +
lda ${left.name}+1
cmp #>$value
beq $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
lda ${left.name}
cmp #<$value
bne +
lda ${left.name}+1
cmp #>$value
beq $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
} else {
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
lda ${left.name}
cmp #<$value
bne +
lda ${left.name}+1
cmp #>$value
bne +
jmp ($asmLabel)
+""")
} else {
asmgen.out("""
lda ${left.name}
cmp #<$value
bne +
lda ${left.name}+1
cmp #>$value
beq $asmLabel
+""")
}
asmgen.translate(stmt.elseScope)
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
lda ${left.name}
cmp #<$value
bne $elseLabel
lda ${left.name}+1
cmp #>$value
bne $elseLabel""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
lda ${left.name}
cmp #<$value
bne $afterIfLabel
lda ${left.name}+1
cmp #>$value
bne $afterIfLabel""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
}
}
fun translateEqualsArray(left: PtArrayIndexer, right: PtExpression) {
val constIndex = left.index.asConstInteger()
if(constIndex!=null) {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varName = asmgen.asmVariableName(left.variable)
if(left.splitWords) {
return if(notEquals)
translateAYNotEquals("${varName}_lsb+$constIndex", "${varName}_msb+$constIndex")
else
translateAYEquals("${varName}_lsb+$constIndex", "${varName}_msb+$constIndex")
}
val offset = constIndex * program.memsizer.memorySize(left.type)
if(offset<256) {
return if(notEquals)
translateAYNotEquals("$varName+$offset", "$varName+$offset+1")
else
translateAYEquals("$varName+$offset", "$varName+$offset+1")
}
}
else {
when(right) {
is PtNumber -> {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
val value = right.number.toInt()
if(notEquals)
translateAYNotEquals("#<$value", "#>$value")
else
translateAYEquals("#<$value", "#>$value")
}
is PtIdentifier -> {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
if(notEquals)
translateAYNotEquals(right.name,right.name + "+1")
else
translateAYEquals(right.name, right.name + "+1")
}
else -> {
TODO("non-fallback code for array ${left.index} ${left.position}")
}
}
}
}
if(notEquals) {
when(left) {
is PtArrayIndexer -> {
val constIndex = left.index.asConstInteger()
if(constIndex!=null) {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varName = asmgen.asmVariableName(left.variable)
if(left.splitWords) {
return translateNotEquals("${varName}_lsb+$constIndex", "${varName}_msb+$constIndex")
}
val offset = constIndex * program.memsizer.memorySize(left.type)
if(offset<256) {
return translateNotEquals("$varName+$offset", "$varName+$offset+1")
}
}
fallbackTranslate(stmt)
translateEqualsArray(left, right)
}
is PtIdentifier -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varname = asmgen.asmVariableName(left)
return translateNotEquals(varname, varname+"+1")
when(right) {
is PtNumber -> translateEqualsVarNum(left, right)
is PtIdentifier -> translateEqualsVarVar(left, right)
else -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varname = asmgen.asmVariableName(left)
translateAYNotEquals(varname, varname + "+1")
}
}
}
is PtAddressOf -> {
if(left.isFromArrayElement)
fallbackTranslateForSimpleCondition(stmt)
else {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varname = asmgen.asmVariableName(left.identifier)
return translateNotEquals("#<$varname", "#>$varname")
val varname = left.identifier.name
translateAYNotEquals("#<$varname", "#>$varname")
}
}
else -> {
when(right) {
is PtNumber -> {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
val value = right.number.toInt()
translateAYNotEquals("#<$value", "#>$value")
}
is PtIdentifier -> {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
translateAYNotEquals(right.name, right.name + "+1")
}
else -> {
TODO("non-fallback code for ${left} ${left.position}")
}
}
}
else -> fallbackTranslate(stmt)
}
} else {
when(left) {
is PtArrayIndexer -> {
val constIndex = left.index.asConstInteger()
if(constIndex!=null) {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varName = asmgen.asmVariableName(left.variable)
if(left.splitWords) {
return translateEquals("${varName}_lsb+$constIndex", "${varName}_msb+$constIndex")
}
val offset = constIndex * program.memsizer.memorySize(left.type)
if(offset<256) {
return translateEquals("$varName+$offset", "$varName+$offset+1")
}
}
fallbackTranslate(stmt)
translateEqualsArray(left, right)
}
is PtIdentifier -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varname = asmgen.asmVariableName(left)
return translateEquals(varname, varname+"+1")
when(right) {
is PtNumber -> translateEqualsVarNum(left, right)
is PtIdentifier -> translateEqualsVarVar(left, right)
else -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varname = asmgen.asmVariableName(left)
translateAYEquals(varname, varname+"+1")
}
}
}
is PtAddressOf -> {
if(left.isFromArrayElement)
fallbackTranslateForSimpleCondition(stmt)
else {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val varname = asmgen.asmVariableName(left.identifier)
return translateEquals("#<$varname", "#>$varname")
val varname = left.identifier.name
translateAYEquals("#<$varname", "#>$varname")
}
}
else -> {
when(right) {
is PtNumber -> {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
val value = right.number.toInt()
translateAYEquals("#<$value", "#>$value")
}
is PtIdentifier -> {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
translateAYEquals(right.name, right.name + "+1")
}
else -> {
TODO("non-fallback code for ${left} ${left.position}")
}
}
}
else -> fallbackTranslate(stmt)
}
}
}

View File

@ -1,17 +1,23 @@
TODO
====
optimize assignOptimizedComparisonWords for when comparing to simple things like number and identifier.
optimize optimizedPlusMinExpr for when comparing to simple things like number and identifier.
optimize the IfElseAsmgen's fallbackTranslate even more (for arrays without const index for example?)
After merging master:
optimize byte < and byte >= assignment to use the rol trick instead of branching:
bool @shared bb = cx16.r0L >= 128
bool @shared bb2 = cx16.r0L < 99
snow example is a lot larger!
; source: examples/test.p8:10 bool @shared bb = cx16.r0L >= 128
lda cx16.r0L
cmp #128
rol a
and #1
sta p8v_bb
; source: examples/test.p8:11 bool @shared bb2 = cx16.r0L < 99
lda cx16.r0L
cmp #99
rol a
and #1
eor #1
sta p8v_bb2
===== ====== =======

View File

@ -7,10 +7,35 @@
main {
sub start() {
ubyte[] envelope_attacks = [1,2,3,4]
uword[] flakes = [1,2,3,4]
if msb(cx16.r0) > cx16.r2L or envelope_attacks[cx16.r1L]==0 {
txt.print("yep")
if cx16.r0==5555
cx16.r0L++
if cx16.r0!=5555
cx16.r0L++
if max(cx16.r0, cx16.r1)==9999
cx16.r0L++
if max(cx16.r0, cx16.r1)!=9999
cx16.r0L++
if derp()==1000
cx16.r0L++
if derp()!=1000
cx16.r0L++
cx16.r0=2
if flakes[cx16.r0L]==239
cx16.r0L++
if flakes[cx16.r0L]!=239
cx16.r0L++
sub derp() -> uword {
cx16.r0++
return cx16.r0
}
;