From 5ecf2a33578316bc800d503ac74369e56f4a8890 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 27 Jan 2022 18:05:25 +0100 Subject: [PATCH] enable more optimizations for typecasted assignments. Fixed missing codegen for assigning bytes to words in certain cases. --- .../cpu6502/codegen/BuiltinFunctionsAsmGen.kt | 20 ++++++++ .../codegen/assignment/AssignmentAsmGen.kt | 27 ++++++++-- compiler/test/TestTypecasts.kt | 51 ++++++++++++++++++- .../prog8/ast/expressions/AstExpressions.kt | 2 +- docs/source/todo.rst | 17 ++++++- examples/cx16/sincos.p8 | 8 +-- examples/test.p8 | 29 ++++++----- 7 files changed, 127 insertions(+), 27 deletions(-) diff --git a/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt b/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt index ab13cef8e..7a2964d50 100644 --- a/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt +++ b/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt @@ -1584,6 +1584,16 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val null, RegisterOrPair.A -> asmgen.out(" lda $sourceName+1") RegisterOrPair.X -> asmgen.out(" ldx $sourceName+1") RegisterOrPair.Y -> asmgen.out(" ldy $sourceName+1") + RegisterOrPair.AX -> asmgen.out(" lda $sourceName+1 | ldx #0") + RegisterOrPair.AY -> asmgen.out(" lda $sourceName+1 | ldy #0") + RegisterOrPair.XY -> asmgen.out(" ldx $sourceName+1 | ldy #0") + in Cx16VirtualRegisters -> { + val regname = resultRegister.name.lowercase() + if(asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(" lda $sourceName+1 | sta cx16.$regname | stz cx16.$regname+1") + else + asmgen.out(" lda $sourceName+1 | sta cx16.$regname | lda #0 | sta cx16.$regname+1") + } else -> throw AssemblyError("invalid reg") } } @@ -1629,6 +1639,16 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val null, RegisterOrPair.A -> asmgen.out(" lda $sourceName") RegisterOrPair.X -> asmgen.out(" ldx $sourceName") RegisterOrPair.Y -> asmgen.out(" ldy $sourceName") + RegisterOrPair.AX -> asmgen.out(" lda $sourceName | ldx #0") + RegisterOrPair.AY -> asmgen.out(" lda $sourceName | ldy #0") + RegisterOrPair.XY -> asmgen.out(" ldx $sourceName | ldy #0") + in Cx16VirtualRegisters -> { + val regname = resultRegister.name.lowercase() + if(asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(" lda $sourceName | sta cx16.$regname | stz cx16.$regname+1") + else + asmgen.out(" lda $sourceName | sta cx16.$regname | lda #0 | sta cx16.$regname+1") + } else -> throw AssemblyError("invalid reg") } } diff --git a/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt b/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt index de75245e1..b8c351715 100644 --- a/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt +++ b/codeGeneration/src/prog8/codegen/target/cpu6502/codegen/assignment/AssignmentAsmGen.kt @@ -1520,7 +1520,7 @@ $containsLabel lda #1 pha ora #$7f bmi + - ldx #0 + lda #0 + tax pla""") RegisterOrPair.AY -> asmgen.out(""" @@ -1528,7 +1528,7 @@ $containsLabel lda #1 pha ora #$7f bmi + - ldy #0 + lda #0 + tay pla""") RegisterOrPair.XY -> asmgen.out(""" @@ -1536,9 +1536,19 @@ $containsLabel lda #1 tax ora #$7f bmi + - ldy #0 + lda #0 + tay""") - else -> throw AssemblyError("only reg pairs are words") + in Cx16VirtualRegisters -> { + val regname = wordtarget.register.name.lowercase() + asmgen.out(""" + lda $sourceName + sta cx16.$regname + ora #$7f + bmi + + lda #0 ++ sta cx16.$regname+1""") + } + else -> throw AssemblyError("only reg pairs allowed as word target ${wordtarget.register}") } } TargetStorageKind.STACK -> { @@ -1589,7 +1599,14 @@ $containsLabel lda #1 RegisterOrPair.AX -> asmgen.out(" ldx #0 | lda $sourceName") RegisterOrPair.AY -> asmgen.out(" ldy #0 | lda $sourceName") RegisterOrPair.XY -> asmgen.out(" ldy #0 | ldx $sourceName") - else -> throw AssemblyError("only reg pairs are words") + in Cx16VirtualRegisters -> { + val regname = wordtarget.register.name.lowercase() + if(asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(" lda $sourceName | sta cx16.$regname | stz cx16.$regname+1") + else + asmgen.out(" lda $sourceName | sta cx16.$regname | lda #0 | sta cx16.$regname+1") + } + else -> throw AssemblyError("only reg pairs allowed as word target") } } TargetStorageKind.STACK -> { diff --git a/compiler/test/TestTypecasts.kt b/compiler/test/TestTypecasts.kt index 705715f5a..5f354e9df 100644 --- a/compiler/test/TestTypecasts.kt +++ b/compiler/test/TestTypecasts.kt @@ -181,9 +181,8 @@ class TestTypecasts: FunSpec({ } }""" val result = compileText(C64Target, false, text, writeAssembly = true).assertSuccess() - printProgram(result.program) val statements = result.program.entrypoint.statements - statements.size shouldBe 16 + statements.size shouldBe 14 } test("no infinite typecast loop in assignment asmgen") { @@ -200,4 +199,52 @@ class TestTypecasts: FunSpec({ """ compileText(C64Target, false, text, writeAssembly = true).assertSuccess() } + + test("(u)byte extend to word parameters") { + val text = """ + main { + sub start() { + byte ub1 = -50 + byte ub2 = -51 + byte ub3 = -52 + byte ub4 = 100 + word @shared ww = func(ub1, ub2, ub3, ub4) + ww = func(ub4, ub2, ub3, ub1) + ww=afunc(ub1, ub2, ub3, ub4) + ww=afunc(ub4, ub2, ub3, ub1) + } + + sub func(word x1, word y1, word x2, word y2) -> word { + return x1 + } + + asmsub afunc(word x1 @R0, word y1 @R1, word x2 @R2, word y2 @R3) -> word @AY { + %asm {{ + lda cx16.r0 + ldy cx16.r0+1 + rts + }} + } + }""" + compileText(C64Target, true, text, writeAssembly = true).assertSuccess() + } + + test("lsb msb used as args with word types") { + val text = """ + main { + sub start() { + uword xx=${'$'}ea31 + uword @shared ww = plot(lsb(xx), msb(xx)) + } + + inline asmsub plot(uword plotx @R0, uword ploty @R1) -> uword @AY{ + %asm {{ + lda cx16.r0 + ldy cx16.r1 + rts + }} + } + }""" + compileText(C64Target, true, text, writeAssembly = true).assertSuccess() + } }) diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 89b9e7e90..304adc24c 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -338,7 +338,7 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp expression.linkParents(this) } - override val isSimple = false + override val isSimple = expression.isSimple override fun replaceChildNode(node: Node, replacement: Node) { require(replacement is Expression && node===expression) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 56b51c94c..85620ad9f 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,22 @@ TODO For next release ^^^^^^^^^^^^^^^^ +fix the value of ww being wrong (with optimizations enabled) in : + sub start() { + byte ub1 = -50 + byte ub2 = -51 + byte ub3 = -52 + byte ub4 = -53 + word ww = func(ub1, ub2, ub3, ub4) + txt.print_w(ww) + } + + sub func(word x1, word y1, word x2, word y2) -> word { + return x1 + } + +- optimize w=msb(w), w=lsb(w) + ... @@ -22,7 +38,6 @@ Blocked by an official Commander-x16 r39 release Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ - nameInAssemblyCode() should search smarter -- Typecastexpression.isSimple: make it 'expression.isSimple' rather than always false. (this breaks some things atm) - IdentifierReference: fix equality to also include position. CallGraph can then also only store IdentifierRef instead of pair(ident, position) as keys. - Fix: don't report as recursion if code assigns address of its own subroutine to something, rather than calling it - allow "xxx" * constexpr (where constexpr is not a number literal, now gives expression error not same type) diff --git a/examples/cx16/sincos.p8 b/examples/cx16/sincos.p8 index 30ecfd4a8..e27ea13b7 100644 --- a/examples/cx16/sincos.p8 +++ b/examples/cx16/sincos.p8 @@ -43,9 +43,9 @@ main { for pixelxb in 0 to 255 { pixelyw = cos16u(pixelxb) / 1024 + 120 - graphics.plot(pixelxb, lsb(pixelyw)) + graphics.plot(pixelxb, pixelyw) pixelyw = sin16u(pixelxb) / 1024 + 120 - graphics.plot(pixelxb, lsb(pixelyw)) + graphics.plot(pixelxb, pixelyw) } } @@ -65,9 +65,9 @@ main { for pixelxb in 0 to 179 { pixelyw = cosr16u(pixelxb) / 1024 + 120 - graphics.plot(pixelxb, lsb(pixelyw)) + graphics.plot(pixelxb, pixelyw) pixelyw = sinr16u(pixelxb) / 1024 + 120 - graphics.plot(pixelxb, lsb(pixelyw)) + graphics.plot(pixelxb, pixelyw) } } diff --git a/examples/test.p8 b/examples/test.p8 index b781b0192..3c87986a6 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,19 +4,20 @@ main { sub start() { - str s1 = "irmen" - ubyte ff = 1 - txt.print(&s1+ff) - txt.nl() - txt.print(&s1+ff) - txt.nl() - txt.print_uwhex(&s1+ff, true) - - - ubyte[] array = [1,2,3,4] - txt.print_uwhex(&array+ff, true) - txt.nl() - txt.print_uwhex(&array+ff, true) - txt.nl() + uword xx=$ea31 + xx = lsb(xx) + uword ww = plot(lsb(xx), msb(xx)) + ww=msb(ww) + txt.print_uwhex(ww, true) } + + inline asmsub plot(uword plotx @R0, uword ploty @R1) -> uword @AY{ + %asm {{ + lda cx16.r0 + ldy cx16.r1 + rts + }} + } + + }