asm optimizer can now also see of a symbol reference if it is in IO space or not (to a certain extent), so that these instructions are no longer optimized away

This commit is contained in:
Irmen de Jong 2021-11-21 13:12:51 +01:00
parent 8887e6af91
commit 787e35c9f3
3 changed files with 36 additions and 18 deletions

View File

@ -87,7 +87,7 @@ class AsmGen(private val program: Program,
assemblyLines.addAll(outputFile.readLines()) assemblyLines.addAll(outputFile.readLines())
var optimizationsDone = 1 var optimizationsDone = 1
while (optimizationsDone > 0) { while (optimizationsDone > 0) {
optimizationsDone = optimizeAssembly(assemblyLines, options.compTarget.machine) optimizationsDone = optimizeAssembly(assemblyLines, options.compTarget.machine, program)
} }
outputFile.printWriter().use { outputFile.printWriter().use {
for (line in assemblyLines) { it.println(line) } for (line in assemblyLines) { it.println(line) }

View File

@ -1,12 +1,16 @@
package prog8.compiler.target.cpu6502.codegen package prog8.compiler.target.cpu6502.codegen
import prog8.ast.Program
import prog8.ast.base.VarDeclType
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.VarDecl
import prog8.compilerinterface.IMachineDefinition import prog8.compilerinterface.IMachineDefinition
// note: see https://wiki.nesdev.org/w/index.php/6502_assembly_optimisations // note: see https://wiki.nesdev.org/w/index.php/6502_assembly_optimisations
fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefinition): Int { fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefinition, program: Program): Int {
var numberOfOptimizations = 0 var numberOfOptimizations = 0
@ -33,7 +37,7 @@ fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefinition): I
numberOfOptimizations++ numberOfOptimizations++
} }
mods = optimizeStoreLoadSame(linesByFour, machine) mods = optimizeStoreLoadSame(linesByFour, machine, program)
if(mods.isNotEmpty()) { if(mods.isNotEmpty()) {
apply(mods, lines) apply(mods, lines)
linesByFour = getLinesBy(lines, 4) linesByFour = getLinesBy(lines, 4)
@ -48,7 +52,7 @@ fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefinition): I
} }
var linesByFourteen = getLinesBy(lines, 14) var linesByFourteen = getLinesBy(lines, 14)
mods = optimizeSameAssignments(linesByFourteen, machine) mods = optimizeSameAssignments(linesByFourteen, machine, program)
if(mods.isNotEmpty()) { if(mods.isNotEmpty()) {
apply(mods, lines) apply(mods, lines)
linesByFourteen = getLinesBy(lines, 14) linesByFourteen = getLinesBy(lines, 14)
@ -113,7 +117,7 @@ private fun optimizeUselessStackByteWrites(linesByFour: List<List<IndexedValue<S
return mods return mods
} }
private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<String>>>, machine: IMachineDefinition): List<Modification> { private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<String>>>, machine: IMachineDefinition, program: Program): List<Modification> {
// Optimize sequential assignments of the same value to various targets (bytes, words, floats) // 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... // the float one is the one that requires 2*7=14 lines of code to check...
@ -138,8 +142,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 same word --> remove second lda/ldy pair (fifth and sixth lines) // lda/ldy sta/sty twice the same word --> remove second lda/ldy pair (fifth and sixth lines)
val address1 = getAddressArg(first) val address1 = getAddressArg(first, program)
val address2 = getAddressArg(second) val address2 = getAddressArg(second, program)
if(address1==null || address2==null || (!machine.isIOAddress(address1) && !machine.isIOAddress(address2))) { if(address1==null || address2==null || (!machine.isIOAddress(address1) && !machine.isIOAddress(address2))) {
mods.add(Modification(lines[4].index, true, null)) mods.add(Modification(lines[4].index, true, null))
mods.add(Modification(lines[5].index, true, null)) mods.add(Modification(lines[5].index, true, null))
@ -152,7 +156,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 same-value / sta ? -> remove second lda (third line) // lda value / sta ? / lda same-value / sta ? -> remove second lda (third line)
val address = getAddressArg(first) val address = getAddressArg(first, program)
if(address==null || !machine.isIOAddress(address)) if(address==null || !machine.isIOAddress(address))
mods.add(Modification(lines[2].index, true, null)) mods.add(Modification(lines[2].index, true, null))
} }
@ -235,7 +239,7 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
val thirdvalue = third.substring(4) val thirdvalue = third.substring(4)
val fourthvalue = fourth.substring(4) val fourthvalue = fourth.substring(4)
if(firstvalue==thirdvalue && secondvalue == fourthvalue) { if(firstvalue==thirdvalue && secondvalue == fourthvalue) {
val address = getAddressArg(first) val address = getAddressArg(first, program)
if(address==null || !machine.isIOAddress(address)) { if(address==null || !machine.isIOAddress(address)) {
overlappingMods = true overlappingMods = true
mods.add(Modification(lines[2].index, true, null)) mods.add(Modification(lines[2].index, true, null))
@ -258,7 +262,7 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
val firstvalue = first.substring(4) val firstvalue = first.substring(4)
val thirdvalue = third.substring(4) val thirdvalue = third.substring(4)
if(firstvalue==thirdvalue) { if(firstvalue==thirdvalue) {
val address = getAddressArg(first) val address = getAddressArg(first, program)
if(address==null || !machine.isIOAddress(address)) { if(address==null || !machine.isIOAddress(address)) {
overlappingMods = true overlappingMods = true
mods.add(Modification(lines[2].index, true, null)) mods.add(Modification(lines[2].index, true, null))
@ -278,7 +282,7 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
val secondvalue = second.substring(4) val secondvalue = second.substring(4)
val thirdvalue = third.substring(4) val thirdvalue = third.substring(4)
if(firstvalue==secondvalue && firstvalue==thirdvalue) { if(firstvalue==secondvalue && firstvalue==thirdvalue) {
val address = getAddressArg(first) val address = getAddressArg(first, program)
if(address==null || !machine.isIOAddress(address)) { if(address==null || !machine.isIOAddress(address)) {
overlappingMods = true overlappingMods = true
val reg2 = second[2] val reg2 = second[2]
@ -297,7 +301,7 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
val firstvalue = first.substring(4) val firstvalue = first.substring(4)
val secondvalue = second.substring(4) val secondvalue = second.substring(4)
if(firstvalue==secondvalue) { if(firstvalue==secondvalue) {
val address = getAddressArg(first) val address = getAddressArg(first, program)
if(address==null || !machine.isIOAddress(address)) { if(address==null || !machine.isIOAddress(address)) {
overlappingMods = true overlappingMods = true
mods.add(Modification(lines[1].index, true, null)) mods.add(Modification(lines[1].index, true, null))
@ -310,7 +314,7 @@ private fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<Stri
return mods return mods
} }
private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>, machine: IMachineDefinition): List<Modification> { private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>, machine: IMachineDefinition, program: Program): List<Modification> {
// 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
val mods = mutableListOf<Modification>() val mods = mutableListOf<Modification>()
for (lines in linesByFour) { for (lines in linesByFour) {
@ -338,7 +342,7 @@ private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>,
} }
else { else {
// no branch instruction follows, we can remove the load instruction // no branch instruction follows, we can remove the load instruction
val address = getAddressArg(lines[2].value) val address = getAddressArg(lines[2].value, program)
address==null || !machine.isIOAddress(address) address==null || !machine.isIOAddress(address)
} }
@ -353,13 +357,30 @@ private fun optimizeStoreLoadSame(linesByFour: List<List<IndexedValue<String>>>,
return mods return mods
} }
private fun getAddressArg(line: String): UInt? { private val identifierRegex = Regex("""^([a-zA-Z_$][a-zA-Z\d_\.$]*)""")
private fun getAddressArg(line: String, program: Program): UInt? {
val loadArg = line.trimStart().substring(3).trim() val loadArg = line.trimStart().substring(3).trim()
return when { return when {
loadArg.startsWith('$') -> loadArg.substring(1).toUIntOrNull(16) loadArg.startsWith('$') -> loadArg.substring(1).toUIntOrNull(16)
loadArg.startsWith('%') -> loadArg.substring(1).toUIntOrNull(2) loadArg.startsWith('%') -> loadArg.substring(1).toUIntOrNull(2)
loadArg.startsWith('#') -> null loadArg.startsWith('#') -> null
loadArg.startsWith('(') -> null loadArg.startsWith('(') -> null
loadArg[0].isLetter() -> {
val identMatch = identifierRegex.find(loadArg)
if(identMatch!=null) {
val identifier = identMatch.value
val decl = program.toplevelModule.lookup(identifier.split(".")) as? VarDecl
if(decl!=null) {
when(decl.type){
VarDeclType.VAR -> null
VarDeclType.CONST,
VarDeclType.MEMORY -> (decl.value as NumericLiteralValue).number.toUInt()
}
}
else null
} else null
}
else -> loadArg.substring(1).toUIntOrNull() else -> loadArg.substring(1).toUIntOrNull()
} }
} }

View File

@ -3,9 +3,6 @@ TODO
For next compiler release (7.4) For next compiler release (7.4)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
BUG: amiga example doesn't clear the whole screen when compiled with optimizations (ok without opts)
same sort of problem in bobs example, and highresbitmap, and testgfx2
... ...