From 222bcb808f773be1e06589ed9a0d4da92542b97c Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 10 Nov 2021 23:47:35 +0100 Subject: [PATCH] optimize load-store-load combo in output asm --- .../target/cpu6502/codegen/AsmOptimizer.kt | 93 +++++++++++-------- .../compiler/BeforeAsmGenerationAstChanger.kt | 3 +- docs/source/todo.rst | 3 +- 3 files changed, 55 insertions(+), 44 deletions(-) diff --git a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmOptimizer.kt b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmOptimizer.kt index eb4d8a878..aad750514 100644 --- a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmOptimizer.kt +++ b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmOptimizer.kt @@ -118,15 +118,15 @@ private fun optimizeSameAssignments(linesByFourteen: List() - for (pair in linesByFourteen) { - val first = pair[0].value.trimStart() - val second = pair[1].value.trimStart() - val third = pair[2].value.trimStart() - val fourth = pair[3].value.trimStart() - val fifth = pair[4].value.trimStart() - val sixth = pair[5].value.trimStart() - val seventh = pair[6].value.trimStart() - val eighth = pair[7].value.trimStart() + for (lines in linesByFourteen) { + val first = lines[0].value.trimStart() + val second = lines[1].value.trimStart() + val third = lines[2].value.trimStart() + val fourth = lines[3].value.trimStart() + val fifth = lines[4].value.trimStart() + val sixth = lines[5].value.trimStart() + val seventh = lines[6].value.trimStart() + val eighth = lines[7].value.trimStart() if(first.startsWith("lda") && second.startsWith("ldy") && third.startsWith("sta") && fourth.startsWith("sty") && fifth.startsWith("lda") && sixth.startsWith("ldy") && seventh.startsWith("sta") && eighth.startsWith("sty")) { @@ -136,8 +136,8 @@ private fun optimizeSameAssignments(linesByFourteen: List remove second lda/ldy pair (fifth and sixth lines) - mods.add(Modification(pair[4].index, true, null)) - mods.add(Modification(pair[5].index, true, null)) + mods.add(Modification(lines[4].index, true, null)) + mods.add(Modification(lines[5].index, true, null)) } } @@ -146,7 +146,7 @@ private fun optimizeSameAssignments(linesByFourteen: List remove second lda (third line) - mods.add(Modification(pair[2].index, true, null)) + mods.add(Modification(lines[2].index, true, null)) } } @@ -154,12 +154,12 @@ private fun optimizeSameAssignments(linesByFourteen: List>>) // sta X + lda X, sty X + ldy X, stx X + ldx X -> the second instruction can OFTEN be eliminated // TODO this is not true if X is not a regular RAM memory address (but instead mapped I/O or ROM) but how does this code know? val mods = mutableListOf() - for (pair in linesByFour) { - val first = pair[0].value.trimStart() - val second = pair[1].value.trimStart() + for (lines in linesByFour) { + val first = lines[1].value.trimStart() + val second = lines[2].value.trimStart() if ((first.startsWith("sta ") && second.startsWith("lda ")) || (first.startsWith("stx ") && second.startsWith("ldx ")) || @@ -196,14 +196,25 @@ private fun optimizeStoreLoadSame(linesByFour: List>>) (first.startsWith("sty ") && second.startsWith("ldy ")) || (first.startsWith("stx ") && second.startsWith("ldx ")) ) { - val third = pair[2].value.trimStart() - if(!third.startsWith("b")) { - // no branch instruction follows, we can potentiall remove the load instruction + val third = lines[3].value.trimStart() + val attemptRemove = + if(third.startsWith("b")) { + // a branch instruction follows, we can only remove the load instruction if + // another load instruction of the same register precedes the store instruction + // (otherwise wrong cpu flags are used) + val loadinstruction = second.substring(0, 3) + lines[0].value.trimStart().startsWith(loadinstruction) + } + else { + // no branch instruction follows, we can remove the load instruction + true + } + + if(attemptRemove) { val firstLoc = first.substring(4).trimStart() val secondLoc = second.substring(4).trimStart() - if (firstLoc == secondLoc) { - mods.add(Modification(pair[1].index, true, null)) - } + if (firstLoc == secondLoc) + mods.add(Modification(lines[2].index, true, null)) } } } @@ -213,15 +224,15 @@ private fun optimizeStoreLoadSame(linesByFour: List>>) private fun optimizeIncDec(linesByFour: List>>): List { // sometimes, iny+dey / inx+dex / dey+iny / dex+inx sequences are generated, these can be eliminated. val mods = mutableListOf() - for (pair in linesByFour) { - val first = pair[0].value - val second = pair[1].value + for (lines in linesByFour) { + val first = lines[0].value + val second = lines[1].value if ((" iny" in first || "\tiny" in first) && (" dey" in second || "\tdey" in second) || (" inx" in first || "\tinx" in first) && (" dex" in second || "\tdex" in second) || (" dey" in first || "\tdey" in first) && (" iny" in second || "\tiny" in second) || (" dex" in first || "\tdex" in first) && (" inx" in second || "\tinx" in second)) { - mods.add(Modification(pair[0].index, true, null)) - mods.add(Modification(pair[1].index, true, null)) + mods.add(Modification(lines[0].index, true, null)) + mods.add(Modification(lines[1].index, true, null)) } } return mods @@ -230,12 +241,12 @@ private fun optimizeIncDec(linesByFour: List>>): List< private fun optimizeJsrRts(linesByFour: List>>): List { // jsr Sub + rts -> jmp Sub val mods = mutableListOf() - for (pair in linesByFour) { - val first = pair[0].value - val second = pair[1].value + for (lines in linesByFour) { + val first = lines[0].value + val second = lines[1].value if ((" jsr" in first || "\tjsr" in first ) && (" rts" in second || "\trts" in second)) { - mods += Modification(pair[0].index, false, pair[0].value.replace("jsr", "jmp")) - mods += Modification(pair[1].index, true, null) + mods += Modification(lines[0].index, false, lines[0].value.replace("jsr", "jmp")) + mods += Modification(lines[1].index, true, null) } } return mods diff --git a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt index 7f7e95c1e..a40164589 100644 --- a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt +++ b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt @@ -209,7 +209,8 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o throw FatalAstException("0==X should have been swapped to if X==0") // simplify the conditional expression, introduce simple assignments if required. - // TODO sometimes this increases code size significantly (Petaxian) !!! FIX THIS + // NOTE: sometimes this increases code size because additional stores/loads are generated for the + // intermediate variables. We assume these are optimized away from the resulting assembly code later. val simplify = simplifyConditionalExpression(binExpr) val modifications = mutableListOf() if(simplify.rightVarAssignment!=null) { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 94f947e35..060784348 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,9 +3,8 @@ TODO For next compiler release (7.3) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- if-statement expression simplification sometimes increases code size (Petaxian) FIX THIS! -- add expression simplification to while and until loops as well. - let typecasting code use expression.typecastTo() +- add expression simplification to while and until loops as well. Blocked by Commander-x16 v39 release