From 35aebbc2093943d9b52cc2abd03865beb46ab708 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 12 Sep 2020 02:48:16 +0200 Subject: [PATCH] optimize unneeded type casts for register args --- .../compiler/BeforeAsmGenerationAstChanger.kt | 13 +++++++++ .../c64/codegen/assignment/AsmAssignment.kt | 3 +- .../codegen/assignment/AssignmentAsmGen.kt | 28 ++++++++++++++----- .../assignment/AugmentableAssignmentAsmGen.kt | 4 +-- examples/mandelbrot-gfx.p8 | 2 +- examples/tehtriz.p8 | 1 + examples/test.p8 | 2 +- examples/turtle-gfx.p8 | 3 ++ 8 files changed, 44 insertions(+), 12 deletions(-) diff --git a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt index 02335fa2a..bfb6eaf78 100644 --- a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt +++ b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt @@ -1,5 +1,6 @@ package prog8.compiler +import prog8.ast.IFunctionCall import prog8.ast.Node import prog8.ast.Program 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, // 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. + // 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(typecast.type==DataType.UWORD) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt index b9238d030..e7e4b9769 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt @@ -159,6 +159,7 @@ internal class AsmAssignment(val source: AsmAssignSource, val position: Position) { 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"} } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt index e89564279..9d1c9e5a6 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -262,7 +262,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen 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.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 -> { @@ -571,19 +573,25 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.A -> {} RegisterOrPair.X -> { asmgen.out(" tax") } 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!!) { RegisterOrPair.A -> { asmgen.out(" txa") } RegisterOrPair.X -> { } 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!!) { RegisterOrPair.A -> { asmgen.out(" tya") } RegisterOrPair.X -> { asmgen.out(" tyx") } 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.X -> asmgen.out(" ldx #${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 -> { asmgen.out(""" @@ -847,7 +857,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.A -> asmgen.out(" lda ${address.toHex()}") RegisterOrPair.X -> asmgen.out(" ldx ${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 -> { asmgen.out(""" @@ -875,7 +887,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.A -> {} RegisterOrPair.X -> asmgen.out(" tax") 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 -> { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt index 0277d8675..b229c6755 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -23,8 +23,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, // A = -A , A = +A, A = ~A, A = not A val type = value.inferType(program).typeOrElse(DataType.STRUCT) when (value.operator) { - "+" -> { - } + "+" -> {} "-" -> inplaceNegate(assign.target, type) "~" -> inplaceInvert(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 { + // TODO doesn't always remove casts for instance uword xx = xb generates complex stack based type cast evaluation... if (target.datatype == value.type) { val childDt = value.expression.inferType(program).typeOrElse(DataType.STRUCT) if (value.type.equalsSize(childDt) || value.type.largerThan(childDt)) { diff --git a/examples/mandelbrot-gfx.p8 b/examples/mandelbrot-gfx.p8 index 4103e4095..cb70ab52a 100644 --- a/examples/mandelbrot-gfx.p8 +++ b/examples/mandelbrot-gfx.p8 @@ -38,7 +38,7 @@ main { } if iter & 1 - graphics.plot(pixelx, pixely) ; TODO get rid of typecast in pixelx arg + graphics.plot(pixelx, pixely) } } diff --git a/examples/tehtriz.p8 b/examples/tehtriz.p8 index bb225a9ae..b00edf84d 100644 --- a/examples/tehtriz.p8 +++ b/examples/tehtriz.p8 @@ -248,6 +248,7 @@ waitkey: c64.CHROUT('K') while c64.GETIN()!=133 { + ; TODO FIX THIS, DOESN'T TRIGGER ANYMORE ON F1 ; endless loop until user presses F1 to restart the game } } diff --git a/examples/test.p8 b/examples/test.p8 index fb84e0803..db8039cfc 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,6 +3,7 @@ ;%import c64flt ;%option enable_floats ; %zeropage kernalsafe +; TODO system reset should also work when kernal is paged out main { @@ -18,7 +19,6 @@ main { ; sub color(...) {} ; sub other(ubyte color) {} ; TODO don't cause name conflict - } } diff --git a/examples/turtle-gfx.p8 b/examples/turtle-gfx.p8 index dea3647d0..c2826bfbb 100644 --- a/examples/turtle-gfx.p8 +++ b/examples/turtle-gfx.p8 @@ -3,6 +3,9 @@ main { + ; TODO this program gets corrupted graphics and crashes near the end + + sub start() { graphics.enable_bitmap_mode() turtle.init()