optimize postincrdecr on memory a bit

This commit is contained in:
Irmen de Jong 2024-02-03 17:36:42 +01:00
parent b0f5b6925d
commit abcdfd8e28
8 changed files with 128 additions and 42 deletions

View File

@ -98,7 +98,7 @@ private fun optimizeCommonSubExpressions(program: PtProgram, errors: IErrorRepor
stmtContainer.children.add(stmtContainer.children.indexOf(stmt), tempassign)
tempassign.parent = stmtContainer
val tempvar = PtVariable(tempvarName, datatype, ZeropageWish.DONTCARE, null, null, binexpr.position)
val tempvar = PtVariable(tempvarName, datatype, ZeropageWish.NOT_IN_ZEROPAGE, null, null, binexpr.position)
stmtContainer.add(0, tempvar)
tempvar.parent = stmtContainer

View File

@ -1192,7 +1192,7 @@ $repeatLabel""")
return null
}
internal fun tryOptimizedPointerAccessWithA(addressExpr: PtExpression, operator: String, write: Boolean): Boolean {
internal fun tryOptimizedPointerAccessWithA(addressExpr: PtBinaryExpression, write: Boolean): Boolean {
// optimize pointer,indexregister if possible
fun evalBytevalueWillClobberA(expr: PtExpression): Boolean {
@ -1208,7 +1208,7 @@ $repeatLabel""")
}
}
if(operator=="+") {
if(addressExpr.operator=="+") {
val ptrAndIndex = pointerViaIndexRegisterPossible(addressExpr)
if(ptrAndIndex!=null) {
val pointervar = ptrAndIndex.first as? PtIdentifier
@ -2919,7 +2919,7 @@ $repeatLabel""")
}
is PtBinaryExpression -> {
val addrExpr = expr.address as PtBinaryExpression
if(!tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
if(!tryOptimizedPointerAccessWithA(addrExpr, false)) {
assignViaExprEval()
}
}

View File

@ -1,9 +1,6 @@
package prog8.codegen.cpu6502
import prog8.code.ast.PtIdentifier
import prog8.code.ast.PtNumber
import prog8.code.ast.PtPostIncrDecr
import prog8.code.ast.PtProgram
import prog8.code.ast.*
import prog8.code.core.*
@ -37,6 +34,55 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as
}
}
targetMemory!=null -> {
fun incDecViaExprEval() {
asmgen.assignExpressionToRegister(targetMemory.address, RegisterOrPair.AY)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
if(incr)
asmgen.out("+\tinc ${'$'}ffff\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff\t; modified")
}
fun tryOptimizedPointerIncDec(address: PtBinaryExpression): Boolean {
if(address.operator=="+") {
val offset = address.right.asConstInteger()
if(offset!=null && offset<256) {
// we have @(ptr + 255) ++ , or @(ptr+255)--
asmgen.assignExpressionToRegister(address.left, RegisterOrPair.AY, false)
asmgen.out("""
sta (+) + 1
sty (+) + 2
ldx #$offset""")
if(incr)
asmgen.out("+\tinc ${'$'}ffff,x\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff,x\t; modified")
return true
} else if(address.right.type in ByteDatatypes) {
// we have @(ptr + bytevar) ++ , or @(ptr+bytevar)--
asmgen.assignExpressionToRegister(address.left, RegisterOrPair.AY, false)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
asmgen.assignExpressionToRegister(address.right, RegisterOrPair.X, false)
if(incr)
asmgen.out("+\tinc ${'$'}ffff,x\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff,x\t; modified")
return true
} else if((address.right as? PtTypeCast)?.value?.type in ByteDatatypes) {
// we have @(ptr + bytevar) ++ , or @(ptr+bytevar)--
asmgen.assignExpressionToRegister(address.left, RegisterOrPair.AY, false)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
asmgen.assignExpressionToRegister((address.right as PtTypeCast).value, RegisterOrPair.X, false)
if(incr)
asmgen.out("+\tinc ${'$'}ffff,x\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff,x\t; modified")
return true
}
}
return false
}
when (val addressExpr = targetMemory.address) {
is PtNumber -> {
val what = addressExpr.number.toHex()
@ -50,13 +96,13 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as
else
asmgen.out("+\tdec ${'$'}ffff\t; modified")
}
is PtBinaryExpression -> {
if(!tryOptimizedPointerIncDec(addressExpr)) {
incDecViaExprEval()
}
}
else -> {
asmgen.assignExpressionToRegister(addressExpr, RegisterOrPair.AY)
asmgen.out(" sta (+) + 1 | sty (+) + 2")
if(incr)
asmgen.out("+\tinc ${'$'}ffff\t; modified")
else
asmgen.out("+\tdec ${'$'}ffff\t; modified")
incDecViaExprEval()
}
}
}

