optimize load-store-load combo in output asm

This commit is contained in:
Irmen de Jong 2021-11-10 23:47:35 +01:00
parent 686483f51a
commit 222bcb808f
3 changed files with 55 additions and 44 deletions

View File

@ -118,15 +118,15 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
// @todo a better place to do this is in the Compiler instead and transform the Ast, or the AsmGen, and never even create the inefficient asm in the first place... // @todo a better place to do this is in the Compiler instead and transform the Ast, or the AsmGen, and never even create the inefficient asm in the first place...
val mods = mutableListOf<Modification>() val mods = mutableListOf<Modification>()
for (pair in linesByFourteen) { for (lines in linesByFourteen) {
val first = pair[0].value.trimStart() val first = lines[0].value.trimStart()
val second = pair[1].value.trimStart() val second = lines[1].value.trimStart()
val third = pair[2].value.trimStart() val third = lines[2].value.trimStart()
val fourth = pair[3].value.trimStart() val fourth = lines[3].value.trimStart()
val fifth = pair[4].value.trimStart() val fifth = lines[4].value.trimStart()
val sixth = pair[5].value.trimStart() val sixth = lines[5].value.trimStart()
val seventh = pair[6].value.trimStart() val seventh = lines[6].value.trimStart()
val eighth = pair[7].value.trimStart() val eighth = lines[7].value.trimStart()
if(first.startsWith("lda") && second.startsWith("ldy") && third.startsWith("sta") && fourth.startsWith("sty") && 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")) { fifth.startsWith("lda") && sixth.startsWith("ldy") && seventh.startsWith("sta") && eighth.startsWith("sty")) {
@ -136,8 +136,8 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
val fourthvalue = sixth.substring(4) val fourthvalue = sixth.substring(4)
if(firstvalue==thirdvalue && secondvalue==fourthvalue) { if(firstvalue==thirdvalue && secondvalue==fourthvalue) {
// lda/ldy sta/sty twice the isSameAs word --> remove second lda/ldy pair (fifth and sixth lines) // lda/ldy sta/sty twice the isSameAs word --> remove second lda/ldy pair (fifth and sixth lines)
mods.add(Modification(pair[4].index, true, null)) mods.add(Modification(lines[4].index, true, null))
mods.add(Modification(pair[5].index, true, null)) mods.add(Modification(lines[5].index, true, null))
} }
} }
@ -146,7 +146,7 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
val secondvalue = third.substring(4) val secondvalue = third.substring(4)
if(firstvalue==secondvalue) { if(firstvalue==secondvalue) {
// lda value / sta ? / lda isSameAs-value / sta ? -> remove second lda (third line) // lda value / sta ? / lda isSameAs-value / sta ? -> 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<List<IndexedValue<Stri
fifth.startsWith("lda") && sixth.startsWith("ldy") && fifth.startsWith("lda") && sixth.startsWith("ldy") &&
(seventh.startsWith("jsr floats.copy_float") || seventh.startsWith("jsr cx16flt.copy_float"))) { (seventh.startsWith("jsr floats.copy_float") || seventh.startsWith("jsr cx16flt.copy_float"))) {
val nineth = pair[8].value.trimStart() val nineth = lines[8].value.trimStart()
val tenth = pair[9].value.trimStart() val tenth = lines[9].value.trimStart()
val eleventh = pair[10].value.trimStart() val eleventh = lines[10].value.trimStart()
val twelveth = pair[11].value.trimStart() val twelveth = lines[11].value.trimStart()
val thirteenth = pair[12].value.trimStart() val thirteenth = lines[12].value.trimStart()
val fourteenth = pair[13].value.trimStart() val fourteenth = lines[13].value.trimStart()
if(eighth.startsWith("lda") && nineth.startsWith("ldy") && tenth.startsWith("sta") && eleventh.startsWith("sty") && if(eighth.startsWith("lda") && nineth.startsWith("ldy") && tenth.startsWith("sta") && eleventh.startsWith("sty") &&
twelveth.startsWith("lda") && thirteenth.startsWith("ldy") && twelveth.startsWith("lda") && thirteenth.startsWith("ldy") &&
@ -167,10 +167,10 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
if(first.substring(4) == eighth.substring(4) && second.substring(4)==nineth.substring(4)) { if(first.substring(4) == eighth.substring(4) && second.substring(4)==nineth.substring(4)) {
// identical float init // identical float init
mods.add(Modification(pair[7].index, true, null)) mods.add(Modification(lines[7].index, true, null))
mods.add(Modification(pair[8].index, true, null)) mods.add(Modification(lines[8].index, true, null))
mods.add(Modification(pair[9].index, true, null)) mods.add(Modification(lines[9].index, true, null))
mods.add(Modification(pair[10].index, true, null)) mods.add(Modification(lines[10].index, true, null))
} }
} }
} }
@ -182,9 +182,9 @@ private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>)
// sta X + lda X, sty X + ldy X, stx X + ldx X -> the second instruction can OFTEN be eliminated // 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? // 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<Modification>() val mods = mutableListOf<Modification>()
for (pair in linesByFour) { for (lines in linesByFour) {
val first = pair[0].value.trimStart() val first = lines[1].value.trimStart()
val second = pair[1].value.trimStart() val second = lines[2].value.trimStart()
if ((first.startsWith("sta ") && second.startsWith("lda ")) || if ((first.startsWith("sta ") && second.startsWith("lda ")) ||
(first.startsWith("stx ") && second.startsWith("ldx ")) || (first.startsWith("stx ") && second.startsWith("ldx ")) ||
@ -196,14 +196,25 @@ private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>)
(first.startsWith("sty ") && second.startsWith("ldy ")) || (first.startsWith("sty ") && second.startsWith("ldy ")) ||
(first.startsWith("stx ") && second.startsWith("ldx ")) (first.startsWith("stx ") && second.startsWith("ldx "))
) { ) {
val third = pair[2].value.trimStart() val third = lines[3].value.trimStart()
if(!third.startsWith("b")) { val attemptRemove =
// no branch instruction follows, we can potentiall remove the load instruction 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 firstLoc = first.substring(4).trimStart()
val secondLoc = second.substring(4).trimStart() val secondLoc = second.substring(4).trimStart()
if (firstLoc == secondLoc) { if (firstLoc == secondLoc)
mods.add(Modification(pair[1].index, true, null)) mods.add(Modification(lines[2].index, true, null))
}
} }
} }
} }
@ -213,15 +224,15 @@ private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>)
private fun optimizeIncDec(linesByFour: List<List<IndexedValue<String>>>): List<Modification> { private fun optimizeIncDec(linesByFour: List<List<IndexedValue<String>>>): List<Modification> {
// sometimes, iny+dey / inx+dex / dey+iny / dex+inx sequences are generated, these can be eliminated. // sometimes, iny+dey / inx+dex / dey+iny / dex+inx sequences are generated, these can be eliminated.
val mods = mutableListOf<Modification>() val mods = mutableListOf<Modification>()
for (pair in linesByFour) { for (lines in linesByFour) {
val first = pair[0].value val first = lines[0].value
val second = pair[1].value val second = lines[1].value
if ((" iny" in first || "\tiny" in first) && (" dey" in second || "\tdey" in second) 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) || (" inx" in first || "\tinx" in first) && (" dex" in second || "\tdex" in second)
|| (" dey" in first || "\tdey" in first) && (" iny" in second || "\tiny" 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)) { || (" dex" in first || "\tdex" in first) && (" inx" in second || "\tinx" in second)) {
mods.add(Modification(pair[0].index, true, null)) mods.add(Modification(lines[0].index, true, null))
mods.add(Modification(pair[1].index, true, null)) mods.add(Modification(lines[1].index, true, null))
} }
} }
return mods return mods
@ -230,12 +241,12 @@ private fun optimizeIncDec(linesByFour: List<List<IndexedValue<String>>>): List<
private fun optimizeJsrRts(linesByFour: List<List<IndexedValue<String>>>): List<Modification> { private fun optimizeJsrRts(linesByFour: List<List<IndexedValue<String>>>): List<Modification> {
// jsr Sub + rts -> jmp Sub // jsr Sub + rts -> jmp Sub
val mods = mutableListOf<Modification>() val mods = mutableListOf<Modification>()
for (pair in linesByFour) { for (lines in linesByFour) {
val first = pair[0].value val first = lines[0].value
val second = pair[1].value val second = lines[1].value
if ((" jsr" in first || "\tjsr" in first ) && (" rts" in second || "\trts" in second)) { 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(lines[0].index, false, lines[0].value.replace("jsr", "jmp"))
mods += Modification(pair[1].index, true, null) mods += Modification(lines[1].index, true, null)
} }
} }
return mods return mods

View File

@ -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") throw FatalAstException("0==X should have been swapped to if X==0")
// simplify the conditional expression, introduce simple assignments if required. // 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 simplify = simplifyConditionalExpression(binExpr)
val modifications = mutableListOf<IAstModification>() val modifications = mutableListOf<IAstModification>()
if(simplify.rightVarAssignment!=null) { if(simplify.rightVarAssignment!=null) {

View File

@ -3,9 +3,8 @@ TODO
For next compiler release (7.3) 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() - let typecasting code use expression.typecastTo()
- add expression simplification to while and until loops as well.
Blocked by Commander-x16 v39 release Blocked by Commander-x16 v39 release