generate 65c02 TSB/TRB instructions in certain cases

This commit is contained in:
Irmen de Jong 2024-07-16 00:25:29 +02:00
parent d5adb85e5b
commit 78c7ee247a
4 changed files with 67 additions and 48 deletions

View File

@ -50,6 +50,13 @@ internal fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefin
numberOfOptimizations++ numberOfOptimizations++
} }
mods = optimizeTSBtoRegularOr(linesByFour)
if(mods.isNotEmpty()) {
apply(mods, lines)
linesByFour = getLinesBy(lines, 4)
numberOfOptimizations++
}
var linesByFourteen = getLinesBy(lines, 14) var linesByFourteen = getLinesBy(lines, 14)
mods = optimizeSameAssignments(linesByFourteen, machine, symbolTable) mods = optimizeSameAssignments(linesByFourteen, machine, symbolTable)
if(mods.isNotEmpty()) { if(mods.isNotEmpty()) {
@ -684,6 +691,29 @@ private fun optimizeUselessPushPopStack(linesByFour: Sequence<List<IndexedValue<
return mods return mods
} }
private fun optimizeTSBtoRegularOr(linesByFour: Sequence<List<IndexedValue<String>>>): List<Modification> {
// Asm peephole: lda var2 / tsb var1 / lda var1 Replace this with this to save 1 cycle: lda var1 / ora var2 / sta var1
val mods = mutableListOf<Modification>()
for(lines in linesByFour) {
val first = lines[0].value.trimStart()
val second = lines[1].value.trimStart()
val third = lines[2].value.trimStart()
if(first.startsWith("lda") && second.startsWith("tsb") && third.startsWith("lda")) {
val operand1 = first.substring(3)
val operand2 = second.substring(3)
val operand3 = third.substring(3)
if(operand1!=operand2 && operand2==operand3) {
mods.add(Modification(lines[0].index, false, " lda $operand2 ; op2"))
mods.add(Modification(lines[1].index, false, " ora $operand1 ; op1"))
mods.add(Modification(lines[2].index, false, " sta $operand2 ; op2"))
}
}
}
return mods
}
private fun optimizeUnneededTempvarInAdd(linesByFour: Sequence<List<IndexedValue<String>>>): List<Modification> { private fun optimizeUnneededTempvarInAdd(linesByFour: Sequence<List<IndexedValue<String>>>): List<Modification> {
// sequence: sta P8ZP_SCRATCH_XX / lda something / clc / adc P8ZP_SCRATCH_XX // sequence: sta P8ZP_SCRATCH_XX / lda something / clc / adc P8ZP_SCRATCH_XX
// this can be performed without the scratch variable: clc / adc something // this can be performed without the scratch variable: clc / adc something

View File

@ -1086,6 +1086,15 @@ $shortcutLabel:""")
} }
} }
if(asmgen.isTargetCpu(CpuType.CPU65c02)) {
if(operator=="&" && value is PtPrefix && value.operator=="~") {
// M &= ~A --> use special TRB 65c02 instruction for that
asmgen.assignExpressionToRegister(value.value, RegisterOrPair.A, dt in SignedDatatypes)
asmgen.out(" trb $name")
return
}
}
// normal evaluation // normal evaluation
asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes) asmgen.assignExpressionToRegister(value, RegisterOrPair.A, dt in SignedDatatypes)
inplacemodificationRegisterAwithVariableWithSwappedOperands(operator, name, dt in SignedDatatypes) inplacemodificationRegisterAwithVariableWithSwappedOperands(operator, name, dt in SignedDatatypes)
@ -1094,6 +1103,15 @@ $shortcutLabel:""")
private fun inplacemodificationByteVariableWithVariable(name: String, dt: DataType, operator: String, otherName: String) { private fun inplacemodificationByteVariableWithVariable(name: String, dt: DataType, operator: String, otherName: String) {
// note: no logical and/or shortcut here, not worth it due to simple right operand // note: no logical and/or shortcut here, not worth it due to simple right operand
if(asmgen.isTargetCpu(CpuType.CPU65c02)) {
if(operator=="|") {
// M |= A --> use special TSB 65c02 instruction for that
asmgen.out(" lda $otherName | tsb $name")
return
}
}
asmgen.out(" lda $name") asmgen.out(" lda $name")
inplacemodificationRegisterAwithVariable(operator, otherName, dt in SignedDatatypes) inplacemodificationRegisterAwithVariable(operator, otherName, dt in SignedDatatypes)
asmgen.out(" sta $name") asmgen.out(" sta $name")

View File

@ -91,7 +91,6 @@ Libraries:
Optimizations: Optimizations:
- For 65c02 targets: use trb and tsb instructions if possible (f.ex. generating ``lda cmask trb nvub`` for ``nvub &= ~cmask`` and ``lda cmask and fillm tsb nvub`` for ``nvub |= cmask & fillm``
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served? - VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served?
for instance, vars used inside loops first, then loopvars, then uwords used as pointers, then the rest for instance, vars used inside loops first, then loopvars, then uwords used as pointers, then the rest
- various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code, - various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code,

View File

@ -1,56 +1,28 @@
%import textio %import textio
%import anyall
%option no_sysinit %option no_sysinit
%zeropage basicsafe
main { main {
byte[256] barray
word[128] warray
uword large_barray=memory("bytes", 1000, 0)
uword large_warray=memory("words", 1000, 0)
sub check() {
txt.print_bool(anyall.all(barray, 256))
txt.spc()
txt.print_bool(anyall.any(barray, 256))
txt.nl()
txt.print_bool(anyall.allw(warray, 128))
txt.spc()
txt.print_bool(anyall.anyw(warray, 128))
txt.nl()
txt.print_bool(anyall.all(large_barray, 1000))
txt.spc()
txt.print_bool(anyall.any(large_barray, 1000))
txt.nl()
txt.print_bool(anyall.allw(large_warray, 500))
txt.spc()
txt.print_bool(anyall.anyw(large_warray, 500))
txt.nl()
txt.nl()
}
sub start() { sub start() {
sys.memset(large_barray, 1000, 0) ubyte @shared b1 = %10101010
sys.memset(large_warray, 1000, 0) ubyte @shared b2 = %00001111
check() b1 &= ~b2
barray[250] = 99 txt.print_ubbin(b1, true)
warray[100] = $0100 txt.nl()
large_barray[900] = 99 b1 |= b2
large_warray[900] = 99 txt.print_ubbin(b1, true)
check() txt.nl()
sys.memset(barray, 255, 1)
sys.memset(warray, 254, 1) b1 = %11001100
sys.memset(large_barray, 999, 1) b2 = %11110000
sys.memset(large_warray, 998, 1)
check() b1 &= ~b2
barray[255]=1 txt.print_ubbin(b1, true)
warray[127]=1 txt.nl()
@(large_barray+999)=1 b1 |= b2
@(large_warray+999)=1 txt.print_ubbin(b1, true)
check() txt.nl()
repeat {}
; smallringbuffer.init() ; smallringbuffer.init()
; ;