From 820541e427bafa4ed22585f6e3e57a92e21a2cc5 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 11 Mar 2024 23:13:32 +0100 Subject: [PATCH] fixed and optimized pointervar indexed in-place operations --- .../src/prog8/codegen/cpu6502/AsmOptimizer.kt | 20 ++- .../assignment/AugmentableAssignmentAsmGen.kt | 71 +++++++--- docs/source/todo.rst | 5 - examples/test.p8 | 131 ++++++++++++++++-- 4 files changed, 186 insertions(+), 41 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt index 9ab425abd..8fbfa512c 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt @@ -382,21 +382,18 @@ private fun optimizeStoreLoadSame( machine: IMachineDefinition, symbolTable: SymbolTable ): List { - // sta X + lda X, sty X + ldy X, stx X + ldx X -> the second instruction can OFTEN be eliminated val mods = mutableListOf() for (lines in linesByFour) { val first = lines[1].value.trimStart() val second = lines[2].value.trimStart() + // sta X + lda X, sty X + ldy X, stx X + ldx X -> the second instruction can OFTEN be eliminated if ((first.startsWith("sta ") && second.startsWith("lda ")) || (first.startsWith("stx ") && second.startsWith("ldx ")) || (first.startsWith("sty ") && second.startsWith("ldy ")) || (first.startsWith("lda ") && second.startsWith("lda ")) || (first.startsWith("ldy ") && second.startsWith("ldy ")) || - (first.startsWith("ldx ") && second.startsWith("ldx ")) || - (first.startsWith("sta ") && second.startsWith("lda ")) || - (first.startsWith("sty ") && second.startsWith("ldy ")) || - (first.startsWith("stx ") && second.startsWith("ldx ")) + (first.startsWith("ldx ") && second.startsWith("ldx ")) ) { val third = lines[3].value.trimStart() val attemptRemove = @@ -439,6 +436,18 @@ private fun optimizeStoreLoadSame( mods.add(Modification(lines[1].index, true, null)) mods.add(Modification(lines[2].index, false, " tya")) } + + + // lda X + sta X, ldy X + sty X, ldx X + stx X -> the second instruction can be eliminated + if ((first.startsWith("lda ") && second.startsWith("sta ")) || + (first.startsWith("ldx ") && second.startsWith("stx ")) || + (first.startsWith("ldy ") && second.startsWith("sty ")) + ) { + val firstLoc = first.substring(4).trimStart() + val secondLoc = second.substring(4).trimStart() + if (firstLoc == secondLoc) + mods.add(Modification(lines[2].index, true, null)) + } } return mods } @@ -485,6 +494,7 @@ private fun optimizeIncDec(linesByFour: Sequence>>): L mods.add(Modification(lines[0].index, true, null)) mods.add(Modification(lines[1].index, true, null)) } + } return mods } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index f77f09303..8a93011d3 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -570,31 +570,68 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, private fun tryOptimizedMemoryInplace(address: PtBinaryExpression, operator: String, value: AsmAssignSource): Boolean { if(value.datatype !in ByteDatatypes || operator !in "|&^+-") return false - val rightTc = address.right as? PtTypeCast - val constOffset = (address.right as? PtNumber)?.number?.toInt() - if(address.operator=="+" && (address.right.type in ByteDatatypes || (rightTc!=null && rightTc.value.type in ByteDatatypes) || (constOffset!=null && constOffset<256)) ) { - if(rightTc!=null) - asmgen.assignExpressionToRegister(rightTc.value, RegisterOrPair.A, false) - else if(constOffset!=null) - asmgen.out(" lda #${constOffset}") - else - asmgen.assignExpressionToRegister(address.right, RegisterOrPair.A, false) - asmgen.out(" pha") // offset on stack - val zpPointerVarName: String + + fun addrIntoZpPointer(): String { if(address.left is PtIdentifier && asmgen.isZpVar(address.left as PtIdentifier)) { - zpPointerVarName = (address.left as PtIdentifier).name + return (address.left as PtIdentifier).name } else { - zpPointerVarName = "P8ZP_SCRATCH_W2" asmgen.assignExpressionToRegister(address.left, RegisterOrPair.AY, false) - asmgen.out(" sta $zpPointerVarName | sty $zpPointerVarName+1") + asmgen.out(" sta P8ZP_SCRATCH_W2 | sty P8ZP_SCRATCH_W2+1") + return "P8ZP_SCRATCH_W2" } - // calculate value into A + } + + fun assignValueToA() { val assignValue = AsmAssignment(value, AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.UBYTE, address.definingISub(), Position.DUMMY, register = RegisterOrPair.A), program.memsizer, Position.DUMMY) - assignmentAsmGen.translateNormalAssignment(assignValue, address.definingISub()) - asmgen.restoreRegisterStack(CpuRegister.Y, false) // offset into Y + assignmentAsmGen.translateNormalAssignment(assignValue, address.definingISub()) // calculate value into A + } + + val rightTc = address.right as? PtTypeCast + val constOffset = (address.right as? PtNumber)?.number?.toInt() + if(address.operator=="+" && (address.right.type in ByteDatatypes || (rightTc!=null && rightTc.value.type in ByteDatatypes) || (constOffset!=null && constOffset<256)) ) { + if(constOffset!=null) { + val zpPointerVarName = addrIntoZpPointer() + if(value.number==null) assignValueToA() + asmgen.out(" ldy #$constOffset") + when(operator) { + "|" -> { + if(value.number!=null) asmgen.out(" lda #${value.number.number.toInt()}") + asmgen.out(" ora ($zpPointerVarName),y") + } + "&" -> { + if(value.number!=null) asmgen.out(" lda #${value.number.number.toInt()}") + asmgen.out(" and ($zpPointerVarName),y") + } + "^" -> { + if(value.number!=null) asmgen.out(" lda #${value.number.number.toInt()}") + asmgen.out(" eor ($zpPointerVarName),y") + } + "+" -> { + // note: there is no inc (ZP),y instruction... + if (value.number != null) asmgen.out(" lda #${value.number.number.toInt()}") + asmgen.out(" clc | adc ($zpPointerVarName),y") + } + "-" -> { + // note: there is no dec (ZP),y instruction... + if (value.number != null) asmgen.out(" lda ($zpPointerVarName),y | sec | sbc #${value.number.number.toInt()}") + else asmgen.out(" sta P8ZP_SCRATCH_REG | lda ($zpPointerVarName),y | sec | sbc P8ZP_SCRATCH_REG") + } + else -> throw AssemblyError("invalid op") + } + asmgen.out(" sta ($zpPointerVarName),y") + return true + } + if(rightTc!=null) + asmgen.assignExpressionToRegister(rightTc.value, RegisterOrPair.A, false) + else + asmgen.assignExpressionToRegister(address.right, RegisterOrPair.A, false) + asmgen.out(" pha") // offset on stack + val zpPointerVarName = addrIntoZpPointer() + assignValueToA() + asmgen.restoreRegisterStack(CpuRegister.Y, true) // offset from stack back into Y when(operator) { "|" -> asmgen.out(" ora ($zpPointerVarName),y") "&" -> asmgen.out(" and ($zpPointerVarName),y") diff --git a/docs/source/todo.rst b/docs/source/todo.rst index db1751c16..ebb95291c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,11 +1,6 @@ TODO ==== -Petaxian has gameplay problems on the C64 (with and without optimization) , cx16 target is fine. -(seems unrelated to boolean type changes. 10.1 was still fine.) -caused by 358215e4ddf408e568ded0d36afce9f0162e21d1 Removed PostIncrDecr - - ... diff --git a/examples/test.p8 b/examples/test.p8 index e919a6d9b..bda9df96b 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,21 +4,124 @@ main { sub start() { - derp("hello") - mult3("hello") - } + uword @shared ref = $2000 + ref[5]=10 + txt.print_ub(ref[5]) + txt.spc() + ref[5]-- + txt.print_ub(ref[5]) + txt.spc() + ref[5]++ + txt.print_ub(ref[5]) + txt.nl() + ref[5]-=2 + txt.print_ub(ref[5]) + txt.spc() + ref[5]+=2 + txt.print_ub(ref[5]) + txt.nl() + ref[5]-=3 + txt.print_ub(ref[5]) + txt.spc() + ref[5]+=3 + txt.print_ub(ref[5]) + txt.nl() - sub derp(str arg) -> str { - cx16.r0++ - return arg - } - asmsub mult3(str input @XY) -> ubyte @A, str @XY { - %asm {{ - lda #99 - ldx #100 - ldy #101 - rts - }} + ubyte[] array = [1,2,3,4,5,10] + array[5]=10 + txt.print_ub(array[5]) + txt.spc() + array[5]-- + txt.print_ub(array[5]) + txt.spc() + array[5]++ + txt.print_ub(array[5]) + txt.nl() + array[5]-=2 + txt.print_ub(array[5]) + txt.spc() + array[5]+=2 + txt.print_ub(array[5]) + txt.nl() + array[5]-=3 + txt.print_ub(array[5]) + txt.spc() + array[5]+=3 + txt.print_ub(array[5]) + txt.nl() + + +; cx16.r0L = 5 +; ref[cx16.r0L]=10 +; txt.print_ub(ref[cx16.r0L]) +; txt.spc() +; ref[cx16.r0L]-- +; txt.print_ub(ref[cx16.r0L]) +; txt.spc() +; ref[cx16.r0L]++ +; txt.print_ub(ref[cx16.r0L]) +; txt.nl() +; +; uword @shared uw = 1000 +; word @shared sw = -1000 +; +; txt.print_uw(uw) +; txt.spc() +; uw++ +; txt.print_uw(uw) +; txt.spc() +; uw-- +; txt.print_uw(uw) +; txt.nl() +; uw = $00ff +; txt.print_uw(uw) +; txt.spc() +; uw++ +; txt.print_uw(uw) +; txt.spc() +; uw-- +; txt.print_uw(uw) +; txt.nl() +; +; txt.print_w(sw) +; txt.spc() +; sw++ +; txt.print_w(sw) +; txt.spc() +; sw-- +; txt.print_w(sw) +; txt.nl() +; sw = $00ff +; txt.print_w(sw) +; txt.spc() +; sw++ +; txt.print_w(sw) +; txt.spc() +; sw-- +; txt.print_w(sw) +; txt.nl() +; sw = -257 +; txt.print_w(sw) +; txt.spc() +; sw++ +; txt.print_w(sw) +; txt.spc() +; sw-- +; txt.print_w(sw) +; txt.nl() + + /* + seekerRef[SKR_X]-- this code looks very wrong with the pha/pla stuff + bulletRef[BD_Y]--/++ + enemyRef[EN_MOVE_CNT]--/++ + + signed word--/++ + unsigned word--/++ + + attackRef+=FIELD_COUNT + +*/ + } }