diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 52cfed85a..1efdf0096 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -2910,6 +2910,9 @@ $repeatLabel lda $counterVar } } + internal fun needAsaveForExpr(arg: Expression): Boolean = + arg !is NumericLiteral && arg !is IdentifierReference && (arg !is DirectMemoryRead || !arg.isSimple) + private val subroutineExtrasCache = mutableMapOf() internal fun subroutineExtra(sub: Subroutine): SubroutineExtraAsmInfo { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 594c1d174..d646180eb 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -44,7 +44,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, "abs" -> funcAbs(fcall, func, resultToStack, resultRegister, sscope) "any", "all" -> funcAnyAll(fcall, func, resultToStack, resultRegister, sscope) "sgn" -> funcSgn(fcall, func, resultToStack, resultRegister, sscope) - "boolean" -> funcBoolean(fcall, func, resultToStack, resultRegister, sscope) + "boolean" -> funcBoolean(fcall, resultToStack, resultRegister, sscope) "rnd", "rndw" -> funcRnd(func, resultToStack, resultRegister, sscope) "sqrt16" -> funcSqrt16(fcall, func, resultToStack, resultRegister, sscope) "rol" -> funcRol(fcall) @@ -698,7 +698,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun funcBoolean(fcall: IFunctionCall, func: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) { + private fun funcBoolean(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) { when (val dt = fcall.args.single().inferType(program).getOr(DataType.UNDEFINED)) { in ByteDatatypes -> { assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.A, dt==DataType.BYTE) @@ -884,7 +884,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex") } else { val reg = resultRegister ?: RegisterOrPair.AY - var needAsave = needAsaveForOtherArg(fcall.args[0]) + var needAsave = asmgen.needAsaveForExpr(fcall.args[0]) if(!needAsave) { val mr0 = fcall.args[0] as? DirectMemoryRead val mr1 = fcall.args[1] as? DirectMemoryRead @@ -1133,7 +1133,4 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, } } - private fun needAsaveForOtherArg(arg: Expression): Boolean = - arg !is NumericLiteral && arg !is IdentifierReference && arg !is DirectMemoryRead - } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index b5288da17..981d2e2a5 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -69,10 +69,6 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg (sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes) || (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes) - private fun needAsaveForOtherArg(arg: Expression): Boolean = - arg !is NumericLiteral && arg !is IdentifierReference && arg !is DirectMemoryRead - - internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) { // Output only the code to set up the parameters and perform the actual call // NOTE: does NOT output the code to deal with the result values! @@ -112,10 +108,10 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg } else { // 2 byte params, second in Y, first in A argumentViaRegister(sub, IndexedValue(0, sub.parameters[0]), call.args[0], RegisterOrPair.A) - if(needAsaveForOtherArg(call.args[1])) + if(asmgen.needAsaveForExpr(call.args[1])) asmgen.out(" pha") argumentViaRegister(sub, IndexedValue(1, sub.parameters[1]), call.args[1], RegisterOrPair.Y) - if(needAsaveForOtherArg(call.args[1])) + if(asmgen.needAsaveForExpr(call.args[1])) asmgen.out(" pla") } } else { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 2009691d6..d6638870b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -2,6 +2,7 @@ package prog8.codegen.cpu6502.assignment import prog8.ast.Program import prog8.ast.expressions.* +import prog8.ast.getTempRegisterName import prog8.ast.statements.* import prog8.code.core.* import prog8.codegen.cpu6502.AsmGen @@ -321,6 +322,63 @@ internal class AssignmentAsmGen(private val program: Program, if(!expr.inferType(program).isInteger) return false + // optimized code for logical expressions + // TODO assume (hope) cx16.r9 isn't used for anything else during the use of this... + if(expr.operator=="and") { + val iDt = expr.left.inferType(program) + val dt = iDt.getOrElse { throw AssemblyError("weird dt") } + if (dt in ByteDatatypes) { + val tmpReg = getTempRegisterName(iDt).joinToString(".") + assignExpressionToVariable(expr.left, tmpReg, dt, expr.definingSubroutine) + assignExpressionToRegister(expr.right, RegisterOrPair.A, dt==DataType.BYTE || dt==DataType.WORD) + asmgen.out(" and $tmpReg") + if(assign.target.datatype in ByteDatatypes) + assignRegisterByte(assign.target, CpuRegister.A) + else { + asmgen.out(" ldy #0") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + } + return true + } + else throw AssemblyError("weird dt for and, expected byte $expr @${expr.position}") + } + else if(expr.operator=="or") { + val iDt = expr.left.inferType(program) + val dt = iDt.getOrElse { throw AssemblyError("weird dt") } + if (dt in ByteDatatypes) { + val tmpReg = getTempRegisterName(iDt).joinToString(".") + assignExpressionToVariable(expr.left, tmpReg, dt, expr.definingSubroutine) + assignExpressionToRegister(expr.right, RegisterOrPair.A, dt==DataType.BYTE || dt==DataType.WORD) + asmgen.out(" ora $tmpReg") + if(assign.target.datatype in ByteDatatypes) + assignRegisterByte(assign.target, CpuRegister.A) + else { + asmgen.out(" ldy #0") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + } + return true + } + else throw AssemblyError("weird dt for or, expected byte $expr @${expr.position}") + } + else if(expr.operator=="xor") { + val iDt = expr.left.inferType(program) + val dt = iDt.getOrElse { throw AssemblyError("weird dt") } + if (dt in ByteDatatypes) { + val tmpReg = getTempRegisterName(iDt).joinToString(".") + assignExpressionToVariable(expr.left, tmpReg, dt, expr.definingSubroutine) + assignExpressionToRegister(expr.right, RegisterOrPair.A, dt==DataType.BYTE || dt==DataType.WORD) + asmgen.out(" eor $tmpReg") + if(assign.target.datatype in ByteDatatypes) + assignRegisterByte(assign.target, CpuRegister.A) + else { + asmgen.out(" ldy #0") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + } + return true + } + else throw AssemblyError("weird dt for xor, expected byte $expr @${expr.position}") + } + if(expr.operator!="+" && expr.operator!="-") return false diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 7262c0562..e3d68a0f1 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- optimize logical expressions in attemptAssignOptimizedBinexpr() -- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value? ... @@ -19,6 +17,7 @@ Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ Compiler: +- add McCarthy evaluation to shortcircuit and/or expressions. First do ifs by splitting them up? Then do expressions that compute a value? - vm: implement remaining sin/cos functions in math.p8 - vm: somehow deal with asmsubs otherwise the vm IR can't fully encode all of prog8 - vm: don't store symbol names in instructions to make optimizing the IR easier? but what about jumps to labels. And it's no longer readable by humans. diff --git a/examples/test.p8 b/examples/test.p8 index c24f06f91..4b00ed6bf 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -73,10 +73,10 @@ main { ubyte value uword wvalue - txt.print("short and with false (word): ") - wvalue = funcw() and funcFalseWord() and funcw() and funcw() - txt.print_uw(wvalue) - txt.nl() +; txt.print("short and with false (word): ") +; wvalue = funcw() and funcFalseWord() and funcw() and funcw() +; txt.print_uw(wvalue) +; txt.nl() txt.print("short and with false: ") value = func1(25) and funcFalse()