From 44ee4b989ff51d3778c25549b746e7647c7f2fb5 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 12 Aug 2022 00:46:38 +0200 Subject: [PATCH] optimize code for logical expressions more if right operand is simple --- .../cpu6502/assignment/AssignmentAsmGen.kt | 105 ++++++++++++------ docs/source/todo.rst | 2 +- examples/test.p8 | 19 ++-- 3 files changed, 84 insertions(+), 42 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index d350feb5d..e17594500 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -360,43 +360,44 @@ internal class AssignmentAsmGen(private val program: Program, if(expr.operator in setOf("&", "|", "^", "and", "or", "xor")) { if(expr.left.inferType(program).isBytes && expr.right.inferType(program).isBytes && expr.left.isSimple && expr.right.isSimple) { -// if(expr.right is NumericLiteral || expr.right is IdentifierReference) { -// TODO("optimized code for logical with right number/variable arg (byte)") -// } else if(expr.left is NumericLiteral || expr.left is IdentifierReference) { -// TODO("optimized code for logical with left number/variable arg (byte)") -// } - - assignExpressionToRegister(expr.left, RegisterOrPair.A, false) - asmgen.saveRegisterStack(CpuRegister.A, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSubroutine) - asmgen.restoreRegisterStack(CpuRegister.A, false) - when(expr.operator) { - "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1") - "|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_B1") - "^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_B1") - else -> throw AssemblyError("invalid operator") + if(expr.right is NumericLiteral || expr.right is IdentifierReference) + assignLogicalWithSimpleRightOperandByte(assign.target, expr.left, expr.operator, expr.right) + else if(expr.left is NumericLiteral || expr.left is IdentifierReference) + assignLogicalWithSimpleRightOperandByte(assign.target, expr.right, expr.operator, expr.left) + else { + assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.saveRegisterStack(CpuRegister.A, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE, expr.definingSubroutine) + asmgen.restoreRegisterStack(CpuRegister.A, false) + when (expr.operator) { + "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_B1") + "|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_B1") + "^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_B1") + else -> throw AssemblyError("invalid operator") + } + assignRegisterByte(assign.target, CpuRegister.A) } - assignRegisterByte(assign.target, CpuRegister.A) return true } if(expr.left.inferType(program).isWords && expr.right.inferType(program).isWords && expr.left.isSimple && expr.right.isSimple) { -// if(expr.right is NumericLiteral || expr.right is IdentifierReference) { -// TODO("optimized code for logical with right number/variable arg (word)") -// } else if(expr.left is NumericLiteral || expr.left is IdentifierReference) { -// TODO("optimized code for logical with left number/variable arg (word)") -// } - assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) - asmgen.saveRegisterStack(CpuRegister.A, false) - asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSubroutine) - when(expr.operator) { - "&", "and" -> asmgen.out(" pla | and P8ZP_SCRATCH_W1+1 | tay | pla | and P8ZP_SCRATCH_W1") - "|", "or" -> asmgen.out(" pla | ora P8ZP_SCRATCH_W1+1 | tay | pla | ora P8ZP_SCRATCH_W1") - "^", "xor" -> asmgen.out(" pla | eor P8ZP_SCRATCH_W1+1 | tay | pla | eor P8ZP_SCRATCH_W1") - else -> throw AssemblyError("invalid operator") + if(expr.right is NumericLiteral || expr.right is IdentifierReference) + assignLogicalWithSimpleRightOperandWord(assign.target, expr.left, expr.operator, expr.right) + else if(expr.left is NumericLiteral || expr.left is IdentifierReference) + assignLogicalWithSimpleRightOperandWord(assign.target, expr.right, expr.operator, expr.left) + else { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) + asmgen.saveRegisterStack(CpuRegister.A, false) + asmgen.saveRegisterStack(CpuRegister.Y, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD, expr.definingSubroutine) + when (expr.operator) { + "&", "and" -> asmgen.out(" pla | and P8ZP_SCRATCH_W1+1 | tay | pla | and P8ZP_SCRATCH_W1") + "|", "or" -> asmgen.out(" pla | ora P8ZP_SCRATCH_W1+1 | tay | pla | ora P8ZP_SCRATCH_W1") + "^", "xor" -> asmgen.out(" pla | eor P8ZP_SCRATCH_W1+1 | tay | pla | eor P8ZP_SCRATCH_W1") + else -> throw AssemblyError("invalid operator") + } + assignRegisterpairWord(assign.target, RegisterOrPair.AY) } - assignRegisterpairWord(assign.target, RegisterOrPair.AY) return true } return false @@ -596,6 +597,48 @@ internal class AssignmentAsmGen(private val program: Program, return false } + private fun assignLogicalWithSimpleRightOperandByte(target: AsmAssignTarget, left: Expression, operator: String, right: Expression) { + assignExpressionToRegister(left, RegisterOrPair.A, false) + val operand = when(right) { + is NumericLiteral -> "#${right.number.toHex()}" + is IdentifierReference -> asmgen.asmSymbolName(right) + else -> throw AssemblyError("wrong right operand type") + } + when (operator) { + "&", "and" -> asmgen.out(" and $operand") + "|", "or" -> asmgen.out(" ora $operand") + "^", "xor" -> asmgen.out(" eor $operand") + else -> throw AssemblyError("invalid operator") + } + assignRegisterByte(target, CpuRegister.A) + } + + private fun assignLogicalWithSimpleRightOperandWord(target: AsmAssignTarget, left: Expression, operator: String, right: Expression) { + assignExpressionToRegister(left, RegisterOrPair.AY, false) + when(right) { + is NumericLiteral -> { + val number = right.number.toHex() + when (operator) { + "&", "and" -> asmgen.out(" and #<$number | pha | tya | and #>$number | tay | pla") + "|", "or" -> asmgen.out(" ora #<$number | pha | tya | ora #>$number | tay | pla") + "^", "xor" -> asmgen.out(" eor #<$number | pha | tya | eor #>$number | tay | pla") + else -> throw AssemblyError("invalid operator") + } + } + is IdentifierReference -> { + val name = asmgen.asmSymbolName(right) + when (operator) { + "&", "and" -> asmgen.out(" and $name | pha | tya | and $name+1 | tay | pla") + "|", "or" -> asmgen.out(" ora $name | pha | tya | ora $name+1 | tay | pla") + "^", "xor" -> asmgen.out(" eor $name | pha | tya | eor $name+1 | tay | pla") + else -> throw AssemblyError("invalid operator") + } + } + else -> throw AssemblyError("wrong right operand type") + } + assignRegisterpairWord(target, RegisterOrPair.AY) + } + private fun attemptAssignToByteCompareZero(expr: BinaryExpression, assign: AsmAssignment): Boolean { when (expr.operator) { "==" -> { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 132f6eca0..c50f8af7c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,8 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- finish the logical expression optimizations set in TODO's in attemptAssignOptimizedBinexpr() - try more benchmarks from https://gglabs.us/node/2293 +- check that all examples still function correctly ... diff --git a/examples/test.p8 b/examples/test.p8 index 6b9758883..0b6e72c09 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,16 +4,15 @@ main { sub start() { uword crc = $ffff - txt.print_uwhex(crc | (crc & $8000), true) -; if crc & $8000 ; msb(crc) & $80 -; txt.print("yes") -; else -; txt.print("fail!") -; -; if msb(crc) & $80 -; txt.print("yes") -; else -; txt.print("fail!") + if crc & $8000 ; msb(crc) & $80 + txt.print("yes") + else + txt.print("fail!") + + if crc & $1234 + txt.print("yes") + else + txt.print("fail!") } ; sub start2() {