mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
generate 65c02 TSB/TRB instructions in certain cases
This commit is contained in:
parent
d5adb85e5b
commit
78c7ee247a
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
;
|
;
|
||||||
|
Loading…
Reference in New Issue
Block a user