View File

@ -144,7 +144,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
is PtBinaryExpression -> {
val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, false)) {
assignRegisterByte(assign.target, CpuRegister.A, false, true)
} else {
assignViaExprEval(value.address)
@ -772,9 +772,21 @@ internal class AssignmentAsmGen(private val program: PtProgram,
return true
}
else -> {
val leftMemByte = expr.left as? PtMemoryByte
val rightMemByte = expr.right as? PtMemoryByte
val leftArrayIndexer = expr.left as? PtArrayIndexer
val rightArrayIndexer = expr.right as? PtArrayIndexer
if(rightArrayIndexer!=null && rightArrayIndexer.type in ByteDatatypes && left.type in ByteDatatypes) {
// special optimization for bytevalue +/- bytearr[y] : no need to use a tempvar, just use adc array,y or sbc array,y or adc (ptr),y / sbc (ptr),y
if(expr.operator=="+" && leftArrayIndexer!=null && leftArrayIndexer.type in ByteDatatypes && right.type in ByteDatatypes) {
// special optimization for bytearray[y] + bytevalue : no need to use a tempvar, just use adc array,y
assignExpressionToRegister(right, RegisterOrPair.A, right.type==DataType.BYTE)
if(!leftArrayIndexer.index.isSimple()) asmgen.out(" pha")
asmgen.assignExpressionToRegister(leftArrayIndexer.index, RegisterOrPair.Y, false)
if(!leftArrayIndexer.index.isSimple()) asmgen.out(" pla")
val arrayvarname = asmgen.asmSymbolName(leftArrayIndexer.variable)
asmgen.out(" clc | adc $arrayvarname,y")
assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true)
} else if(rightArrayIndexer!=null && rightArrayIndexer.type in ByteDatatypes && left.type in ByteDatatypes) {
// special optimization for bytevalue +/- bytearray[y] : no need to use a tempvar, just use adc array,y or sbc array,y
assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE)
if(!rightArrayIndexer.index.isSimple()) asmgen.out(" pha")
asmgen.assignExpressionToRegister(rightArrayIndexer.index, RegisterOrPair.Y, false)
@ -785,6 +797,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
else
asmgen.out(" sec | sbc $arrayvarname,y")
assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true)
} else if(expr.operator=="+" && leftMemByte!=null && right.type in ByteDatatypes && optimizedPointerIndexPlusByteIntoA(leftMemByte, right)) {
assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true)
return true
} else if(rightMemByte!=null && left.type in ByteDatatypes && optimizedPointerIndexPlusMinusByteIntoA(left, expr.operator, rightMemByte)) {
assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true)
return true
} else {
assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE)
if(directIntoY(right)) {
@ -969,6 +987,32 @@ internal class AssignmentAsmGen(private val program: PtProgram,
return false
}
private fun optimizedPointerIndexPlusByteIntoA(mem: PtMemoryByte, value: PtExpression): Boolean {
// special optimization for pointervar[y] + bytevalue (actually: @(address) + value)
return false // TODO implement this optimization?
}
private fun optimizedPointerIndexPlusMinusByteIntoA(value: PtExpression, operator: String, mem: PtMemoryByte): Boolean {
// special optimization for bytevalue +/- pointervar[y] (actually: bytevalue +/- @(address) )
val address = mem.address as? PtBinaryExpression
if(address is PtBinaryExpression) {
val offset = address.right.asConstInteger()
if(offset!=null && offset<256) {
// we have value + @(ptr + 255), or value - @(ptr+255)
// TODO()
} else if(address.right.type in ByteDatatypes) {
// we have @(ptr + bytevar) ++ , or @(ptr+bytevar)--
// TODO()
} else if((address.right as? PtTypeCast)?.value?.type in ByteDatatypes) {
// we have @(ptr + bytevar) ++ , or @(ptr+bytevar)--
// TODO()
}
}
println("TODO: OPTIMIZE POINTER PLUSMINUS ${value.position}")
return false
}
private fun optimizedBitwiseExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean {
if (expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) {
if (expr.right.isSimple()) {
@ -1993,7 +2037,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
is PtBinaryExpression -> {
val addrExpr = value.address as PtBinaryExpression
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, addrExpr.operator, false)) {
if(asmgen.tryOptimizedPointerAccessWithA(addrExpr, false)) {
asmgen.out(" ldy #0")
assignRegisterpairWord(target, RegisterOrPair.AY)
} else {
@ -3860,7 +3904,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
}
}
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, addressExpr.operator, true))
if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, true))
storeViaExprEval()
}
else -> storeViaExprEval()

