mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 04:30:03 +00:00
optimized 6502 codegen for logical expressions
This commit is contained in:
parent
cc174b7b85
commit
bda016bb3b
@ -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 {
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user