From 110f877dcc5972a89e012316f6d7136081538af4 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 2 Oct 2020 00:04:21 +0200 Subject: [PATCH] binexpr expression splitter for assignments --- .../src/prog8/optimizer/ExpressionSplitter.kt | 116 +++++++++++++----- compiler/src/prog8/optimizer/Extensions.kt | 6 +- examples/test.p8 | 28 ++--- 3 files changed, 105 insertions(+), 45 deletions(-) diff --git a/compiler/src/prog8/optimizer/ExpressionSplitter.kt b/compiler/src/prog8/optimizer/ExpressionSplitter.kt index c24d6c9f9..38a086d49 100644 --- a/compiler/src/prog8/optimizer/ExpressionSplitter.kt +++ b/compiler/src/prog8/optimizer/ExpressionSplitter.kt @@ -3,44 +3,44 @@ package prog8.optimizer import prog8.ast.INameScope import prog8.ast.Node import prog8.ast.Program +import prog8.ast.base.VarDeclType import prog8.ast.expressions.* import prog8.ast.processing.AstWalker import prog8.ast.processing.IAstModification import prog8.ast.statements.AssignTarget import prog8.ast.statements.Assignment +import prog8.ast.statements.VarDecl class ExpressionSplitter(private val program: Program) : AstWalker() { // TODO once this works, integrate it back into expressionsimplifier - override fun after(assignment: Assignment, parent: Node): Iterable { + override fun after(decl: VarDecl, parent: Node): Iterable { - if(assignment!=null) { - val expr = assignment.value as? BinaryExpression - if (expr != null) { - // 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 + val expr = decl.value as? BinaryExpression + if (expr != null) { + // 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 - // TODO FIX THIS, IT SOMETIMES JUST LOOPS... (for example on plasma.p8) - if (expr.operator !in comparisonOperators && !assignment.isAugmentable && isSimpleTarget(assignment.target, program.namespace)) { - if (expr.right !is BinaryExpression) { - println("SPLIT RIGHT BINEXPR $expr") - val firstAssign = Assignment(assignment.target, expr.left, assignment.position) - val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.right, expr.position) - return listOf( - IAstModification.InsertBefore(assignment, firstAssign, parent), - IAstModification.ReplaceNode(assignment.value, augExpr, assignment) - ) - } else if (expr.left !is BinaryExpression && expr.operator in associativeOperators) { - println("SPLIT LEFT BINEXPR $expr") - val firstAssign = Assignment(assignment.target, expr.right, assignment.position) - val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.left, expr.position) - return listOf( - IAstModification.InsertBefore(assignment, firstAssign, parent), - IAstModification.ReplaceNode(assignment.value, augExpr, assignment)) - } + // TODO DOES THIS LOOP AS WELL? + if (expr.operator !in comparisonOperators && decl.type==VarDeclType.VAR) { + if (expr.right !is BinaryExpression) { + println("SPLIT VARDECL RIGHT BINEXPR $expr") // TODO +// val firstAssign = Assignment(assignment.target, expr.left, assignment.position) +// val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.right, expr.position) +// return listOf( +// IAstModification.InsertBefore(assignment, firstAssign, parent), +// IAstModification.ReplaceNode(assignment.value, augExpr, assignment) +// ) + } else if (expr.left !is BinaryExpression && expr.operator in associativeOperators) { + println("SPLIT VARDECL LEFT BINEXPR $expr") // TODO +// val firstAssign = Assignment(assignment.target, expr.right, assignment.position) +// val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.left, expr.position) +// return listOf( +// IAstModification.InsertBefore(assignment, firstAssign, parent), +// IAstModification.ReplaceNode(assignment.value, augExpr, assignment)) } } } @@ -48,13 +48,73 @@ class ExpressionSplitter(private val program: Program) : AstWalker() { return emptyList() } + // TODO once this works, integrate it back into expressionsimplifier + override fun after(assignment: Assignment, parent: Node): Iterable { + + val binExpr = assignment.value as? BinaryExpression + if (binExpr != null) { +/* + +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 = BinExpr X = LeftExpr + followed by + / \ IF 'X' not used X = BinExpr + / \ IN LEFTEXPR ==> + / \ / \ + LeftExpr. RightExpr. / \ + / \ / \ X RightExpr. + .. .. .. .. + + + +X = BinExpr X = RightExpr + followed by + / \ IF ASSOCIATIVE X = BinExpr + / \ ==> + / \ / \ + LeftExpr. SimpleExpr. / \ + / \ (not X) X LeftExpr. + .. .. + + */ + if(!assignment.isAugmentable && isSimpleTarget(assignment.target, program.namespace)) { + val firstAssign = Assignment(assignment.target, binExpr.left, binExpr.left.position) + val targetExpr = assignment.target.toExpression() + val augExpr = BinaryExpression(targetExpr, binExpr.operator, binExpr.right, binExpr.right.position) + return listOf( + IAstModification.InsertBefore(assignment, firstAssign, parent), + IAstModification.ReplaceNode(assignment.value, augExpr, assignment)) + } + + if(binExpr.operator in associativeOperators && binExpr.left is BinaryExpression) { + if (binExpr.right !is BinaryExpression && !(binExpr.right isSameAs assignment.target)) { + val firstAssign = Assignment(assignment.target, binExpr.right, binExpr.right.position) + val targetExpr = assignment.target.toExpression() + val augExpr = BinaryExpression(targetExpr, binExpr.operator, binExpr.left, binExpr.left.position) + return listOf( + IAstModification.InsertBefore(assignment, firstAssign, parent), + IAstModification.ReplaceNode(assignment.value, augExpr, assignment)) + } + } + + // TODO further unraveling of binary expression trees into flat statements. + // however this should probably be done in a more generic way to also service + // the expressiontrees that are not used in an assignment statement... + } + + return emptyList() + } + private fun isSimpleTarget(target: AssignTarget, namespace: INameScope): Boolean { return when { target.identifier!=null -> target.isInRegularRAM(namespace) target.memoryAddress!=null -> target.isInRegularRAM(namespace) target.arrayindexed!=null -> { val index = target.arrayindexed!!.arrayspec.index - if(index is NumericLiteralValue || index is IdentifierReference) + if(index is NumericLiteralValue) target.isInRegularRAM(namespace) else false diff --git a/compiler/src/prog8/optimizer/Extensions.kt b/compiler/src/prog8/optimizer/Extensions.kt index 4457cc0b5..203c1999f 100644 --- a/compiler/src/prog8/optimizer/Extensions.kt +++ b/compiler/src/prog8/optimizer/Extensions.kt @@ -55,8 +55,8 @@ internal fun Program.simplifyExpressions() : Int { } internal fun Program.splitExpressions() : Int { - val opti = ExpressionSplitter(this) - opti.visit(this) - return opti.applyModifications() + val splitter = ExpressionSplitter(this) + splitter.visit(this) + return splitter.applyModifications() } diff --git a/examples/test.p8 b/examples/test.p8 index 14cdd188f..79a80d3ce 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -19,20 +19,20 @@ main { ; uword[] arrays = [names, names3, values] - asmsub testX() { - %asm {{ - stx _saveX - lda #13 - jsr txt.chrout - lda _saveX - jsr txt.print_ub - lda #13 - jsr txt.chrout - ldx _saveX - rts -_saveX .byte 0 - }} - } +; asmsub testX() { +; %asm {{ +; stx _saveX +; lda #13 +; jsr txt.chrout +; lda _saveX +; jsr txt.print_ub +; lda #13 +; jsr txt.chrout +; ldx _saveX +; rts +;_saveX .byte 0 +; }} +; } sub start() { ; byte bb = 100