View File

@ -197,19 +197,16 @@ _after:
val indexExpr = arrayIndexedExpression.indexer.indexExpr
val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl(program)
if(arrayVar!=null && arrayVar.datatype==DataType.UWORD) {
val add: Expression =
if(indexExpr.constValue(program)?.number==0.0)
arrayIndexedExpression.arrayvar.copy()
else
BinaryExpression(arrayIndexedExpression.arrayvar.copy(), "+", indexExpr, arrayIndexedExpression.position)
val wordIndex = TypecastExpression(indexExpr, DataType.UWORD, true, indexExpr.position)
val address = BinaryExpression(arrayIndexedExpression.arrayvar.copy(), "+", wordIndex, arrayIndexedExpression.position)
return if(parent is AssignTarget) {
// assignment to array
val memwrite = DirectMemoryWrite(add, arrayIndexedExpression.position)
val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position)
val newtarget = AssignTarget(null, null, memwrite, arrayIndexedExpression.position)
listOf(IAstModification.ReplaceNode(parent, newtarget, parent.parent))
} else {
// read from array
val memread = DirectMemoryRead(add, arrayIndexedExpression.position)
val memread = DirectMemoryRead(address, arrayIndexedExpression.position)
listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent))
}
}

View File

@ -552,7 +552,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
private fun transform(srcArr: ArrayIndexedExpression): PtArrayIndexer {
if(srcArr.arrayvar.targetVarDecl(program)!!.datatype !in ArrayDatatypes + DataType.STR)
throw FatalAstException("array indexing can be used on array or string variables ${srcArr.position}")
throw FatalAstException("array indexing can only be used on array or string variables ${srcArr.position}")
val eltType = srcArr.inferType(program).getOrElse { throw FatalAstException("unknown dt") }
val array = PtArrayIndexer(eltType, srcArr.position)
array.add(transform(srcArr.arrayvar))

View File

@ -4,6 +4,8 @@ TODO
petaxian is now a lot larger since pointer[idx] is rewritten into @(ptr+idx). Missing some optimized code somewhere now?
VM textelite is now a lot larger too
DO: "TODO implement this optimization"
(after merge in boolean): move all "OperatorXinplace" from expressionGen to AssignmentGen, see if we can get rid of the Result return type.
...

View File

@ -5,25 +5,22 @@
%option no_sysinit
main {
sub derp(str arg) {
arg[4] = '?'
}
sub start() {
str msg = "hello"
derp(msg)
txt.chrout(msg[4]) ; ?
txt.nl()
; ubyte[10] az
ubyte @shared offset=4
uword @shared az = $4000
@($4004) = 0
az[4] |= $40
txt.print_ub(@($4004)) ; 64
ubyte @shared value = 22
@($4004) = 99
az[4]--
@(az + offset)--
txt.print_ub(@($4004))
txt.nl()
@(az+4) = 0
@(az+4) |= $4f
txt.print_ub(@($4004)) ; 79
az[4]++
@(az+offset)++
txt.print_ub(@($4004))
txt.nl()
; cx16.r0L = az[4] + value*5
; cx16.r1L = value*5 + az[4]
; ubyte @shared idx = 1
; txt.print_w(array[idx])