micro optimization to save 2 cycles: change some pha+pla into tax+txa

This commit is contained in:
Irmen de Jong 2023-09-01 20:27:39 +02:00
parent 9cc0cda0fb
commit f14ea1b3de
7 changed files with 74 additions and 73 deletions

View File

@ -742,11 +742,11 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.out(""" asmgen.out("""
ldy #0 ldy #0
lda ($varname),y lda ($varname),y
pha tax
iny iny
lda ($varname),y lda ($varname),y
tay tay
pla""") txa""")
} }
} else fallback() } else fallback()
} }
@ -759,11 +759,11 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y) asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y)
asmgen.out(""" asmgen.out("""
lda ($varname),y lda ($varname),y
pha tax
iny iny
lda ($varname),y lda ($varname),y
tay tay
pla""") txa""")
} else fallback() } else fallback()
} }
else -> fallback() else -> fallback()

View File

@ -255,11 +255,11 @@ $loopLabel""")
sec sec
sbc #<${stepsize.absoluteValue} sbc #<${stepsize.absoluteValue}
sta $varname sta $varname
pha tax
lda $varname+1 lda $varname+1
sbc #>${stepsize.absoluteValue} sbc #>${stepsize.absoluteValue}
sta $varname+1 sta $varname+1
pla txa
$modifiedLabel2 cmp #0 ; modified $modifiedLabel2 cmp #0 ; modified
lda $varname+1 lda $varname+1
$modifiedLabel sbc #0 ; modified $modifiedLabel sbc #0 ; modified

View File

@ -142,12 +142,12 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as
is PtIdentifier -> { is PtIdentifier -> {
val sourceName = asmgen.asmVariableName(value) val sourceName = asmgen.asmVariableName(value)
asmgen.out(""" asmgen.out("""
pha tax
clc clc
lda $sourceName lda $sourceName
beq + beq +
sec sec
+ pla""") + txa""")
} }
else -> { else -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.A) asmgen.assignExpressionToRegister(value, RegisterOrPair.A)

View File

@ -88,7 +88,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignRegisterpairWord(assign.target, RegisterOrPair.AY) assignRegisterpairWord(assign.target, RegisterOrPair.AY)
} else { } else {
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y) asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
asmgen.out(" lda ${arrayVarName}_lsb,y | pha | lda ${arrayVarName}_msb,y | tay | pla") asmgen.out(" lda ${arrayVarName}_lsb,y | tax | lda ${arrayVarName}_msb,y | tay | txa")
assignRegisterpairWord(assign.target, RegisterOrPair.AY) assignRegisterpairWord(assign.target, RegisterOrPair.AY)
} }
return return
@ -122,7 +122,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
in WordDatatypes -> { in WordDatatypes -> {
asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y) asmgen.loadScaledArrayIndexIntoRegister(value, elementDt, CpuRegister.Y)
asmgen.out(" lda $arrayVarName,y | pha | lda $arrayVarName+1,y | tay | pla") asmgen.out(" lda $arrayVarName,y | tax | lda $arrayVarName+1,y | tay | txa")
assignRegisterpairWord(assign.target, RegisterOrPair.AY) assignRegisterpairWord(assign.target, RegisterOrPair.AY)
} }
DataType.FLOAT -> { DataType.FLOAT -> {
@ -257,12 +257,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
when (assign.target.datatype) { when (assign.target.datatype) {
DataType.STR -> { DataType.STR -> {
asmgen.out(""" asmgen.out("""
pha tax
lda #<${assign.target.asmVarname} lda #<${assign.target.asmVarname}
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda #>${assign.target.asmVarname} lda #>${assign.target.asmVarname}
sta P8ZP_SCRATCH_W1+1 sta P8ZP_SCRATCH_W1+1
pla txa
jsr prog8_lib.strcpy""") jsr prog8_lib.strcpy""")
} }
DataType.UWORD -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) DataType.UWORD -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
@ -306,14 +306,14 @@ internal class AssignmentAsmGen(private val program: PtProgram,
sec sec
eor #255 eor #255
adc #0 adc #0
pha tax
tya tya
eor #255 eor #255
adc #0 adc #0
tay tay
pla""") txa""")
} }
"~" -> asmgen.out(" pha | tya | eor #255 | tay | pla | eor #255") "~" -> asmgen.out(" tax | tya | eor #255 | tay | txa | eor #255")
"not" -> throw AssemblyError("not should have been replaced in the Ast by ==0") "not" -> throw AssemblyError("not should have been replaced in the Ast by ==0")
else -> throw AssemblyError("invalid prefix operator") else -> throw AssemblyError("invalid prefix operator")
} }
@ -759,20 +759,20 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.out(""" asmgen.out("""
clc clc
adc P8ZP_SCRATCH_W1 adc P8ZP_SCRATCH_W1
pha tax
tya tya
adc P8ZP_SCRATCH_W1+1 adc P8ZP_SCRATCH_W1+1
tay tay
pla""") txa""")
else else
asmgen.out(""" asmgen.out("""
sec sec
sbc P8ZP_SCRATCH_W1 sbc P8ZP_SCRATCH_W1
pha tax
tya tya
sbc P8ZP_SCRATCH_W1+1 sbc P8ZP_SCRATCH_W1+1
tay tay
pla""") txa""")
assignRegisterpairWord(target, RegisterOrPair.AY) assignRegisterpairWord(target, RegisterOrPair.AY)
} }
@ -784,20 +784,20 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.out(""" asmgen.out("""
clc clc
adc #<$symbol adc #<$symbol
pha tax
tya tya
adc #>$symbol adc #>$symbol
tay tay
pla""") txa""")
else else
asmgen.out(""" asmgen.out("""
sec sec
sbc #<$symbol sbc #<$symbol
pha tax
tya tya
sbc #>$symbol sbc #>$symbol
tay tay
pla""") txa""")
assignRegisterpairWord(target, RegisterOrPair.AY) assignRegisterpairWord(target, RegisterOrPair.AY)
return true return true
} }
@ -808,20 +808,20 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.out(""" asmgen.out("""
clc clc
adc $symname adc $symname
pha tax
tya tya
adc $symname+1 adc $symname+1
tay tay
pla""") txa""")
else else
asmgen.out(""" asmgen.out("""
sec sec
sbc $symname sbc $symname
pha tax
tya tya
sbc $symname+1 sbc $symname+1
tay tay
pla""") txa""")
assignRegisterpairWord(target, RegisterOrPair.AY) assignRegisterpairWord(target, RegisterOrPair.AY)
return true return true
} }
@ -831,20 +831,20 @@ internal class AssignmentAsmGen(private val program: PtProgram,
asmgen.out(""" asmgen.out("""
clc clc
adc #<${right.number.toHex()} adc #<${right.number.toHex()}
pha tax
tya tya
adc #>${right.number.toHex()} adc #>${right.number.toHex()}
tay tay
pla""") txa""")
} else if(expr.operator=="-") { } else if(expr.operator=="-") {
asmgen.out(""" asmgen.out("""
sec sec
sbc #<${right.number.toHex()} sbc #<${right.number.toHex()}
pha tax
tya tya
sbc #>${right.number.toHex()} sbc #>${right.number.toHex()}
tay tay
pla""") txa""")
} }
assignRegisterpairWord(target, RegisterOrPair.AY) assignRegisterpairWord(target, RegisterOrPair.AY)
return true return true
@ -926,9 +926,9 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1") asmgen.assignWordOperandsToAYAndVar(expr.left, expr.right, "P8ZP_SCRATCH_W1")
when (expr.operator) { when (expr.operator) {
"&", "and" -> asmgen.out(" and P8ZP_SCRATCH_W1 | pha | tya | and P8ZP_SCRATCH_W1+1 | tay | pla") "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_W1 | tax | tya | and P8ZP_SCRATCH_W1+1 | tay | txa")
"|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_W1 | pha | tya | ora P8ZP_SCRATCH_W1+1 | tay | pla") "|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_W1 | tax | tya | ora P8ZP_SCRATCH_W1+1 | tay | txa")
"^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_W1 | pha | tya | eor P8ZP_SCRATCH_W1+1 | tay | pla") "^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_W1 | tax | tya | eor P8ZP_SCRATCH_W1+1 | tay | txa")
else -> throw AssemblyError("invalid operator") else -> throw AssemblyError("invalid operator")
} }
assignRegisterpairWord(target, RegisterOrPair.AY) assignRegisterpairWord(target, RegisterOrPair.AY)
@ -1489,18 +1489,18 @@ internal class AssignmentAsmGen(private val program: PtProgram,
is PtNumber -> { is PtNumber -> {
val number = right.number.toHex() val number = right.number.toHex()
when (operator) { when (operator) {
"&", "and" -> asmgen.out(" and #<$number | pha | tya | and #>$number | tay | pla") "&", "and" -> asmgen.out(" and #<$number | tax | tya | and #>$number | tay | txa")
"|", "or" -> asmgen.out(" ora #<$number | pha | tya | ora #>$number | tay | pla") "|", "or" -> asmgen.out(" ora #<$number | tax | tya | ora #>$number | tay | txa")
"^", "xor" -> asmgen.out(" eor #<$number | pha | tya | eor #>$number | tay | pla") "^", "xor" -> asmgen.out(" eor #<$number | tax | tya | eor #>$number | tay | txa")
else -> throw AssemblyError("invalid operator") else -> throw AssemblyError("invalid operator")
} }
} }
is PtIdentifier -> { is PtIdentifier -> {
val name = asmgen.asmSymbolName(right) val name = asmgen.asmSymbolName(right)
when (operator) { when (operator) {
"&", "and" -> asmgen.out(" and $name | pha | tya | and $name+1 | tay | pla") "&", "and" -> asmgen.out(" and $name | tax | tya | and $name+1 | tay | txa")
"|", "or" -> asmgen.out(" ora $name | pha | tya | ora $name+1 | tay | pla") "|", "or" -> asmgen.out(" ora $name | tax | tya | ora $name+1 | tay | txa")
"^", "xor" -> asmgen.out(" eor $name | pha | tya | eor $name+1 | tay | pla") "^", "xor" -> asmgen.out(" eor $name | tax | tya | eor $name+1 | tay | txa")
else -> throw AssemblyError("invalid operator") else -> throw AssemblyError("invalid operator")
} }
} }
@ -1510,6 +1510,11 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { private fun attemptAssignToByteCompareZero(expr: PtBinaryExpression, assign: AsmAssignment): Boolean {
// TODO optimized code for (word1 & word2) == 0 :
// if(expr.left.type in WordDatatypes && (expr.operator=="==" || expr.operator=="!=") && expr.left is PtBinaryExpression) {
// ...
// }
when (expr.operator) { when (expr.operator) {
"==" -> { "==" -> {
when(val dt = expr.left.type) { when(val dt = expr.left.type) {
@ -2095,12 +2100,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
if(regs!=RegisterOrPair.AY) if(regs!=RegisterOrPair.AY)
throw AssemblyError("only supports AY here") throw AssemblyError("only supports AY here")
asmgen.out(""" asmgen.out("""
pha tax
lda #<$targetAsmVarName lda #<$targetAsmVarName
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
lda #>$targetAsmVarName lda #>$targetAsmVarName
sta P8ZP_SCRATCH_W2+1 sta P8ZP_SCRATCH_W2+1
pla txa
jsr floats.cast_from_uw""") jsr floats.cast_from_uw""")
} }
else -> throw AssemblyError("weird type") else -> throw AssemblyError("weird type")
@ -2123,12 +2128,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
if(regs!=RegisterOrPair.AY) if(regs!=RegisterOrPair.AY)
throw AssemblyError("only supports AY here") throw AssemblyError("only supports AY here")
asmgen.out(""" asmgen.out("""
pha tax
lda #<$targetAsmVarName lda #<$targetAsmVarName
sta P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2
lda #>$targetAsmVarName lda #>$targetAsmVarName
sta P8ZP_SCRATCH_W2+1 sta P8ZP_SCRATCH_W2+1
pla txa
jsr floats.cast_from_w""") jsr floats.cast_from_w""")
} }
else -> throw AssemblyError("weird type") else -> throw AssemblyError("weird type")
@ -2562,12 +2567,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
pla""") pla""")
RegisterOrPair.AY -> asmgen.out(""" RegisterOrPair.AY -> asmgen.out("""
lda $sourceName lda $sourceName
pha tax
ora #$7f ora #$7f
bmi + bmi +
lda #0 lda #0
+ tay + tay
pla""") txa""")
RegisterOrPair.XY -> asmgen.out(""" RegisterOrPair.XY -> asmgen.out("""
lda $sourceName lda $sourceName
tax tax
@ -3770,12 +3775,12 @@ internal class AssignmentAsmGen(private val program: PtProgram,
sec sec
eor #255 eor #255
adc #0 adc #0
pha tax
tya tya
eor #255 eor #255
adc #0 adc #0
tay tay
pla""") txa""")
} }
RegisterOrPair.XY -> { RegisterOrPair.XY -> {
asmgen.out(""" asmgen.out("""

View File

@ -415,8 +415,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
} }
} }
asmgen.out(""" asmgen.out("""
lda P8ZP_SCRATCH_W1 ldx P8ZP_SCRATCH_W1
pha
lda P8ZP_SCRATCH_W1+1 lda P8ZP_SCRATCH_W1+1
pha pha
lda #<$tempvar lda #<$tempvar
@ -424,7 +423,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1 sty P8ZP_SCRATCH_W1+1
ply ply
pla txa
jsr floats.copy_float""") // copy from array into float temp var, clobbers A,Y jsr floats.copy_float""") // copy from array into float temp var, clobbers A,Y
} }
else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}") else -> throw AssemblyError("weird type to do in-place modification on ${target.datatype}")
@ -445,11 +444,11 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.out(""" asmgen.out("""
clc clc
adc $variable adc $variable
pha tay
txa txa
adc $variable+1 adc $variable+1
tax tax
pla""") tya""")
true true
} else { } else {
asmgen.out(""" asmgen.out("""
@ -469,11 +468,11 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.out(""" asmgen.out("""
sec sec
sbc $variable sbc $variable
pha tay
txa txa
sbc $variable+1 sbc $variable+1
tax tax
pla""") tya""")
true true
} else { } else {
asmgen.out(""" asmgen.out("""
@ -508,11 +507,11 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.out(""" asmgen.out("""
clc clc
adc #<$number adc #<$number
pha tay
txa txa
adc #>$number adc #>$number
tax tax
pla""") tya""")
true true
} }
} }
@ -529,11 +528,11 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
asmgen.out(""" asmgen.out("""
sec sec
sbc #<$number sbc #<$number
pha tay
txa txa
sbc #>$number sbc #>$number
tax tax
pla""") tya""")
true true
} }
} }
@ -1990,12 +1989,12 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
fun divideVarByWordInAY() { fun divideVarByWordInAY() {
asmgen.out(""" asmgen.out("""
pha tax
lda $name lda $name
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda $name+1 lda $name+1
sta P8ZP_SCRATCH_W1+1 sta P8ZP_SCRATCH_W1+1
pla""") txa""")
if (dt == DataType.WORD) if (dt == DataType.WORD)
asmgen.out(" jsr math.divmod_w_asm") asmgen.out(" jsr math.divmod_w_asm")
else else
@ -2007,12 +2006,12 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram,
if(dt==DataType.WORD) if(dt==DataType.WORD)
throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead") throw AssemblyError("remainder of signed integers is not properly defined/implemented, use unsigned instead")
asmgen.out(""" asmgen.out("""
pha tax
lda $name lda $name
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
lda $name+1 lda $name+1
sta P8ZP_SCRATCH_W1+1 sta P8ZP_SCRATCH_W1+1
pla txa
jsr math.divmod_uw_asm jsr math.divmod_uw_asm
lda P8ZP_SCRATCH_W2 lda P8ZP_SCRATCH_W2
ldy P8ZP_SCRATCH_W2+1 ldy P8ZP_SCRATCH_W2+1

View File

@ -41,6 +41,7 @@ sprites {
} }
sub pos_batch(ubyte first_spritenum, ubyte num_sprites, uword xpositions_ptr, uword ypositions_ptr) { sub pos_batch(ubyte first_spritenum, ubyte num_sprites, uword xpositions_ptr, uword ypositions_ptr) {
; -- note: the x and y positions word arrays must be regular arrays, they cannot be @split arrays!
sprite_reg = VERA_SPRITEREGS + 2 + first_spritenum*$0008 sprite_reg = VERA_SPRITEREGS + 2 + first_spritenum*$0008
cx16.vaddr_autoincr(1, sprite_reg, 0, 8) cx16.vaddr_autoincr(1, sprite_reg, 0, 8)
cx16.vaddr_autoincr(1, sprite_reg+1, 1, 8) cx16.vaddr_autoincr(1, sprite_reg+1, 1, 8)

View File

@ -1,11 +1,6 @@
TODO TODO
==== ====
- optimize assembly output for ( word1 & word2 ==0) ... (no need for stack pushes)
- opimize assembly where pha/pla can be converted into tax/txa (saves 2 cycles, clobbers X)
- prefix prog8 subroutines with p8s_ instead of p8_ to not let them clash with variables in the asm? - prefix prog8 subroutines with p8s_ instead of p8_ to not let them clash with variables in the asm?
- allow 'chained' array indexing for expressions: value = ptrarray[0][0] - allow 'chained' array indexing for expressions: value = ptrarray[0][0]
- allow 'chained' array indexing for assign targets: ptrarray[0][0] = 42 this is just evaluating the lhs as a uword pointer expression - allow 'chained' array indexing for assign targets: ptrarray[0][0] = 42 this is just evaluating the lhs as a uword pointer expression
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
@ -61,6 +56,7 @@ Libraries:
Optimizations: Optimizations:
- optimize assembly output for ( word1 & word2 ==0) ... (no need for stack pushes) see attemptAssignToByteCompareZero().
- 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,