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 ee79302cc..5ff6fd19b 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -1686,7 +1686,6 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, eor #$80 sta ${target.asmVarname}+1 """) - asmgen.restoreRegister(CpuRegister.X) } TargetStorageKind.ARRAY -> TODO("in-place negate float array") TargetStorageKind.STACK -> TODO("stack float negate") diff --git a/compiler/src/prog8/optimizer/StatementOptimizer.kt b/compiler/src/prog8/optimizer/StatementOptimizer.kt index 3e064a223..515f2c74a 100644 --- a/compiler/src/prog8/optimizer/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizer/StatementOptimizer.kt @@ -395,21 +395,21 @@ internal class StatementOptimizer(private val program: Program, val targetDt = targetIDt.typeOrElse(DataType.STRUCT) val bexpr=assignment.value as? BinaryExpression if(bexpr!=null) { - val cv = bexpr.right.constValue(program)?.number?.toDouble() - if (cv != null && assignment.target isSameAs bexpr.left) { + val rightCv = bexpr.right.constValue(program)?.number?.toDouble() + if (rightCv != null && assignment.target isSameAs bexpr.left) { // assignments of the form: X = X // remove assignments that have no effect (such as X=X+0) // optimize/rewrite some other expressions val vardeclDt = (assignment.target.identifier?.targetVarDecl(program.namespace))?.type when (bexpr.operator) { "+" -> { - if (cv == 0.0) { + if (rightCv == 0.0) { return listOf(IAstModification.Remove(assignment, parent)) - } else if (targetDt in IntegerDatatypes && floor(cv) == cv) { - if (vardeclDt != VarDeclType.MEMORY && cv in 1.0..4.0) { + } else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) { + if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0) { // replace by several INCs if it's not a memory address (inc on a memory mapped register doesn't work very well) val incs = AnonymousScope(mutableListOf(), assignment.position) - repeat(cv.toInt()) { + repeat(rightCv.toInt()) { incs.statements.add(PostIncrDecr(assignment.target, "++", assignment.position)) } return listOf(IAstModification.ReplaceNode(assignment, incs, parent)) @@ -417,36 +417,73 @@ internal class StatementOptimizer(private val program: Program, } } "-" -> { - if (cv == 0.0) { + if (rightCv == 0.0) { return listOf(IAstModification.Remove(assignment, parent)) - } else if (targetDt in IntegerDatatypes && floor(cv) == cv) { - if (vardeclDt != VarDeclType.MEMORY && cv in 1.0..4.0) { + } else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) { + if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0) { // replace by several DECs if it's not a memory address (dec on a memory mapped register doesn't work very well) val decs = AnonymousScope(mutableListOf(), assignment.position) - repeat(cv.toInt()) { + repeat(rightCv.toInt()) { decs.statements.add(PostIncrDecr(assignment.target, "--", assignment.position)) } return listOf(IAstModification.ReplaceNode(assignment, decs, parent)) } } } - "*" -> if (cv == 1.0) return listOf(IAstModification.Remove(assignment, parent)) - "/" -> if (cv == 1.0) return listOf(IAstModification.Remove(assignment, parent)) - "**" -> if (cv == 1.0) return listOf(IAstModification.Remove(assignment, parent)) - "|" -> if (cv == 0.0) return listOf(IAstModification.Remove(assignment, parent)) - "^" -> if (cv == 0.0) return listOf(IAstModification.Remove(assignment, parent)) + "*" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, parent)) + "/" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, parent)) + "**" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, parent)) + "|" -> if (rightCv == 0.0) return listOf(IAstModification.Remove(assignment, parent)) + "^" -> if (rightCv == 0.0) return listOf(IAstModification.Remove(assignment, parent)) "<<" -> { - if (cv == 0.0) + if (rightCv == 0.0) return listOf(IAstModification.Remove(assignment, parent)) } ">>" -> { - if (cv == 0.0) + if (rightCv == 0.0) return listOf(IAstModification.Remove(assignment, parent)) } } } + + fun isSimpleTarget(target: AssignTarget): Boolean { + return when { + target.identifier!=null -> true + target.memoryAddress!=null -> { + target.memoryAddress.addressExpression is NumericLiteralValue || target.memoryAddress.addressExpression is IdentifierReference + } + target.arrayindexed!=null -> { + target.arrayindexed!!.arrayspec.index is NumericLiteralValue || target.arrayindexed!!.arrayspec.index is IdentifierReference + } + else -> false + } + } + + // reduce the complexity of a (binary) expression that has to be evaluated on the eval stack, + // by attempting to splitting it up into individual simple steps: + // X = + // or X = + // split that into X = ; X = X + if(!assignment.isAugmentable && isSimpleTarget(assignment.target)) { + if (bexpr.right !is BinaryExpression) { + println("SPLIT RIGHT ${bexpr.left}\n ${bexpr.operator}\n ${bexpr.right}") + val firstAssign = Assignment(assignment.target, bexpr.left, assignment.position) + val augExpr = BinaryExpression(assignment.target.toExpression(), bexpr.operator, bexpr.right, bexpr.position) + return listOf( + IAstModification.InsertBefore(assignment, firstAssign, parent), + IAstModification.ReplaceNode(assignment.value, augExpr, assignment)) + } else if (bexpr.left !is BinaryExpression && bexpr.operator in associativeOperators) { + println("SPLIT LEFT ${bexpr.left}\n ${bexpr.operator}\n ${bexpr.right}") + val firstAssign = Assignment(assignment.target, bexpr.right, assignment.position) + val augExpr = BinaryExpression(assignment.target.toExpression(), bexpr.operator, bexpr.left, bexpr.position) + return listOf( + IAstModification.InsertBefore(assignment, firstAssign, parent), + IAstModification.ReplaceNode(assignment.value, augExpr, assignment)) + } + } } + return noModifications } diff --git a/examples/test.p8 b/examples/test.p8 index 79ed78b79..299144779 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -40,11 +40,13 @@ _saveX .byte 0 float ff1 = 1000 float ff2 = -1000 - ff1 = 1+((-ff1) *3) ; TODO why is splitting undone when OPTIMIZATION is ON? + ff1 = 1+((-ff1) *3) floats.print_f(ff1) + floats.print_f(1+((-1000) *3)) testX() - ff1 = 1+((-ff2) *3) ; TODO why is splitting undone when OPTIMIZATION is ON? + ff1 = 1+((-ff2) *3) floats.print_f(ff1) + floats.print_f(1+((- (-1000)) *3)) txt.chrout('\n') testX() return