optimize unneeded type casts for register args

This commit is contained in:
Irmen de Jong 2020-09-12 02:48:16 +02:00
parent 81f7419f70
commit 35aebbc209
8 changed files with 44 additions and 12 deletions

View File

@ -1,5 +1,6 @@
package prog8.compiler package prog8.compiler
import prog8.ast.IFunctionCall
import prog8.ast.Node import prog8.ast.Node
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.* import prog8.ast.base.*
@ -114,6 +115,18 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
// that the types of assignment values and their target are the same, // that the types of assignment values and their target are the same,
// and that the types of both operands of a binaryexpression node are the same. // and that the types of both operands of a binaryexpression node are the same.
// So, it is not easily possible to remove the typecasts that are there to make these conditions true. // So, it is not easily possible to remove the typecasts that are there to make these conditions true.
// The only place for now where we can do this is for:
// asmsub register pair parameter.
if(typecast.type in WordDatatypes) {
val fcall = typecast.parent as? IFunctionCall
if (fcall != null) {
val sub = fcall.target.targetStatement(program.namespace) as? Subroutine
if (sub != null && sub.isAsmSubroutine) {
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
}
}
}
if(sourceDt in PassByReferenceDatatypes) { if(sourceDt in PassByReferenceDatatypes) {
if(typecast.type==DataType.UWORD) { if(typecast.type==DataType.UWORD) {

View File

@ -159,6 +159,7 @@ internal class AsmAssignment(val source: AsmAssignSource,
val position: Position) { val position: Position) {
init { init {
require(source.datatype==target.datatype) {"source and target datatype must be identical"} if(target.register !in setOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY))
require(source.datatype==target.datatype) {"source and target datatype must be identical"}
} }
} }

View File

@ -262,7 +262,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
RegisterOrPair.A -> asmgen.out(" inx | lda P8ESTACK_LO,x") RegisterOrPair.A -> asmgen.out(" inx | lda P8ESTACK_LO,x")
RegisterOrPair.X -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}") RegisterOrPair.X -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
RegisterOrPair.Y -> asmgen.out(" inx | ldy P8ESTACK_LO,x") RegisterOrPair.Y -> asmgen.out(" inx | ldy P8ESTACK_LO,x")
else -> throw AssemblyError("can't assign byte to register pair word") RegisterOrPair.AX -> asmgen.out(" inx | lda P8ESTACK_LO,x | ldx #0")
RegisterOrPair.AY -> asmgen.out(" inx | lda P8ESTACK_LO,x | ldy #0")
else -> throw AssemblyError("can't assign byte from stack to register pair XY")
} }
} }
DataType.UWORD, DataType.WORD, in PassByReferenceDatatypes -> { DataType.UWORD, DataType.WORD, in PassByReferenceDatatypes -> {
@ -571,19 +573,25 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
RegisterOrPair.A -> {} RegisterOrPair.A -> {}
RegisterOrPair.X -> { asmgen.out(" tax") } RegisterOrPair.X -> { asmgen.out(" tax") }
RegisterOrPair.Y -> { asmgen.out(" tay") } RegisterOrPair.Y -> { asmgen.out(" tay") }
else -> throw AssemblyError("attempt to assign byte to register pair word") RegisterOrPair.AY -> { asmgen.out(" ldy #0") }
RegisterOrPair.AX -> { asmgen.out(" ldx #0") }
RegisterOrPair.XY -> { asmgen.out(" tax | ldy #0") }
} }
CpuRegister.X -> when(target.register!!) { CpuRegister.X -> when(target.register!!) {
RegisterOrPair.A -> { asmgen.out(" txa") } RegisterOrPair.A -> { asmgen.out(" txa") }
RegisterOrPair.X -> { } RegisterOrPair.X -> { }
RegisterOrPair.Y -> { asmgen.out(" txy") } RegisterOrPair.Y -> { asmgen.out(" txy") }
else -> throw AssemblyError("attempt to assign byte to register pair word") RegisterOrPair.AY -> { asmgen.out(" txa | ldy #0") }
RegisterOrPair.AX -> { asmgen.out(" txa | ldx #0") }
RegisterOrPair.XY -> { asmgen.out(" ldy #0") }
} }
CpuRegister.Y -> when(target.register!!) { CpuRegister.Y -> when(target.register!!) {
RegisterOrPair.A -> { asmgen.out(" tya") } RegisterOrPair.A -> { asmgen.out(" tya") }
RegisterOrPair.X -> { asmgen.out(" tyx") } RegisterOrPair.X -> { asmgen.out(" tyx") }
RegisterOrPair.Y -> { } RegisterOrPair.Y -> { }
else -> throw AssemblyError("attempt to assign byte to register pair word") RegisterOrPair.AY -> { asmgen.out(" tya | ldy #0") }
RegisterOrPair.AX -> { asmgen.out(" tya | ldx #0") }
RegisterOrPair.XY -> { asmgen.out(" tya | tax | ldy #0") }
} }
} }
} }
@ -692,7 +700,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
RegisterOrPair.A -> asmgen.out(" lda #${byte.toHex()}") RegisterOrPair.A -> asmgen.out(" lda #${byte.toHex()}")
RegisterOrPair.X -> asmgen.out(" ldx #${byte.toHex()}") RegisterOrPair.X -> asmgen.out(" ldx #${byte.toHex()}")
RegisterOrPair.Y -> asmgen.out(" ldy #${byte.toHex()}") RegisterOrPair.Y -> asmgen.out(" ldy #${byte.toHex()}")
else -> throw AssemblyError("can't assign byte to word register apir") RegisterOrPair.AX -> asmgen.out(" lda #${byte.toHex()} | ldx #0")
RegisterOrPair.AY -> asmgen.out(" lda #${byte.toHex()} | ldy #0")
RegisterOrPair.XY -> asmgen.out(" ldx #${byte.toHex()} | ldy #0")
} }
TargetStorageKind.STACK -> { TargetStorageKind.STACK -> {
asmgen.out(""" asmgen.out("""
@ -847,7 +857,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
RegisterOrPair.A -> asmgen.out(" lda ${address.toHex()}") RegisterOrPair.A -> asmgen.out(" lda ${address.toHex()}")
RegisterOrPair.X -> asmgen.out(" ldx ${address.toHex()}") RegisterOrPair.X -> asmgen.out(" ldx ${address.toHex()}")
RegisterOrPair.Y -> asmgen.out(" ldy ${address.toHex()}") RegisterOrPair.Y -> asmgen.out(" ldy ${address.toHex()}")
else -> throw AssemblyError("can't assign byte to word register apir") RegisterOrPair.AX -> asmgen.out(" lda ${address.toHex()} | ldx #0")
RegisterOrPair.AY -> asmgen.out(" lda ${address.toHex()} | ldy #0")
RegisterOrPair.XY -> asmgen.out(" ldy ${address.toHex()} | ldy #0")
} }
TargetStorageKind.STACK -> { TargetStorageKind.STACK -> {
asmgen.out(""" asmgen.out("""
@ -875,7 +887,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
RegisterOrPair.A -> {} RegisterOrPair.A -> {}
RegisterOrPair.X -> asmgen.out(" tax") RegisterOrPair.X -> asmgen.out(" tax")
RegisterOrPair.Y -> asmgen.out(" tay") RegisterOrPair.Y -> asmgen.out(" tay")
else -> throw AssemblyError("can't assign byte to word register apir") RegisterOrPair.AX -> asmgen.out(" ldx #0")
RegisterOrPair.AY -> asmgen.out(" ldy #0")
RegisterOrPair.XY -> asmgen.out(" tax | ldy #0")
} }
} }
TargetStorageKind.STACK -> { TargetStorageKind.STACK -> {

View File

@ -23,8 +23,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
// A = -A , A = +A, A = ~A, A = not A // A = -A , A = +A, A = ~A, A = not A
val type = value.inferType(program).typeOrElse(DataType.STRUCT) val type = value.inferType(program).typeOrElse(DataType.STRUCT)
when (value.operator) { when (value.operator) {
"+" -> { "+" -> {}
}
"-" -> inplaceNegate(assign.target, type) "-" -> inplaceNegate(assign.target, type)
"~" -> inplaceInvert(assign.target, type) "~" -> inplaceInvert(assign.target, type)
"not" -> inplaceBooleanNot(assign.target, type) "not" -> inplaceBooleanNot(assign.target, type)
@ -219,6 +218,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
} }
private fun tryRemoveRedundantCast(value: TypecastExpression, target: AsmAssignTarget, operator: String): Boolean { private fun tryRemoveRedundantCast(value: TypecastExpression, target: AsmAssignTarget, operator: String): Boolean {
// TODO doesn't always remove casts for instance uword xx = xb generates complex stack based type cast evaluation...
if (target.datatype == value.type) { if (target.datatype == value.type) {
val childDt = value.expression.inferType(program).typeOrElse(DataType.STRUCT) val childDt = value.expression.inferType(program).typeOrElse(DataType.STRUCT)
if (value.type.equalsSize(childDt) || value.type.largerThan(childDt)) { if (value.type.equalsSize(childDt) || value.type.largerThan(childDt)) {

View File

@ -38,7 +38,7 @@ main {
} }
if iter & 1 if iter & 1
graphics.plot(pixelx, pixely) ; TODO get rid of typecast in pixelx arg graphics.plot(pixelx, pixely)
} }
} }

View File

@ -248,6 +248,7 @@ waitkey:
c64.CHROUT('K') c64.CHROUT('K')
while c64.GETIN()!=133 { while c64.GETIN()!=133 {
; TODO FIX THIS, DOESN'T TRIGGER ANYMORE ON F1
; endless loop until user presses F1 to restart the game ; endless loop until user presses F1 to restart the game
} }
} }

View File

@ -3,6 +3,7 @@
;%import c64flt ;%import c64flt
;%option enable_floats ;%option enable_floats
; %zeropage kernalsafe ; %zeropage kernalsafe
; TODO system reset should also work when kernal is paged out
main { main {
@ -18,7 +19,6 @@ main {
; sub color(...) {} ; sub color(...) {}
; sub other(ubyte color) {} ; TODO don't cause name conflict ; sub other(ubyte color) {} ; TODO don't cause name conflict
} }
} }

View File

@ -3,6 +3,9 @@
main { main {
; TODO this program gets corrupted graphics and crashes near the end
sub start() { sub start() {
graphics.enable_bitmap_mode() graphics.enable_bitmap_mode()
turtle.init() turtle.init()