mirror of
https://github.com/irmen/prog8.git
synced 2024-11-27 03:50:27 +00:00
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:
parent
8887e6af91
commit
787e35c9f3
@ -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) }
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user