From e7178ee496433ef2ba21503346b1a5062c3792dd Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 5 Nov 2023 00:20:12 +0100 Subject: [PATCH] optimized comparison with word variables --- .../cpu6502/assignment/AnyExprAsmGen.kt | 4 +- .../cpu6502/assignment/AssignmentAsmGen.kt | 205 +++++++++++++++--- docs/source/todo.rst | 2 - examples/test.p8 | 38 ++-- 4 files changed, 190 insertions(+), 59 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt index 406d894c2..c45a0dbc5 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt @@ -23,13 +23,13 @@ internal class AnyExprAsmGen( return assignByteBinExpr(expr, assign) if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { require(expr.operator in ComparisonOperators) - TODO("words operands comparison -> byte") + throw AssemblyError("words operands comparison -> byte, should have been handled by assignOptimizedComparisonWords()") } if (expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) { require(expr.operator in ComparisonOperators) return assignFloatBinExpr(expr, assign) } - TODO("weird expr operand types") + throw AssemblyError("weird expr operand types: ${expr.left.type} and {${expr.right.type}") } in WordDatatypes -> { require(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 7d2416a2c..bea50807e 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -1414,10 +1414,24 @@ internal class AssignmentAsmGen(private val program: PtProgram, private fun assignOptimizedComparisonWords(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { val signed = expr.left.type == DataType.WORD || expr.right.type == DataType.WORD + when(expr.operator) { "==" -> { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(""" + if(expr.left is PtIdentifier) { + val varName = asmgen.asmVariableName(expr.left as PtIdentifier) + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.AY) + asmgen.out(""" + cmp $varName + bne + + cpy $varName+1 + bne + + lda #1 + bne ++ ++ lda #0 ++""") + } else { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(""" cmp P8ZP_SCRATCH_W1 bne + cpy P8ZP_SCRATCH_W1+1 @@ -1426,10 +1440,24 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") + } } "!=" -> { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(""" + if(expr.left is PtIdentifier) { + val varName = asmgen.asmVariableName(expr.left as PtIdentifier) + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.AY) + asmgen.out(""" + cmp $varName + bne + + cpy $varName+1 + bne + + lda #0 + beq ++ ++ lda #1 ++""") + } else { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(""" cmp P8ZP_SCRATCH_W1 bne + cpy P8ZP_SCRATCH_W1+1 @@ -1438,11 +1466,39 @@ internal class AssignmentAsmGen(private val program: PtProgram, beq ++ + lda #1 +""") + } } "<" -> { - if(signed) { - asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") - asmgen.out(""" + if(expr.right is PtIdentifier) { + val varName = asmgen.asmVariableName(expr.right as PtIdentifier) + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.AY) + if(signed) + asmgen.out(""" + cmp $varName + tya + sbc $varName+1 + bvc + + eor #${'$'}80 ++ bpl ++ ++ lda #1 + bne ++ ++ lda #0 ++""") + else + asmgen.out(""" + cpy $varName+1 + bcc + + bne ++ + cmp $varName + bcs ++ ++ lda #1 + bne ++ ++ lda #0 ++""") + } else { + if(signed) { + asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") + asmgen.out(""" cmp P8ZP_SCRATCH_W1 tya sbc P8ZP_SCRATCH_W1+1 @@ -1453,10 +1509,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") - } - else { - asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") - asmgen.out(""" + } + else { + asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") + asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 bcc + bne ++ @@ -1466,12 +1522,40 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") + } } } "<=" -> { - if(signed) { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(""" + if(expr.left is PtIdentifier) { + val varName = asmgen.asmVariableName(expr.left as PtIdentifier) + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.AY) + if(signed) + asmgen.out(""" + cmp $varName + tya + sbc $varName+1 + bvc + + eor #${'$'}80 ++ bmi + + lda #1 + bne ++ ++ lda #0 ++""") + else + asmgen.out(""" + cpy $varName+1 + bcc ++ + bne + + cmp $varName + bcc ++ ++ lda #1 + bne ++ ++ lda #0 ++""") + } else { + if(signed) { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(""" cmp P8ZP_SCRATCH_W1 tya sbc P8ZP_SCRATCH_W1+1 @@ -1482,10 +1566,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") - } - else { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(""" + } + else { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 bcc ++ bne + @@ -1495,12 +1579,40 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") + } } } ">" -> { - if(signed) { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(""" + if(expr.left is PtIdentifier) { + val varName = asmgen.asmVariableName(expr.left as PtIdentifier) + asmgen.assignExpressionToRegister(expr.right, RegisterOrPair.AY) + if(signed) + asmgen.out(""" + cmp $varName + tya + sbc $varName+1 + bvc + + eor #${'$'}80 ++ bpl ++ ++ lda #1 + bne ++ ++ lda #0 ++""") + else + asmgen.out(""" + cpy $varName+1 + bcc + + bne ++ + cmp $varName + bcs ++ ++ lda #1 + bne ++ ++ lda #0 ++""") + } else { + if(signed) { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(""" cmp P8ZP_SCRATCH_W1 tya sbc P8ZP_SCRATCH_W1+1 @@ -1511,10 +1623,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") - } - else { - asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") - asmgen.out(""" + } + else { + asmgen.assignWordOperandsToAYAndVar(expr.right, expr.left, "P8ZP_SCRATCH_W1") + asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 bcc + bne ++ @@ -1524,12 +1636,40 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") + } } } ">=" -> { - if(signed) { - asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") - asmgen.out(""" + if(expr.right is PtIdentifier) { + val varName = asmgen.asmVariableName(expr.right as PtIdentifier) + asmgen.assignExpressionToRegister(expr.left, RegisterOrPair.AY) + if(signed) + asmgen.out(""" + cmp $varName + tya + sbc $varName+1 + bvc + + eor #${'$'}80 ++ bmi + + lda #1 + bne ++ ++ lda #0 ++""") + else + asmgen.out(""" + cpy $varName+1 + bcc ++ + bne + + cmp $varName + bcc ++ ++ lda #1 + bne ++ ++ lda #0 ++""") + } else { + if(signed) { + asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") + asmgen.out(""" cmp P8ZP_SCRATCH_W1 tya sbc P8ZP_SCRATCH_W1+1 @@ -1540,10 +1680,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") - } - else { - asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") - asmgen.out(""" + } + else { + asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") + asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 bcc ++ bne + @@ -1553,6 +1693,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, bne ++ + lda #0 +""") + } } } else -> return false diff --git a/docs/source/todo.rst b/docs/source/todo.rst index bd54f57af..a5d480918 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,6 @@ TODO ==== -- what makes while xx <= x2 and pget(xx as uword, yy as uword) == cx16.r11L so large - - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - [on branch: ir-less-branch-opcodes] IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction - IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? Bitwise operations, etc), but only after setting the status bits is verified! diff --git a/examples/test.p8 b/examples/test.p8 index 81423210f..2320e386b 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,30 +1,22 @@ -%import syslib -%import textio %zeropage basicsafe main { - sub start() { - uword[] wordarray = [0,1,2,3,4,5,6,7,8,9] - ubyte n = 5 - n = lsb(wordarray[n]) - n = wordarray[n] as ubyte - test(wordarray[n] as ubyte,wordarray[n] as ubyte,0) - test(lsb(wordarray[n]), lsb(wordarray[n]),0) + + sub pget(uword x, uword y) -> ubyte { + return lsb(x+y) } - asmsub test(ubyte a1 @A, ubyte a2 @X, ubyte a3 @Y) { - %asm {{ - phy - phx - jsr txt.print_ub - jsr txt.spc - pla - jsr txt.print_ub - jsr txt.spc - pla - jsr txt.print_ub - jsr txt.nl - rts - }} + sub start() { + + word xx + word x2 + word yy + + if xx <= x2 and pget(xx as uword, yy as uword) == cx16.r11L + xx++ + +; if xx <= x2 +; if pget(xx as uword, yy as uword) == cx16.r11L +; xx++ } }