From 6f3b2749b087edc4e10085c14632c93b8a8e94bd Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 20 Aug 2020 15:18:24 +0200 Subject: [PATCH] refactoring assignments codegen --- .../src/prog8/ast/statements/AstStatements.kt | 2 +- .../compiler/target/c64/codegen/AsmGen.kt | 32 +-- .../target/c64/codegen/AssignmentAsmGen.kt | 211 ++++++++++-------- .../target/c64/codegen/ExpressionsAsmGen.kt | 7 +- .../target/c64/codegen/FunctionCallAsmGen.kt | 46 +--- examples/test.p8 | 19 +- 6 files changed, 127 insertions(+), 190 deletions(-) diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index 77686a5a9..4e3a5a393 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -328,7 +328,7 @@ open class Assignment(var target: AssignTarget, var value: Expression, override return("Assignment(target: $target, value: $value, pos=$position)") } - val isInplace: Boolean + val isAugmentable: Boolean get() { val binExpr = value as? BinaryExpression if(binExpr!=null) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 5ad7cdc21..c22838ecb 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -1025,36 +1025,6 @@ $counterVar .byte 0""") internal fun translateFunctionCall(functionCall: FunctionCall) = functioncallAsmGen.translateFunctionCall(functionCall) - internal fun assignFromEvalResult(target: AssignTarget) = - assignmentAsmGen.assignFromEvalResult(target) - - fun assignFromByteConstant(target: AssignTarget, value: Short) = - assignmentAsmGen.assignFromByteConstant(target, value) - - fun assignFromWordConstant(target: AssignTarget, value: Int) = - assignmentAsmGen.assignFromWordConstant(target, value) - - fun assignFromFloatConstant(target: AssignTarget, value: Double) = - assignmentAsmGen.assignFromFloatConstant(target, value) - - fun assignFromByteVariable(target: AssignTarget, variable: IdentifierReference) = - assignmentAsmGen.assignFromByteVariable(target, variable) - - fun assignFromWordVariable(target: AssignTarget, variable: IdentifierReference) = - assignmentAsmGen.assignFromWordVariable(target, variable) - - fun assignFromAddressOf(target: AssignTarget, variable: IdentifierReference) = - assignmentAsmGen.assignFromAddressOf(target, variable) - - fun assignFromFloatVariable(target: AssignTarget, variable: IdentifierReference) = - assignmentAsmGen.assignFromFloatVariable(target, variable) - - fun assignFromRegister(target: AssignTarget, register: CpuRegister) = - assignmentAsmGen.assignFromRegister(target, register) - - fun assignFromMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) = - assignmentAsmGen.assignFromMemoryByte(target, address, identifier) - - fun assignToRegister(reg: CpuRegister, value: Short?, identifier: IdentifierReference?) = + internal fun assignToRegister(reg: CpuRegister, value: Short?, identifier: IdentifierReference?) = assignmentAsmGen.assignToRegister(reg, value, identifier) } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt index db33a9698..87659beba 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt @@ -3,10 +3,7 @@ package prog8.compiler.target.c64.codegen import prog8.ast.Program import prog8.ast.base.* import prog8.ast.expressions.* -import prog8.ast.statements.AssignTarget -import prog8.ast.statements.Assignment -import prog8.ast.statements.DirectMemoryWrite -import prog8.ast.statements.VarDecl +import prog8.ast.statements.* import prog8.compiler.AssemblyError import prog8.compiler.target.c64.C64MachineDefinition import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage @@ -18,33 +15,49 @@ import prog8.compiler.toHex internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen) { internal fun translate(assign: Assignment) { - if(assign.isInplace) - translateNormalAssignment(assign) // TODO generate better code here for in-place assignments - else - translateNormalAssignment(assign) + when { + assign.value is NumericLiteralValue -> translateConstantValueAssignment(assign) + assign.value is IdentifierReference -> translateVariableAssignment(assign) + assign.isAugmentable -> { + println("TODO: optimize augmentable assignment ${assign.position}") // TODO + translateOtherAssignment(assign) // TODO generate better code here for augmentable assignments + } + else -> translateOtherAssignment(assign) + } } - // old code-generation below: - // eventually, all of this should have been replaced by newer more optimized code. - private fun translateNormalAssignment(assign: Assignment) { + internal fun assignToRegister(reg: CpuRegister, value: Short?, identifier: IdentifierReference?) { + if(value!=null) { + asmgen.out(" ld${reg.toString().toLowerCase()} #${value.toHex()}") + } else if(identifier!=null) { + val name = asmgen.asmIdentifierName(identifier) + asmgen.out(" ld${reg.toString().toLowerCase()} $name") + } + } + + private fun translateVariableAssignment(assign: Assignment) { + val identifier = assign.value as IdentifierReference + when (val type = assign.target.inferType(program, assign).typeOrElse(DataType.STRUCT)) { + DataType.UBYTE, DataType.BYTE -> assignFromByteVariable(assign.target, identifier) + DataType.UWORD, DataType.WORD -> assignFromWordVariable(assign.target, identifier) + DataType.FLOAT -> assignFromFloatVariable(assign.target, identifier) + in PassByReferenceDatatypes -> assignFromAddressOf(assign.target, identifier) + else -> throw AssemblyError("unsupported assignment target type $type") + } + } + + private fun translateConstantValueAssignment(assign: Assignment) { + val numVal = assign.value as NumericLiteralValue + when (numVal.type) { + DataType.UBYTE, DataType.BYTE -> assignFromByteConstant(assign.target, numVal.number.toShort()) + DataType.UWORD, DataType.WORD -> assignFromWordConstant(assign.target, numVal.number.toInt()) + DataType.FLOAT -> assignFromFloatConstant(assign.target, numVal.number.toDouble()) + else -> throw AssemblyError("weird numval type") + } + } + + private fun translateOtherAssignment(assign: Assignment) { when (assign.value) { - is NumericLiteralValue -> { - val numVal = assign.value as NumericLiteralValue - when (numVal.type) { - DataType.UBYTE, DataType.BYTE -> assignFromByteConstant(assign.target, numVal.number.toShort()) - DataType.UWORD, DataType.WORD -> assignFromWordConstant(assign.target, numVal.number.toInt()) - DataType.FLOAT -> assignFromFloatConstant(assign.target, numVal.number.toDouble()) - else -> throw AssemblyError("weird numval type") - } - } - is IdentifierReference -> { - when (val type = assign.target.inferType(program, assign).typeOrElse(DataType.STRUCT)) { - DataType.UBYTE, DataType.BYTE -> assignFromByteVariable(assign.target, assign.value as IdentifierReference) - DataType.UWORD, DataType.WORD -> assignFromWordVariable(assign.target, assign.value as IdentifierReference) - DataType.FLOAT -> assignFromFloatVariable(assign.target, assign.value as IdentifierReference) - else -> throw AssemblyError("unsupported assignment target type $type") - } - } is AddressOf -> { val identifier = (assign.value as AddressOf).identifier assignFromAddressOf(assign.target, identifier) @@ -60,7 +73,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen assignFromMemoryByte(assign.target, null, read.addressExpression as IdentifierReference) } else -> { - throw AssemblyError("missing asm gen for memread assignment into ${assign.target}") + asmgen.translateExpression(read.addressExpression) + asmgen.out(" jsr prog8_lib.read_byte_from_address | inx") + assignFromRegister(assign.target, CpuRegister.A) } } } @@ -120,10 +135,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array assignment $assign") is RangeExpr -> throw AssemblyError("range expression should have been changed into array values ${assign.value.position}") + else -> throw AssemblyError("assignment value type should have been handled elsewhere") } } - internal fun assignFromEvalResult(target: AssignTarget) { + private fun assignFromEvalResult(target: AssignTarget) { val targetIdent = target.identifier when { targetIdent != null -> { @@ -152,8 +168,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } target.memoryAddress != null -> { - asmgen.out(" inx | ldy $ESTACK_LO_HEX,x") - storeRegisterInMemoryAddress(CpuRegister.Y, target.memoryAddress) + asmgen.out(" inx") + storeByteViaRegisterAInMemoryAddress("$ESTACK_LO_HEX,x", target.memoryAddress) } target.arrayindexed != null -> { val arrayDt = target.arrayindexed!!.identifier.inferType(program).typeOrElse(DataType.STRUCT) @@ -166,7 +182,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - internal fun assignFromAddressOf(target: AssignTarget, name: IdentifierReference) { + private fun assignFromAddressOf(target: AssignTarget, name: IdentifierReference) { val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed val struct = name.memberOfStruct(program.namespace) @@ -204,7 +220,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - internal fun assignFromWordVariable(target: AssignTarget, variable: IdentifierReference) { + private fun assignFromWordVariable(target: AssignTarget, variable: IdentifierReference) { val sourceName = asmgen.asmIdentifierName(variable) val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed @@ -234,7 +250,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - internal fun assignFromFloatVariable(target: AssignTarget, variable: IdentifierReference) { + private fun assignFromFloatVariable(target: AssignTarget, variable: IdentifierReference) { val sourceName = asmgen.asmIdentifierName(variable) val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed @@ -265,7 +281,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - internal fun assignFromByteVariable(target: AssignTarget, variable: IdentifierReference) { + private fun assignFromByteVariable(target: AssignTarget, variable: IdentifierReference) { val sourceName = asmgen.asmIdentifierName(variable) val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed @@ -296,16 +312,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.out(" lda $sourceName | sta $targetName") } else -> { - asmgen.translateExpression(addressExpr) - asmgen.out(""" - inx - lda $ESTACK_LO_HEX,x - ldy $ESTACK_HI_HEX,x - sta (+) +1 - sty (+) +2 - lda $sourceName -+ sta ${'$'}ffff ; modified - """) + storeByteViaRegisterAInMemoryAddress(sourceName, target.memoryAddress) } } } @@ -313,7 +320,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - internal fun assignFromRegister(target: AssignTarget, register: CpuRegister) { + private fun assignFromRegister(target: AssignTarget, register: CpuRegister) { val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed when { @@ -372,7 +379,39 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } + private fun storeByteViaRegisterAInMemoryAddress(ldaInstructionArg: String, memoryAddress: DirectMemoryWrite) { + val addressExpr = memoryAddress.addressExpression + val addressLv = addressExpr as? NumericLiteralValue + when { + addressLv != null -> asmgen.out(" lda $ldaInstructionArg | sta ${addressLv.number.toHex()}") + addressExpr is IdentifierReference -> { + val targetName = asmgen.asmIdentifierName(addressExpr) + asmgen.out(""" + lda $targetName + sta ${C64Zeropage.SCRATCH_W1} + lda $targetName+1 + sta ${C64Zeropage.SCRATCH_W1+1} + lda $ldaInstructionArg + ldy #0 + sta (${C64Zeropage.SCRATCH_W1}),y""") + } + else -> { + asmgen.translateExpression(addressExpr) + asmgen.out(""" + inx + lda $ESTACK_LO_HEX,x + sta ${C64Zeropage.SCRATCH_W1} + lda $ESTACK_HI_HEX,x + sta ${C64Zeropage.SCRATCH_W1+1} + lda $ldaInstructionArg + ldy #0 + sta (${C64Zeropage.SCRATCH_W1}),y""") + } + } + } + private fun storeRegisterInMemoryAddress(register: CpuRegister, memoryAddress: DirectMemoryWrite) { + // this is optimized for register A. val addressExpr = memoryAddress.addressExpression val addressLv = addressExpr as? NumericLiteralValue val registerName = register.name.toLowerCase() @@ -381,48 +420,35 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen addressExpr is IdentifierReference -> { val targetName = asmgen.asmIdentifierName(addressExpr) when (register) { - CpuRegister.A -> asmgen.out(""" - ldy $targetName - sty (+) +1 - ldy $targetName+1 - sty (+) +2 -+ sta ${'$'}ffff ; modified""") - CpuRegister.X -> asmgen.out(""" - ldy $targetName - sty (+) +1 - ldy $targetName+1 - sty (+) +2 -+ stx ${'$'}ffff ; modified""") - CpuRegister.Y -> asmgen.out(""" - lda $targetName - sta (+) +1 - lda $targetName+1 - sta (+) +2 -+ sty ${'$'}ffff ; modified""") + CpuRegister.A -> {} + CpuRegister.X -> asmgen.out(" txa") + CpuRegister.Y -> asmgen.out(" tya") } + asmgen.out(""" + ldy $targetName + sty ${C64Zeropage.SCRATCH_W1} + ldy $targetName+1 + sty ${C64Zeropage.SCRATCH_W1+1} + ldy #0 + sta (${C64Zeropage.SCRATCH_W1}),y""") } else -> { asmgen.saveRegister(register) asmgen.translateExpression(addressExpr) - asmgen.restoreRegister(register) - when (register) { - CpuRegister.A -> asmgen.out(" tay") - CpuRegister.X -> throw AssemblyError("can't use X register here") - CpuRegister.Y -> {} - } + asmgen.restoreRegister(CpuRegister.A) asmgen.out(""" - inx - lda $ESTACK_LO_HEX,x - sta (+) +1 - lda $ESTACK_HI_HEX,x - sta (+) +2 -+ sty ${'$'}ffff ; modified - """) + inx + ldy $ESTACK_LO_HEX,x + sty ${C64Zeropage.SCRATCH_W1} + ldy $ESTACK_HI_HEX,x + sty ${C64Zeropage.SCRATCH_W1+1} + ldy #0 + sta (${C64Zeropage.SCRATCH_W1}),y""") } } } - internal fun assignFromWordConstant(target: AssignTarget, word: Int) { + private fun assignFromWordConstant(target: AssignTarget, word: Int) { val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed when { @@ -467,17 +493,17 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - internal fun assignFromByteConstant(target: AssignTarget, byte: Short) { + private fun assignFromByteConstant(target: AssignTarget, byte: Short) { val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed + val targetMemory = target.memoryAddress when { targetIdent != null -> { val targetName = asmgen.asmIdentifierName(targetIdent) asmgen.out(" lda #${byte.toHex()} | sta $targetName ") } - target.memoryAddress != null -> { - asmgen.out(" ldy #${byte.toHex()}") - storeRegisterInMemoryAddress(CpuRegister.Y, target.memoryAddress) + targetMemory != null -> { + storeByteViaRegisterAInMemoryAddress("#${byte.toHex()}", targetMemory) } targetArrayIdx != null -> { val index = targetArrayIdx.arrayspec.index @@ -495,7 +521,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - internal fun assignFromFloatConstant(target: AssignTarget, float: Double) { + private fun assignFromFloatConstant(target: AssignTarget, float: Double) { val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed if (float == 0.0) { @@ -594,7 +620,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - internal fun assignFromMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) { + private fun assignFromMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) { val targetIdent = target.identifier val targetArrayIdx = target.arrayindexed if (address != null) { @@ -607,8 +633,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen """) } target.memoryAddress != null -> { - asmgen.out(" ldy ${address.toHex()}") - storeRegisterInMemoryAddress(CpuRegister.Y, target.memoryAddress) + storeByteViaRegisterAInMemoryAddress(address.toHex(), target.memoryAddress) } targetArrayIdx != null -> { val index = targetArrayIdx.arrayspec.index @@ -631,8 +656,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen sta $targetName""") } target.memoryAddress != null -> { - asmgen.out(" ldy $sourceName") - storeRegisterInMemoryAddress(CpuRegister.Y, target.memoryAddress) + storeByteViaRegisterAInMemoryAddress(sourceName, target.memoryAddress) } targetArrayIdx != null -> { val index = targetArrayIdx.arrayspec.index @@ -663,13 +687,4 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen throw AssemblyError("weird array type") } } - - fun assignToRegister(reg: CpuRegister, value: Short?, identifier: IdentifierReference?) { - if(value!=null) { - asmgen.out(" ld${reg.toString().toLowerCase()} #${value.toHex()}") - } else if(identifier!=null) { - val name = asmgen.asmIdentifierName(identifier) - asmgen.out(" ld${reg.toString().toLowerCase()} $name") - } - } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index 22f5b9d25..b8a2308c5 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -140,10 +140,11 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge val sourceName = asmgen.asmIdentifierName(expr.addressExpression as IdentifierReference) asmgen.out(""" lda $sourceName - sta (+) +1 + sta ${C64MachineDefinition.C64Zeropage.SCRATCH_W1} lda $sourceName+1 - sta (+) +2 -+ lda ${'$'}ffff ; modified + sta ${C64MachineDefinition.C64Zeropage.SCRATCH_W1+1} + ldy #0 + lda (${C64MachineDefinition.C64Zeropage.SCRATCH_W1}),y sta $ESTACK_LO_HEX,x dex""") } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt index 541e7a1f2..a11788278 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt @@ -5,6 +5,7 @@ import prog8.ast.Program import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.AssignTarget +import prog8.ast.statements.Assignment import prog8.ast.statements.Subroutine import prog8.ast.statements.SubroutineParameter import prog8.compiler.AssemblyError @@ -107,48 +108,9 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg val paramVar = parameter.value val scopedParamVar = (sub.scopedname+"."+paramVar.name).split(".") val target = AssignTarget(IdentifierReference(scopedParamVar, sub.position), null, null, sub.position) - target.linkParents(value.parent) - when (value) { - is NumericLiteralValue -> { - // optimize when the argument is a constant literal - when(parameter.value.type) { - in ByteDatatypes -> asmgen.assignFromByteConstant(target, value.number.toShort()) - in WordDatatypes -> asmgen.assignFromWordConstant(target, value.number.toInt()) - DataType.FLOAT -> asmgen.assignFromFloatConstant(target, value.number.toDouble()) - else -> throw AssemblyError("weird parameter datatype") - } - } - is IdentifierReference -> { - // optimize when the argument is a variable - when (parameter.value.type) { - in ByteDatatypes -> asmgen.assignFromByteVariable(target, value) - in WordDatatypes -> asmgen.assignFromWordVariable(target, value) - DataType.FLOAT -> asmgen.assignFromFloatVariable(target, value) - in PassByReferenceDatatypes -> asmgen.assignFromAddressOf(target, value) - else -> throw AssemblyError("weird parameter datatype") - } - } - is DirectMemoryRead -> { - when(value.addressExpression) { - is NumericLiteralValue -> { - val address = (value.addressExpression as NumericLiteralValue).number.toInt() - asmgen.assignFromMemoryByte(target, address, null) - } - is IdentifierReference -> { - asmgen.assignFromMemoryByte(target, null, value.addressExpression as IdentifierReference) - } - else -> { - asmgen.translateExpression(value.addressExpression) - asmgen.out(" jsr prog8_lib.read_byte_from_address | inx") - asmgen.assignFromRegister(target, CpuRegister.A) - } - } - } - else -> { - asmgen.translateExpression(value) - asmgen.assignFromEvalResult(target) - } - } + val assign = Assignment(target, value, value.position) + assign.linkParents(value.parent) + asmgen.translate(assign) } private fun argumentViaRegister(sub: Subroutine, parameter: IndexedValue, value: Expression) { diff --git a/examples/test.p8 b/examples/test.p8 index d9e001861..a7b433ddc 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,21 +7,10 @@ main { sub start() { - c64scr.print_ub(5) - c64.CHROUT('\n') - return + ubyte A=5 + uword clr = $d020 + @(clr+1) = A - c64scr.print_ub(5) - c64.CHROUT('\n') - - goto start - - c64scr.print_ub(5) - c64.CHROUT('\n') - - exit(11) - - c64scr.print_ub(5) - c64.CHROUT('\n') +; uword xx = @(clr+1) } }