binexpr expression splitter for assignments

This commit is contained in:
Irmen de Jong 2020-10-02 00:04:21 +02:00
parent 9cd3a9f8e8
commit 110f877dcc
3 changed files with 105 additions and 45 deletions

View File

@ -3,44 +3,44 @@ package prog8.optimizer
import prog8.ast.INameScope import prog8.ast.INameScope
import prog8.ast.Node import prog8.ast.Node
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.base.VarDeclType
import prog8.ast.expressions.* import prog8.ast.expressions.*
import prog8.ast.processing.AstWalker import prog8.ast.processing.AstWalker
import prog8.ast.processing.IAstModification import prog8.ast.processing.IAstModification
import prog8.ast.statements.AssignTarget import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Assignment import prog8.ast.statements.Assignment
import prog8.ast.statements.VarDecl
class ExpressionSplitter(private val program: Program) : AstWalker() { class ExpressionSplitter(private val program: Program) : AstWalker() {
// TODO once this works, integrate it back into expressionsimplifier // TODO once this works, integrate it back into expressionsimplifier
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> { override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
if(assignment!=null) { val expr = decl.value as? BinaryExpression
val expr = assignment.value as? BinaryExpression if (expr != null) {
if (expr != null) { // reduce the complexity of a (binary) expression that has to be evaluated on the eval stack,
// 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:
// by attempting to splitting it up into individual simple steps: // X = <some-expression-not-X> <operator> <not-binary-expression>
// X = <some-expression-not-X> <operator> <not-binary-expression> // or X = <not-binary-expression> <associativeoperator> <some-expression-not-X>
// or X = <not-binary-expression> <associativeoperator> <some-expression-not-X> // split that into X = <some-expression-not-X> ; X = X <operator> <not-binary-expression>
// split that into X = <some-expression-not-X> ; X = X <operator> <not-binary-expression>
// TODO FIX THIS, IT SOMETIMES JUST LOOPS... (for example on plasma.p8) // TODO DOES THIS LOOP AS WELL?
if (expr.operator !in comparisonOperators && !assignment.isAugmentable && isSimpleTarget(assignment.target, program.namespace)) { if (expr.operator !in comparisonOperators && decl.type==VarDeclType.VAR) {
if (expr.right !is BinaryExpression) { if (expr.right !is BinaryExpression) {
println("SPLIT RIGHT BINEXPR $expr") println("SPLIT VARDECL RIGHT BINEXPR $expr") // TODO
val firstAssign = Assignment(assignment.target, expr.left, assignment.position) // val firstAssign = Assignment(assignment.target, expr.left, assignment.position)
val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.right, expr.position) // val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.right, expr.position)
return listOf( // return listOf(
IAstModification.InsertBefore(assignment, firstAssign, parent), // IAstModification.InsertBefore(assignment, firstAssign, parent),
IAstModification.ReplaceNode(assignment.value, augExpr, assignment) // IAstModification.ReplaceNode(assignment.value, augExpr, assignment)
) // )
} else if (expr.left !is BinaryExpression && expr.operator in associativeOperators) { } else if (expr.left !is BinaryExpression && expr.operator in associativeOperators) {
println("SPLIT LEFT BINEXPR $expr") println("SPLIT VARDECL LEFT BINEXPR $expr") // TODO
val firstAssign = Assignment(assignment.target, expr.right, assignment.position) // val firstAssign = Assignment(assignment.target, expr.right, assignment.position)
val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.left, expr.position) // val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.left, expr.position)
return listOf( // return listOf(
IAstModification.InsertBefore(assignment, firstAssign, parent), // IAstModification.InsertBefore(assignment, firstAssign, parent),
IAstModification.ReplaceNode(assignment.value, augExpr, assignment)) // IAstModification.ReplaceNode(assignment.value, augExpr, assignment))
}
} }
} }
} }
@ -48,13 +48,73 @@ class ExpressionSplitter(private val program: Program) : AstWalker() {
return emptyList() return emptyList()
} }
// TODO once this works, integrate it back into expressionsimplifier
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
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
<operator> followed by
/ \ IF 'X' not used X = BinExpr
/ \ IN LEFTEXPR ==> <operator>
/ \ / \
LeftExpr. RightExpr. / \
/ \ / \ X RightExpr.
.. .. .. ..
X = BinExpr X = RightExpr
<operator> followed by
/ \ IF ASSOCIATIVE X = BinExpr
/ \ <operator> ==> <operator>
/ \ / \
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 { private fun isSimpleTarget(target: AssignTarget, namespace: INameScope): Boolean {
return when { return when {
target.identifier!=null -> target.isInRegularRAM(namespace) target.identifier!=null -> target.isInRegularRAM(namespace)
target.memoryAddress!=null -> target.isInRegularRAM(namespace) target.memoryAddress!=null -> target.isInRegularRAM(namespace)
target.arrayindexed!=null -> { target.arrayindexed!=null -> {
val index = target.arrayindexed!!.arrayspec.index val index = target.arrayindexed!!.arrayspec.index
if(index is NumericLiteralValue || index is IdentifierReference) if(index is NumericLiteralValue)
target.isInRegularRAM(namespace) target.isInRegularRAM(namespace)
else else
false false

View File

@ -55,8 +55,8 @@ internal fun Program.simplifyExpressions() : Int {
} }
internal fun Program.splitExpressions() : Int { internal fun Program.splitExpressions() : Int {
val opti = ExpressionSplitter(this) val splitter = ExpressionSplitter(this)
opti.visit(this) splitter.visit(this)
return opti.applyModifications() return splitter.applyModifications()
} }

View File

@ -19,20 +19,20 @@ main {
; uword[] arrays = [names, names3, values] ; uword[] arrays = [names, names3, values]
asmsub testX() { ; asmsub testX() {
%asm {{ ; %asm {{
stx _saveX ; stx _saveX
lda #13 ; lda #13
jsr txt.chrout ; jsr txt.chrout
lda _saveX ; lda _saveX
jsr txt.print_ub ; jsr txt.print_ub
lda #13 ; lda #13
jsr txt.chrout ; jsr txt.chrout
ldx _saveX ; ldx _saveX
rts ; rts
_saveX .byte 0 ;_saveX .byte 0
}} ; }}
} ; }
sub start() { sub start() {
; byte bb = 100 ; byte bb = 100