From 238d8197f550a83bc63414f71f7c4b9fb37387d7 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 26 Nov 2020 01:11:31 +0100 Subject: [PATCH] byte/word typecasts optimized even further to just use cpu registers (and fixed sign extending AY) --- compiler/res/prog8lib/prog8_lib.asm | 1 - .../codegen/assignment/AssignmentAsmGen.kt | 166 +++++++++++++++++- examples/test.p8 | 112 ++---------- 3 files changed, 175 insertions(+), 104 deletions(-) diff --git a/compiler/res/prog8lib/prog8_lib.asm b/compiler/res/prog8lib/prog8_lib.asm index 64031d216..7cc9f46b7 100644 --- a/compiler/res/prog8lib/prog8_lib.asm +++ b/compiler/res/prog8lib/prog8_lib.asm @@ -1081,7 +1081,6 @@ sign_extend_stack_byte .proc sign_extend_AY_byte .proc ; -- sign extend the (signed) byte in AY to full 16 bits pha - tya and #$80 beq + ldy #$ff 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 9df2b8f78..abd243184 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -122,7 +122,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference) } else -> { - asmgen.assignExpressionToVariable(value.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope) + assignExpressionToVariable(value.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope) asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") assignRegisterByte(assign.target, CpuRegister.A) } @@ -272,18 +272,26 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen return assignTypeCastedIdentifier(target.asmVarname, targetDt, asmgen.asmVariableName(value), valueDt) when (valueDt) { - in ByteDatatypes, in WordDatatypes -> { - // TODO optimize byte/word typecasts even more by only using registers - asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", valueDt, null) - return assignTypeCastedIdentifier(target.asmVarname, targetDt, "P8ZP_SCRATCH_W1", valueDt) + in ByteDatatypes -> { + assignExpressionToRegister(value, RegisterOrPair.A) + return assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.A, valueDt) + } + in WordDatatypes -> { + assignExpressionToRegister(value, RegisterOrPair.AY) + return assignTypeCastedRegisters(target.asmVarname, targetDt, RegisterOrPair.AY, valueDt) } DataType.FLOAT -> { // float value cast, fall through and do it via stack for now - // TODO optimize float casts to not use stack + // because doing it with an intermediate variable uses up quite a few extra instructions at this point.. + // TODO re-enable float cast via var once expression code generation is more efficent? Or do it via FAC1 directly? +// val scope = value.definingSubroutine()!! +// scope.asmGenInfo.usedFloatEvalResultVar = true +// assignExpressionToVariable(value, subroutineFloatEvalResultVar, valueDt, scope) +// return assignTypeCastedIdentifier(target.asmVarname, targetDt, subroutineFloatEvalResultVar, valueDt) } in PassByReferenceDatatypes -> { // str/array value cast (most likely to UWORD, take address-of) - return asmgen.assignExpressionToVariable(value, target.asmVarname, targetDt, null) // TODO test this cast + return assignExpressionToVariable(value, target.asmVarname, targetDt, null) // TODO test this cast } else -> throw AssemblyError("strange dt in typecast assign to var: $valueDt --> $targetDt") } @@ -398,6 +406,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } DataType.FLOAT -> { + // TODO loading targetasmname in SCRATCH_W2 no longer needed??????? asmgen.out(""" lda #<$targetAsmVarName ldy #>$targetAsmVarName @@ -423,6 +432,145 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } + private fun assignTypeCastedRegisters(targetAsmVarName: String, targetDt: DataType, + regs: RegisterOrPair, sourceDt: DataType) { + if(sourceDt == targetDt) + throw AssemblyError("typecast to identical value") + + // also see: ExpressionAsmGen, fun translateExpression(typecast: TypecastExpression) + when(sourceDt) { + DataType.UBYTE -> { + when(targetDt) { + DataType.UBYTE, DataType.BYTE -> { + asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName") + } + DataType.UWORD, DataType.WORD -> { + if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02) + asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | stz $targetAsmVarName+1") + else + asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") + } + DataType.FLOAT -> { + when(regs) { + RegisterOrPair.A -> asmgen.out(" tay") + RegisterOrPair.X -> asmgen.out(" txa | tay") + RegisterOrPair.Y -> {} + else -> throw AssemblyError("non-byte regs") + } + asmgen.out(""" + lda #<$targetAsmVarName + sta P8ZP_SCRATCH_W2 + lda #>$targetAsmVarName + sta P8ZP_SCRATCH_W2+1 + jsr floats.cast_from_ub""") + } + else -> throw AssemblyError("weird type") + } + } + DataType.BYTE -> { + when(targetDt) { + DataType.UBYTE, DataType.BYTE -> { + asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName") + } + DataType.UWORD -> { + if(CompilationTarget.instance.machine.cpu==CpuType.CPU65c02) + asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | stz $targetAsmVarName+1") + else + asmgen.out(" st${regs.toString().toLowerCase()} $targetAsmVarName | lda #0 | sta $targetAsmVarName+1") + } + DataType.WORD -> { + when(regs) { + RegisterOrPair.A -> {} + RegisterOrPair.X -> asmgen.out(" txa") + RegisterOrPair.Y -> asmgen.out(" tya") + else -> throw AssemblyError("non-byte regs") + } + asmgen.signExtendAYlsb(sourceDt) + asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1") + } + DataType.FLOAT -> { + when(regs) { + RegisterOrPair.A -> {} + RegisterOrPair.X -> asmgen.out(" txa") + RegisterOrPair.Y -> asmgen.out(" tya") + else -> throw AssemblyError("non-byte regs") + } + asmgen.out(""" + ldy #<$targetAsmVarName + sty P8ZP_SCRATCH_W2 + ldy #>$targetAsmVarName + sty P8ZP_SCRATCH_W2+1 + jsr floats.cast_from_b""") + } + else -> throw AssemblyError("weird type") + } + } + DataType.UWORD -> { + when(targetDt) { + DataType.BYTE, DataType.UBYTE -> { + asmgen.out(" st${regs.toString().toLowerCase().first()} $targetAsmVarName") + } + DataType.WORD, DataType.UWORD -> { + when(regs) { + RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1") + RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1") + RegisterOrPair.XY -> asmgen.out(" stx $targetAsmVarName | sty $targetAsmVarName+1") + else -> throw AssemblyError("non-word regs") + } + } + DataType.FLOAT -> { + if(regs!=RegisterOrPair.AY) + throw AssemblyError("only supports AY here") + asmgen.out(""" + pha + lda #<$targetAsmVarName + sta P8ZP_SCRATCH_W2 + lda #>$targetAsmVarName + sta P8ZP_SCRATCH_W2+1 + pla + jsr floats.cast_from_uw""") + } + else -> throw AssemblyError("weird type") + } + } + DataType.WORD -> { + when(targetDt) { + DataType.BYTE, DataType.UBYTE -> { + asmgen.out(" st${regs.toString().toLowerCase().first()} $targetAsmVarName") + } + DataType.WORD, DataType.UWORD -> { + when(regs) { + RegisterOrPair.AX -> asmgen.out(" sta $targetAsmVarName | stx $targetAsmVarName+1") + RegisterOrPair.AY -> asmgen.out(" sta $targetAsmVarName | sty $targetAsmVarName+1") + RegisterOrPair.XY -> asmgen.out(" stx $targetAsmVarName | sty $targetAsmVarName+1") + else -> throw AssemblyError("non-word regs") + } + } + DataType.FLOAT -> { + if(regs!=RegisterOrPair.AY) + throw AssemblyError("only supports AY here") + asmgen.out(""" + pha + lda #<$targetAsmVarName + sta P8ZP_SCRATCH_W2 + lda #>$targetAsmVarName + sta P8ZP_SCRATCH_W2+1 + pla + jsr floats.cast_from_w""") + } + else -> throw AssemblyError("weird type") + } + } + DataType.STR -> { + if (targetDt != DataType.UWORD && targetDt == DataType.STR) + throw AssemblyError("cannot typecast a string into another incompatitble type") + TODO("assign typecasted string into target var") + } + else -> throw AssemblyError("weird type") + } + } + + private fun assignStackValue(target: AsmAssignTarget) { when(target.kind) { TargetStorageKind.VARIABLE -> { @@ -1469,7 +1617,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg) } else -> { - asmgen.assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) + assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) asmgen.out(" ldy #0 | lda $ldaInstructionArg | sta (P8ZP_SCRATCH_W2),y") } } @@ -1494,7 +1642,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } else -> { asmgen.saveRegister(register, false, memoryAddress.definingSubroutine()!!) - asmgen.assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) + assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) asmgen.restoreRegister(CpuRegister.A, false) asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y") } diff --git a/examples/test.p8 b/examples/test.p8 index 1833706e3..7f3ef76b5 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,105 +7,29 @@ main { sub start() { - uword uw = $c000 - ubyte ub = 1 - ubyte ub2 = 1 - uword uv1 = 1 - uword uv2 = 1 + float fl + word ww + uword uw + byte bb + ubyte ub - uw = 1000 - uw += ub+ub2 + + fl = 9997.999 + ww = (fl+1.1) as word + uw = (fl+1.1) as uword + fl = 97.999 + bb = (fl+1.1) as byte + ub = (fl+1.1) as ubyte + + txt.print_w(ww) + txt.chrout('\n') txt.print_uw(uw) txt.chrout('\n') - - uw = 1000 - uw -= ub+ub2 - txt.print_uw(uw) + txt.print_b(bb) + txt.chrout('\n') + txt.print_ub(ub) txt.chrout('\n') - uw = 1000 - uw *= ub+ub2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = 1000 - uw /= ub+ub2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = 1000 - uw %= 5*ub+ub2+ub2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = 1000 - uw <<= ub+ub2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = 1000 - uw >>= ub+ub2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = $1111 - uw &= (ub+ub2) | 15 - txt.print_uwhex(uw, 1) - txt.chrout('\n') - - uw = $1111 - uw |= (ub+ub2) | 15 - txt.print_uwhex(uw, 1) - txt.chrout('\n') - - uw = $1111 - uw ^= (ub+ub2) | 15 - txt.print_uwhex(uw, 1) - txt.chrout('\n') - - txt.chrout('\n') - - - - uw = 1000 - uw += uv1+uv2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = 1000 - uw -= uv1+uv2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = 1000 - uw *= uv1+uv2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = 1000 - uw /= uv1+uv2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = 1000 - uw %= 5*uv1+uv2+uv2 - txt.print_uw(uw) - txt.chrout('\n') - - uw = $1111 - uw &= (uv1+uv2) | 1023 - txt.print_uwhex(uw, 1) - txt.chrout('\n') - - uw = $1111 - uw |= (uv1+uv2) | 32768 - txt.print_uwhex(uw, 1) - txt.chrout('\n') - - uw = $1111 - uw ^= (uv1+uv2) | 32768 - txt.print_uwhex(uw, 1) - txt.chrout('\n') test_stack.test()