From fe8b6e820c9790b830489c3da634534057b04e51 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 2 Mar 2024 18:46:34 +0100 Subject: [PATCH] getting rid of problematic fallback (infinite recursion) --- .../src/prog8/codegen/cpu6502/IfElseAsmGen.kt | 390 +++++++++++++++--- docs/source/todo.rst | 22 +- examples/test.p8 | 31 +- 3 files changed, 376 insertions(+), 67 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt index 57c340b9e..db586ee9c 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt @@ -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$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) } } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 66d27e3a4..39e3bff14 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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 ===== ====== ======= diff --git a/examples/test.p8 b/examples/test.p8 index e6c3e80ae..96efdcdb0 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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 } ;