mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
asm assignment opts
This commit is contained in:
parent
5f2bf2b375
commit
8bd5cc01b4
@ -85,65 +85,6 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
return AssemblyProgram(program.name)
|
||||
}
|
||||
|
||||
private fun optimizeAssembly(lines: MutableList<String>): Int {
|
||||
// sometimes, iny+dey / inx+dex / dey+iny / dex+inx sequences are generated, these can be eliminated.
|
||||
val removeLines = mutableListOf<Int>()
|
||||
var numberOfOptimizations = 0
|
||||
for(pair in lines.withIndex().windowed(2)) {
|
||||
val first = pair[0].value
|
||||
val second = pair[1].value
|
||||
if(first.trimStart().startsWith(';') || second.trimStart().startsWith(';'))
|
||||
continue // skip over asm comments
|
||||
|
||||
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))
|
||||
{
|
||||
removeLines.add(pair[0].index)
|
||||
removeLines.add(pair[1].index)
|
||||
numberOfOptimizations++
|
||||
}
|
||||
}
|
||||
|
||||
for(i in removeLines.reversed())
|
||||
lines.removeAt(i)
|
||||
removeLines.clear()
|
||||
|
||||
// sta X + lda X, sty X + ldy X, stx X + ldx X -> the second instruction can be eliminated
|
||||
for(pair in lines.withIndex().windowed(2)) {
|
||||
val first = pair[0].value.trim()
|
||||
val second = pair[1].value.trim()
|
||||
if(first.startsWith(';') || second.startsWith(';'))
|
||||
continue // skip over asm comments
|
||||
|
||||
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 "))
|
||||
) {
|
||||
val firstLoc = first.substring(4)
|
||||
val secondLoc = second.substring(4)
|
||||
if(firstLoc==secondLoc) {
|
||||
removeLines.add(pair[1].index)
|
||||
numberOfOptimizations++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(i in removeLines.reversed())
|
||||
lines.removeAt(i)
|
||||
removeLines.clear()
|
||||
|
||||
return numberOfOptimizations
|
||||
}
|
||||
|
||||
private fun out(str: String, splitlines: Boolean=true) {
|
||||
if(splitlines) {
|
||||
for (line in str.split('\n')) {
|
||||
@ -576,7 +517,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
" sta ${ESTACK_LO.toHex()},x | tya | sta ${ESTACK_HI.toHex()},x | dex "
|
||||
}
|
||||
Opcode.PUSH_ADDR_HEAPVAR -> {
|
||||
" lda #<${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | lda #>${ins.callLabel} | sta ${ESTACK_HI.toHex()},x | dex"
|
||||
" lda #<${ins.callLabel} | sta ${ESTACK_LO.toHex()},x | lda #>${ins.callLabel} | sta ${ESTACK_HI.toHex()},x | dex"
|
||||
}
|
||||
Opcode.POP_REGAX_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself")
|
||||
Opcode.POP_REGXY_WORD -> throw AssemblyError("cannot load X register from stack because it's used as the stack pointer itself")
|
||||
@ -1595,9 +1536,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
val number = hexVal(segment[0])
|
||||
"""
|
||||
lda #<$number
|
||||
ldy #>$number
|
||||
sta ${segment[1].callLabel}
|
||||
lda #>$number
|
||||
sta ${segment[1].callLabel}+1
|
||||
sty ${segment[1].callLabel}+1
|
||||
"""
|
||||
},
|
||||
// var = ubytevar
|
||||
@ -1695,9 +1636,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
AsmPattern(listOf(Opcode.PUSH_WORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
"""
|
||||
lda #<${hexVal(segment[0])}
|
||||
ldy #>${hexVal(segment[0])}
|
||||
sta ${hexVal(segment[1])}
|
||||
lda #>${hexVal(segment[0])}
|
||||
sta ${hexValPlusOne(segment[1])}
|
||||
sty ${hexValPlusOne(segment[1])}
|
||||
"""
|
||||
},
|
||||
// mem uword = ubyte var
|
||||
@ -1720,11 +1661,11 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
},
|
||||
// mem uword = uword var
|
||||
AsmPattern(listOf(Opcode.PUSH_VAR_WORD, Opcode.POP_MEM_WORD)) { segment ->
|
||||
" lda ${segment[0].callLabel} || sta ${hexVal(segment[1])} | lda ${segment[0].callLabel}+1 | sta ${hexValPlusOne(segment[1])}"
|
||||
" lda ${segment[0].callLabel} | ldy ${segment[0].callLabel}+1 | sta ${hexVal(segment[1])} | sty ${hexValPlusOne(segment[1])}"
|
||||
},
|
||||
// mem uword = address-of var
|
||||
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.POP_MEM_WORD)) { segment ->
|
||||
" lda #<${segment[0].callLabel} || sta ${hexVal(segment[1])} | lda #>${segment[0].callLabel} | sta ${hexValPlusOne(segment[1])}"
|
||||
" lda #<${segment[0].callLabel} | ldy #>{segment[0].callLabel} | sta ${hexVal(segment[1])} | sty ${hexValPlusOne(segment[1])}"
|
||||
},
|
||||
// mem (u)word = mem (u)word
|
||||
AsmPattern(
|
||||
@ -1742,9 +1683,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
val index = intVal(segment[0])
|
||||
"""
|
||||
lda ${segment[1].callLabel}+$index
|
||||
ldy #0
|
||||
sta ${hexVal(segment[3])}
|
||||
lda #0
|
||||
sta ${hexValPlusOne(segment[3])}
|
||||
sty ${hexValPlusOne(segment[3])}
|
||||
"""
|
||||
},
|
||||
// mem uword = bytearray[index] (sign extended)
|
||||
@ -2248,7 +2189,7 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram,
|
||||
// uwordarray[index] = address-of var
|
||||
AsmPattern(listOf(Opcode.PUSH_ADDR_HEAPVAR, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
|
||||
val index = intVal(segment[1])*2
|
||||
" lda #<${segment[0].callLabel} | sta ${segment[2].callLabel}+$index | lda #>${segment[0].callLabel} | sta ${segment[2].callLabel}+${index+1}"
|
||||
" lda #<${segment[0].callLabel} | ldy #>${segment[0].callLabel} | sta ${segment[2].callLabel}+$index | sty ${segment[2].callLabel}+${index+1}"
|
||||
},
|
||||
// uwordarray[index] = mem uword
|
||||
AsmPattern(listOf(Opcode.PUSH_MEM_UW, Opcode.PUSH_BYTE, Opcode.WRITE_INDEXED_VAR_WORD)) { segment ->
|
||||
|
127
compiler/src/prog8/compiler/target/c64/AsmOptimizer.kt
Normal file
127
compiler/src/prog8/compiler/target/c64/AsmOptimizer.kt
Normal file
@ -0,0 +1,127 @@
|
||||
package prog8.compiler.target.c64
|
||||
|
||||
fun optimizeAssembly(lines: MutableList<String>): Int {
|
||||
|
||||
var numberOfOptimizations = 0
|
||||
|
||||
var linesByTwo = getLinesBy(lines, 2)
|
||||
|
||||
var removeLines = optimizeIncDec(linesByTwo)
|
||||
if(removeLines.isNotEmpty()) {
|
||||
for (i in removeLines.reversed())
|
||||
lines.removeAt(i)
|
||||
linesByTwo = getLinesBy(lines, 2)
|
||||
numberOfOptimizations++
|
||||
}
|
||||
|
||||
removeLines = optimizeStoreLoadSame(linesByTwo)
|
||||
|
||||
if(removeLines.isNotEmpty()) {
|
||||
for (i in removeLines.reversed())
|
||||
lines.removeAt(i)
|
||||
numberOfOptimizations++
|
||||
}
|
||||
|
||||
var linesByFourteen = getLinesBy(lines, 14)
|
||||
removeLines = optimizeSameAssignments(linesByFourteen)
|
||||
if(removeLines.isNotEmpty()) {
|
||||
for (i in removeLines.reversed())
|
||||
lines.removeAt(i)
|
||||
numberOfOptimizations++
|
||||
}
|
||||
|
||||
|
||||
println("ASM OPTIMIZATIONS: $numberOfOptimizations") // TODO weg
|
||||
return numberOfOptimizations
|
||||
}
|
||||
|
||||
fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<String>>>): List<Int> {
|
||||
|
||||
// optimize sequential assignments of the same value to various targets (bytes, words, floats)
|
||||
// the float one is the one that requires 2*7=14 lines of code to check...
|
||||
|
||||
val removeLines = mutableListOf<Int>()
|
||||
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()
|
||||
|
||||
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")) {
|
||||
val firstvalue = first.substring(4)
|
||||
val secondvalue = second.substring(4)
|
||||
val thirdvalue = fifth.substring(4)
|
||||
val fourthvalue = sixth.substring(4)
|
||||
if(firstvalue==thirdvalue && secondvalue==fourthvalue) {
|
||||
// lda/ldy sta/sty twice the same word --> remove second lda/ldy pair (fifth and sixth lines)
|
||||
removeLines.add(pair[4].index)
|
||||
removeLines.add(pair[5].index)
|
||||
}
|
||||
}
|
||||
|
||||
if(first.startsWith("lda") && second.startsWith("sta") && third.startsWith("lda") && fourth.startsWith("sta")) {
|
||||
val firstvalue = first.substring(4)
|
||||
val secondvalue = third.substring(4)
|
||||
if(firstvalue==secondvalue) {
|
||||
// lda value / sta ? / lda same-value / sta ? -> remove second lda (third line)
|
||||
removeLines.add(pair[2].index)
|
||||
}
|
||||
}
|
||||
|
||||
// @todo check float initializations.
|
||||
}
|
||||
return removeLines
|
||||
}
|
||||
|
||||
private fun getLinesBy(lines: MutableList<String>, windowSize: Int) =
|
||||
// all lines (that aren't empty or comments) in sliding pairs of 2
|
||||
lines.withIndex().filter { it.value.isNotBlank() && !it.value.trimStart().startsWith(';') }.windowed(windowSize, partialWindows = false)
|
||||
|
||||
private fun optimizeStoreLoadSame(linesByTwo: List<List<IndexedValue<String>>>): List<Int> {
|
||||
// sta X + lda X, sty X + ldy X, stx X + ldx X -> the second instruction can be eliminated
|
||||
val removeLines = mutableListOf<Int>()
|
||||
for (pair in linesByTwo) {
|
||||
val first = pair[0].value.trimStart()
|
||||
val second = pair[1].value.trimStart()
|
||||
|
||||
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 "))
|
||||
) {
|
||||
val firstLoc = first.substring(4)
|
||||
val secondLoc = second.substring(4)
|
||||
if (firstLoc == secondLoc) {
|
||||
removeLines.add(pair[1].index)
|
||||
}
|
||||
}
|
||||
}
|
||||
return removeLines
|
||||
}
|
||||
|
||||
private fun optimizeIncDec(linesByTwo: List<List<IndexedValue<String>>>): List<Int> {
|
||||
// sometimes, iny+dey / inx+dex / dey+iny / dex+inx sequences are generated, these can be eliminated.
|
||||
val removeLines = mutableListOf<Int>()
|
||||
for (pair in linesByTwo) {
|
||||
val first = pair[0].value
|
||||
val second = pair[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)) {
|
||||
removeLines.add(pair[0].index)
|
||||
removeLines.add(pair[1].index)
|
||||
}
|
||||
}
|
||||
return removeLines
|
||||
}
|
Loading…
Reference in New Issue
Block a user