From abcdfd8e282704ad39d966a4945843f8b41610ad Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 3 Feb 2024 17:36:42 +0100 Subject: [PATCH] optimize postincrdecr on memory a bit --- codeCore/src/prog8/code/optimize/Optimizer.kt | 2 +- .../src/prog8/codegen/cpu6502/AsmGen.kt | 6 +- .../codegen/cpu6502/PostIncrDecrAsmGen.kt | 66 ++++++++++++++++--- .../cpu6502/assignment/AssignmentAsmGen.kt | 54 +++++++++++++-- .../compiler/astprocessing/CodeDesugarer.kt | 11 ++-- .../astprocessing/IntermediateAstMaker.kt | 2 +- docs/source/todo.rst | 2 + examples/test.p8 | 27 ++++---- 8 files changed, 128 insertions(+), 42 deletions(-) diff --git a/codeCore/src/prog8/code/optimize/Optimizer.kt b/codeCore/src/prog8/code/optimize/Optimizer.kt index ff6c91acb..2e0d0323c 100644 --- a/codeCore/src/prog8/code/optimize/Optimizer.kt +++ b/codeCore/src/prog8/code/optimize/Optimizer.kt @@ -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 diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 73b0c5982..55fde8cef 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -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() } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt index 91ad85934..632054f49 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt @@ -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() } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 07a79bc5c..3925f86ee 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -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() diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index 8b8ed6d25..818dc1a3f 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -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)) } } diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index 948a10a4d..c493ab259 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -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)) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4eda06138..bd4dc5d5f 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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. ... diff --git a/examples/test.p8 b/examples/test.p8 index 1f1aaa0d6..a60058068 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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])