optimized 6502 codegen for logical expressions

This commit is contained in:
Irmen de Jong 2022-06-15 22:16:17 +02:00
parent cc174b7b85
commit bda016bb3b
6 changed files with 71 additions and 18 deletions

View File

@ -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<Subroutine, SubroutineExtraAsmInfo>() private val subroutineExtrasCache = mutableMapOf<Subroutine, SubroutineExtraAsmInfo>()
internal fun subroutineExtra(sub: Subroutine): SubroutineExtraAsmInfo { internal fun subroutineExtra(sub: Subroutine): SubroutineExtraAsmInfo {

View File

@ -44,7 +44,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
"abs" -> funcAbs(fcall, func, resultToStack, resultRegister, sscope) "abs" -> funcAbs(fcall, func, resultToStack, resultRegister, sscope)
"any", "all" -> funcAnyAll(fcall, func, resultToStack, resultRegister, sscope) "any", "all" -> funcAnyAll(fcall, func, resultToStack, resultRegister, sscope)
"sgn" -> funcSgn(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) "rnd", "rndw" -> funcRnd(func, resultToStack, resultRegister, sscope)
"sqrt16" -> funcSqrt16(fcall, func, resultToStack, resultRegister, sscope) "sqrt16" -> funcSqrt16(fcall, func, resultToStack, resultRegister, sscope)
"rol" -> funcRol(fcall) "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)) { when (val dt = fcall.args.single().inferType(program).getOr(DataType.UNDEFINED)) {
in ByteDatatypes -> { in ByteDatatypes -> {
assignAsmGen.assignExpressionToRegister(fcall.args.single(), RegisterOrPair.A, dt==DataType.BYTE) 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") asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
} else { } else {
val reg = resultRegister ?: RegisterOrPair.AY val reg = resultRegister ?: RegisterOrPair.AY
var needAsave = needAsaveForOtherArg(fcall.args[0]) var needAsave = asmgen.needAsaveForExpr(fcall.args[0])
if(!needAsave) { if(!needAsave) {
val mr0 = fcall.args[0] as? DirectMemoryRead val mr0 = fcall.args[0] as? DirectMemoryRead
val mr1 = fcall.args[1] 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
} }

View File

@ -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==1 && sub.parameters[0].type in IntegerDatatypes)
|| (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes) || (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) { internal fun translateFunctionCall(call: IFunctionCall, isExpression: Boolean) {
// Output only the code to set up the parameters and perform the actual call // 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! // 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 { } else {
// 2 byte params, second in Y, first in A // 2 byte params, second in Y, first in A
argumentViaRegister(sub, IndexedValue(0, sub.parameters[0]), call.args[0], RegisterOrPair.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") asmgen.out(" pha")
argumentViaRegister(sub, IndexedValue(1, sub.parameters[1]), call.args[1], RegisterOrPair.Y) 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") asmgen.out(" pla")
} }
} else { } else {

View File

@ -2,6 +2,7 @@ package prog8.codegen.cpu6502.assignment
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.getTempRegisterName
import prog8.ast.statements.* import prog8.ast.statements.*
import prog8.code.core.* import prog8.code.core.*
import prog8.codegen.cpu6502.AsmGen import prog8.codegen.cpu6502.AsmGen
@ -321,6 +322,63 @@ internal class AssignmentAsmGen(private val program: Program,
if(!expr.inferType(program).isInteger) if(!expr.inferType(program).isInteger)
return false 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!="-") if(expr.operator!="+" && expr.operator!="-")
return false return false

View File

@ -3,8 +3,6 @@ TODO
For next release 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: 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: 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: 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. - 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.

View File

@ -73,10 +73,10 @@ main {
ubyte value ubyte value
uword wvalue uword wvalue
txt.print("short and with false (word): ") ; txt.print("short and with false (word): ")
wvalue = funcw() and funcFalseWord() and funcw() and funcw() ; wvalue = funcw() and funcFalseWord() and funcw() and funcw()
txt.print_uw(wvalue) ; txt.print_uw(wvalue)
txt.nl() ; txt.nl()
txt.print("short and with false: ") txt.print("short and with false: ")
value = func1(25) and funcFalse() value = func1(25) and funcFalse()