From cb9825484d0b5049deff5dab98776681ae9027bb Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 17 Jun 2020 21:41:38 +0200 Subject: [PATCH] some more optimized in-array assignments codegeneration --- compiler/res/prog8lib/c64floats.asm | 15 +++ compiler/res/version.txt | 2 +- .../prog8/ast/expressions/AstExpressions.kt | 2 + .../compiler/target/c64/codegen/AsmGen.kt | 2 - .../target/c64/codegen/AssignmentAsmGen.kt | 117 ++++++++++++++---- .../c64/codegen/BuiltinFunctionsAsmGen.kt | 52 +++++++- examples/cube3d-sprites.p8 | 15 ++- examples/test.p8 | 36 +++++- 8 files changed, 207 insertions(+), 34 deletions(-) diff --git a/compiler/res/prog8lib/c64floats.asm b/compiler/res/prog8lib/c64floats.asm index cc751f333..b427aec9c 100644 --- a/compiler/res/prog8lib/c64floats.asm +++ b/compiler/res/prog8lib/c64floats.asm @@ -781,3 +781,18 @@ set_array_float .proc ; -- copies the 5 bytes of the mflt value pointed to by SCRATCH_ZPWORD1, ; into the 5 bytes pointed to by A/Y. Clobbers A,Y. .pend + + +swap_floats .proc + ; -- swap floats pointed to by SCRATCH_ZPWORD1, SCRATCH_ZPWORD2 + ldy #4 +- lda (c64.SCRATCH_ZPWORD1),y + pha + lda (c64.SCRATCH_ZPWORD2),y + sta (c64.SCRATCH_ZPWORD1),y + pla + sta (c64.SCRATCH_ZPWORD2),y + dey + bpl - + rts + .pend diff --git a/compiler/res/version.txt b/compiler/res/version.txt index 8bbe6cf74..b80651de1 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -2.2 +2.3-SNAPSHOT diff --git a/compiler/src/prog8/ast/expressions/AstExpressions.kt b/compiler/src/prog8/ast/expressions/AstExpressions.kt index fe6fbd5c4..b59490dc5 100644 --- a/compiler/src/prog8/ast/expressions/AstExpressions.kt +++ b/compiler/src/prog8/ast/expressions/AstExpressions.kt @@ -731,6 +731,8 @@ data class IdentifierReference(val nameInSource: List, override val posi fun targetVarDecl(namespace: INameScope): VarDecl? = targetStatement(namespace) as? VarDecl fun targetSubroutine(namespace: INameScope): Subroutine? = targetStatement(namespace) as? Subroutine + override fun equals(other: Any?) = other is IdentifierReference && other.nameInSource==nameInSource + override fun linkParents(parent: Node) { this.parent = parent } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 1766bf600..48049050f 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -691,7 +691,6 @@ internal class AsmGen(private val program: Program, loopEndLabels.push(endLabel) loopContinueLabels.push(whileLabel) out(whileLabel) - // TODO optimize for the simple cases, can we avoid stack use? expressionsAsmGen.translateExpression(stmt.condition) val conditionDt = stmt.condition.inferType(program) if(!conditionDt.isKnown) @@ -720,7 +719,6 @@ internal class AsmGen(private val program: Program, loopEndLabels.push(endLabel) loopContinueLabels.push(repeatLabel) out(repeatLabel) - // TODO optimize this for the simple cases, can we avoid stack use? translate(stmt.body) expressionsAsmGen.translateExpression(stmt.untilCondition) val conditionDt = stmt.untilCondition.inferType(program) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt index 6d6963599..ab6488b62 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AssignmentAsmGen.kt @@ -167,33 +167,108 @@ internal class AssignmentAsmGen(private val program: Program, private val errors TODO("$assign") } is ArrayIndexedExpression -> { + if(assign.aug_op != "setvalue") + return false // we don't put effort into optimizing anything beside simple assignment val valueArrayExpr = assign.value as ArrayIndexedExpression val valueArrayIndex = valueArrayExpr.arrayspec.index + if(valueArrayIndex is RegisterExpr || arrayIndex is RegisterExpr) { + throw AssemblyError("cannot generate code for array operations with registers as index") + } val valueVariablename = asmgen.asmIdentifierName(valueArrayExpr.identifier) val valueDt = valueArrayExpr.identifier.inferType(program).typeOrElse(DataType.STRUCT) when(arrayDt) { - DataType.ARRAY_UB -> { - if (arrayDt != DataType.ARRAY_B && arrayDt != DataType.ARRAY_UB && arrayDt != DataType.STR) - throw AssemblyError("assignment to array: expected byte array or string") - if (assign.aug_op == "setvalue") { - if (valueArrayIndex is NumericLiteralValue) - asmgen.out(" ldy #${valueArrayIndex.number.toHex()}") - else - asmgen.translateArrayIndexIntoY(valueArrayExpr) - asmgen.out(" lda $valueVariablename,y") - if (arrayIndex is NumericLiteralValue) - asmgen.out(" ldy #${arrayIndex.number.toHex()}") - else - asmgen.translateArrayIndexIntoY(targetArray) - asmgen.out(" sta $targetName,y") - } else { - return false // TODO optimize - } + DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> { + if (valueArrayIndex is NumericLiteralValue) + asmgen.out(" ldy #${valueArrayIndex.number.toHex()}") + else + asmgen.translateArrayIndexIntoY(valueArrayExpr) + asmgen.out(" lda $valueVariablename,y") + if (arrayIndex is NumericLiteralValue) + asmgen.out(" ldy #${arrayIndex.number.toHex()}") + else + asmgen.translateArrayIndexIntoY(targetArray) + asmgen.out(" sta $targetName,y") + } + DataType.ARRAY_UW, DataType.ARRAY_W -> { + if (valueArrayIndex is NumericLiteralValue) + asmgen.out(" ldy #2*${valueArrayIndex.number.toHex()}") + else { + asmgen.translateArrayIndexIntoA(valueArrayExpr) + asmgen.out(" asl a | tay") + } + asmgen.out(""" + lda $valueVariablename,y + pha + lda $valueVariablename+1,y + pha + """) + if (arrayIndex is NumericLiteralValue) + asmgen.out(" ldy #2*${arrayIndex.number.toHex()}") + else { + asmgen.translateArrayIndexIntoA(targetArray) + asmgen.out(" asl a | tay") + } + asmgen.out(""" + pla + sta $targetName+1,y + pla + sta $targetName,y + """) + return true + } + DataType.ARRAY_F -> { + if (valueArrayIndex is NumericLiteralValue) + asmgen.out(" ldy #5*${valueArrayIndex.number.toHex()}") + else { + asmgen.translateArrayIndexIntoA(valueArrayExpr) + asmgen.out(""" + sta ${C64Zeropage.SCRATCH_REG} + asl a + asl a + clc + adc ${C64Zeropage.SCRATCH_REG} + tay + """) + } + asmgen.out(""" + lda $valueVariablename,y + pha + lda $valueVariablename+1,y + pha + lda $valueVariablename+2,y + pha + lda $valueVariablename+3,y + pha + lda $valueVariablename+4,y + pha + """) + if (arrayIndex is NumericLiteralValue) + asmgen.out(" ldy #5*${arrayIndex.number.toHex()}") + else { + asmgen.translateArrayIndexIntoA(targetArray) + asmgen.out(""" + sta ${C64Zeropage.SCRATCH_REG} + asl a + asl a + clc + adc ${C64Zeropage.SCRATCH_REG} + tay + """) + } + asmgen.out(""" + pla + sta $targetName+4,y + pla + sta $targetName+3,y + pla + sta $targetName+2,y + pla + sta $targetName+1,y + pla + sta $targetName,y + """) + return true } - DataType.ARRAY_B -> TODO() - DataType.ARRAY_UW -> TODO() - DataType.ARRAY_W -> TODO() - DataType.ARRAY_F -> TODO() else -> throw AssemblyError("assignment to array: invalid array dt") } return true diff --git a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt index 61a33b64b..49e2fe9b8 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt @@ -581,23 +581,63 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val ldy $firstName lda $secondName sta $firstName - tya - sta $secondName + sty $secondName ldy $firstName+1 lda $secondName+1 sta $firstName+1 - tya - sta $secondName+1 + sty $secondName+1 """) return } if(dt.istype(DataType.FLOAT)) { - TODO("optimized case for swapping 2 float vars-- asm subroutine") + asmgen.out(""" + lda #<$firstName + sta ${C64Zeropage.SCRATCH_W1} + lda #>$firstName + sta ${C64Zeropage.SCRATCH_W1+1} + lda #<$secondName + sta ${C64Zeropage.SCRATCH_W2} + lda #>$secondName + sta ${C64Zeropage.SCRATCH_W2+1} + jsr c64flt.swap_floats + """) return } } - // TODO more optimized cases? for instance swapping elements of array vars? + // TODO more optimized cases? + +// if(first is ArrayIndexedExpression && second is ArrayIndexedExpression && first.identifier == second.identifier) { +// // swapping two elements of an array +// // we optimize just some simple cases here: same array, const/var/reg index. +// val arrayName = asmgen.asmIdentifierName(first.identifier) +// val dt = first.inferType(program).typeOrElse(DataType.STRUCT) +// val constIndex1 = first.arrayspec.index.constValue(program) +// val constIndex2 = second.arrayspec.index.constValue(program) +// val varIndex1 = first.arrayspec.index as? IdentifierReference +// val varIndex2 = first.arrayspec.index as? IdentifierReference +// val regIndex1 = (first.arrayspec.index as? RegisterExpr)?.register +// val regIndex2 = (first.arrayspec.index as? RegisterExpr)?.register +// when(dt) { +// DataType.UBYTE, DataType.BYTE -> { +// TODO("swap byte in array $arrayName") +// } +// DataType.UWORD, DataType.WORD -> { +// // swap word in array +// if(varIndex1!=null && varIndex2!=null){ +// TODO("swap word in array $arrayName with varindexes") +// } else if(constIndex1!=null && constIndex2!=null) { +// TODO("swap word in array $arrayName with constants") +// } else if(regIndex1!=null && regIndex2!=null) { +// TODO("swap word in array $arrayName with register indexes") +// } +// } +// DataType.FLOAT -> { +// TODO("swap float in array $arrayName") +// } +// else -> throw AssemblyError("invalid array dt") +// } +// } // suboptimal code via the evaluation stack... asmgen.translateExpression(first) diff --git a/examples/cube3d-sprites.p8 b/examples/cube3d-sprites.p8 index 54f62caed..bfc4200fb 100644 --- a/examples/cube3d-sprites.p8 +++ b/examples/cube3d-sprites.p8 @@ -143,9 +143,18 @@ main { for i1 in 0 to i { ubyte i2 = i1+1 if(rotatedz[i1] > rotatedz[i2]) { - swap(rotatedx[i1], rotatedx[i2]) - swap(rotatedy[i1], rotatedy[i2]) - swap(rotatedz[i1], rotatedz[i2]) + ; swap(rotatedx[i1], rotatedx[i2]) ; TODO eventually, implment the swap() + ; swap(rotatedy[i1], rotatedy[i2]) + ; swap(rotatedz[i1], rotatedz[i2]) + word tmp1 = rotatedx[i1] + rotatedx[i1] = rotatedx[i2] ; TODO fix assignment error + rotatedx[i2] = tmp1 + tmp1 = rotatedy[i1] + rotatedy[i1] = rotatedy[i2] + rotatedy[i2] = tmp1 + tmp1 = rotatedz[i1] + rotatedz[i1] = rotatedz[i2] + rotatedz[i2] = tmp1 } } } diff --git a/examples/test.p8 b/examples/test.p8 index 7b402568f..680dd1503 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -8,7 +8,41 @@ main { sub start() { - A=42 + float[] fa=[1.1111,2.2222,3.3333,4.4444] + ubyte[] uba = [1,2,3,4] + word[] uwa = [1111,2222,3333,4444] + ubyte ii = 1 + ubyte jj = 3 + + float f1 = 1.123456 + float f2 = 2.223344 + + swap(f1, f2) + + swap(fa[0], fa[1]) + swap(uba[0], uba[1]) + swap(uwa[0], uwa[1]) + + swap(fa[A], fa[Y]) + swap(uba[A], uba[Y]) + swap(uwa[A], uwa[Y]) + + ubyte i1 + ubyte i2 + swap(fa[i1], fa[i2]) + swap(uba[i1], uba[i2]) + swap(uwa[i1], uwa[i2]) + + c64flt.print_f(f1) + c64.CHROUT('\n') + c64flt.print_f(f2) + c64.CHROUT('\n') + + swap(f1,f2) + c64flt.print_f(f1) + c64.CHROUT('\n') + c64flt.print_f(f2) + c64.CHROUT('\n') } }